mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
[codex] Load user instructions through an injected provider (#27101)
## Why We want to remove implicit use of `$CODEX_HOME` from `codex-core` and make embedders responsible for supplying user-level instructions. This also ensures user instructions load when no primary environment is selected. ## What changed Stacked on #27415, which makes `codex exec` surface thread-scoped runtime warnings. - Added `UserInstructionsProvider` to `codex-extension-api`, with absolute source attribution and recoverable loading warnings. - Added `codex-home` with the filesystem-backed provider for `AGENTS.override.md` and `AGENTS.md`, preserving precedence, fallback, trimming, lossy UTF-8 handling, and the existing uncapped global instruction size. - Removed global instruction loading from `Config` and require `ThreadManager` callers to inject a provider. - Load provider instructions once for each fresh root runtime, including runtimes without a primary environment. Running sessions retain their snapshot, while child agents inherit the parent snapshot without invoking the provider. - Keep provider instructions separate while loading project `AGENTS.md`, then assemble the model-visible instructions with the existing ordering, source attribution, warning, and turn-context behavior. - Wired the Codex home provider through the CLI, app server, MCP server, core facade, and thread-manager sample. ## Validation - `just test -p codex-home -p codex-extension-api` - `just test -p codex-core agents_md` - `just test -p codex-core guardian` - `just test -p codex-app-server thread_start_without_selected_environment_includes_only_global_instruction_source` - `just test -p codex-exec warning` - `just bazel-lock-check`
This commit is contained in:
@@ -20,6 +20,7 @@ codex-config = { workspace = true }
|
||||
codex-core = { workspace = true }
|
||||
codex-extension-api = { workspace = true }
|
||||
codex-exec-server = { workspace = true }
|
||||
codex-home = { workspace = true }
|
||||
codex-features = { workspace = true }
|
||||
codex-hooks = { workspace = true }
|
||||
codex-login = { workspace = true }
|
||||
|
||||
@@ -6,6 +6,7 @@ use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::AtomicU64;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -24,7 +25,10 @@ use codex_exec_server::CreateDirectoryOptions;
|
||||
use codex_exec_server::ExecutorFileSystem;
|
||||
use codex_exec_server::RemoveOptions;
|
||||
use codex_extension_api::ExtensionRegistry;
|
||||
use codex_extension_api::LoadUserInstructionsFuture;
|
||||
use codex_extension_api::UserInstructionsProvider;
|
||||
use codex_extension_api::empty_extension_registry;
|
||||
use codex_home::CodexHomeUserInstructionsProvider;
|
||||
use codex_login::CodexAuth;
|
||||
use codex_model_provider_info::ModelProviderInfo;
|
||||
use codex_model_provider_info::built_in_model_providers;
|
||||
@@ -72,6 +76,31 @@ const REMOTE_EXEC_SERVER_URL_ENV_VAR: &str = "CODEX_TEST_REMOTE_EXEC_SERVER_URL"
|
||||
static REMOTE_TEST_INSTANCE_COUNTER: AtomicU64 = AtomicU64::new(0);
|
||||
const SUBMIT_TURN_COMPLETE_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
|
||||
pub struct RecordingUserInstructionsProvider {
|
||||
inner: Arc<dyn UserInstructionsProvider>,
|
||||
load_count: AtomicUsize,
|
||||
}
|
||||
|
||||
impl RecordingUserInstructionsProvider {
|
||||
pub fn new(inner: Arc<dyn UserInstructionsProvider>) -> Self {
|
||||
Self {
|
||||
inner,
|
||||
load_count: AtomicUsize::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_count(&self) -> usize {
|
||||
self.load_count.load(Ordering::SeqCst)
|
||||
}
|
||||
}
|
||||
|
||||
impl UserInstructionsProvider for RecordingUserInstructionsProvider {
|
||||
fn load_user_instructions(&self) -> LoadUserInstructionsFuture<'_> {
|
||||
self.load_count.fetch_add(1, Ordering::SeqCst);
|
||||
self.inner.load_user_instructions()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn local(cwd: AbsolutePathBuf) -> TurnEnvironmentSelection {
|
||||
TurnEnvironmentSelection {
|
||||
environment_id: codex_exec_server::LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
@@ -233,6 +262,7 @@ pub struct TestCodexBuilder {
|
||||
user_shell_override: Option<Shell>,
|
||||
exec_server_url: Option<String>,
|
||||
extensions: Arc<ExtensionRegistry<Config>>,
|
||||
user_instructions_provider: Option<Arc<dyn UserInstructionsProvider>>,
|
||||
}
|
||||
|
||||
impl TestCodexBuilder {
|
||||
@@ -322,6 +352,14 @@ impl TestCodexBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_user_instructions_provider(
|
||||
mut self,
|
||||
provider: Arc<dyn UserInstructionsProvider>,
|
||||
) -> Self {
|
||||
self.user_instructions_provider = Some(provider);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_windows_cmd_shell(self) -> Self {
|
||||
if cfg!(windows) {
|
||||
self.with_user_shell(get_shell_by_model_provided_path(&PathBuf::from("cmd.exe")))
|
||||
@@ -510,12 +548,19 @@ impl TestCodexBuilder {
|
||||
let state_db = codex_core::init_state_db(&config).await;
|
||||
let thread_store = thread_store_from_config(&config, state_db.clone());
|
||||
let installation_id = resolve_installation_id(&config.codex_home).await?;
|
||||
let user_instructions_provider =
|
||||
self.user_instructions_provider.clone().unwrap_or_else(|| {
|
||||
Arc::new(CodexHomeUserInstructionsProvider::new(
|
||||
config.codex_home.clone(),
|
||||
))
|
||||
});
|
||||
let thread_manager = ThreadManager::new(
|
||||
&config,
|
||||
codex_core::test_support::auth_manager_from_auth(auth.clone()),
|
||||
SessionSource::Exec,
|
||||
Arc::clone(&environment_manager),
|
||||
Arc::clone(&self.extensions),
|
||||
user_instructions_provider,
|
||||
/*analytics_events_client*/ None,
|
||||
thread_store,
|
||||
state_db.clone(),
|
||||
@@ -1103,6 +1148,7 @@ pub fn test_codex() -> TestCodexBuilder {
|
||||
user_shell_override: None,
|
||||
exec_server_url: None,
|
||||
extensions: empty_extension_registry(),
|
||||
user_instructions_provider: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
use anyhow::Result;
|
||||
use anyhow::anyhow;
|
||||
use codex_core::ForkSnapshot;
|
||||
use codex_core::StartThreadOptions;
|
||||
use codex_exec_server::CreateDirectoryOptions;
|
||||
use codex_features::Feature;
|
||||
use codex_home::CodexHomeUserInstructionsProvider;
|
||||
use codex_protocol::protocol::EventMsg;
|
||||
use codex_protocol::protocol::InitialHistory;
|
||||
use codex_protocol::protocol::Op;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
@@ -18,6 +21,7 @@ use core_test_support::responses::mount_sse_once;
|
||||
use core_test_support::responses::sse;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::RecordingUserInstructionsProvider;
|
||||
use core_test_support::test_codex::TestCodexBuilder;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::wait_for_event;
|
||||
@@ -364,6 +368,89 @@ async fn selected_environment_sources_match_model_visible_instructions() -> Resu
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn loads_user_instructions_without_a_primary_environment() -> Result<()> {
|
||||
let server = start_mock_server().await;
|
||||
let response_mock = mount_sse_once(
|
||||
&server,
|
||||
sse(vec![
|
||||
ev_response_created("no-primary-environment-response"),
|
||||
ev_completed("no-primary-environment-response"),
|
||||
]),
|
||||
)
|
||||
.await;
|
||||
let home = Arc::new(TempDir::new()?);
|
||||
let global_source =
|
||||
write_global_file(home.as_ref(), GLOBAL_AGENTS_FILENAME, GLOBAL_INSTRUCTIONS)?;
|
||||
let provider = Arc::new(RecordingUserInstructionsProvider::new(Arc::new(
|
||||
CodexHomeUserInstructionsProvider::new(AbsolutePathBuf::try_from(
|
||||
home.path().to_path_buf(),
|
||||
)?),
|
||||
)));
|
||||
|
||||
let mut builder = test_codex()
|
||||
.with_home(Arc::clone(&home))
|
||||
.with_user_instructions_provider(provider.clone())
|
||||
.with_workspace_setup(|cwd, fs| async move {
|
||||
let project_agents_uri = PathUri::from_path(cwd.join(GLOBAL_AGENTS_FILENAME))?;
|
||||
fs.write_file(
|
||||
&project_agents_uri,
|
||||
PROJECT_INSTRUCTIONS.as_bytes().to_vec(),
|
||||
/*sandbox*/ None,
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
});
|
||||
let test = builder.build_with_remote_env(&server).await?;
|
||||
assert_eq!(provider.load_count(), 1);
|
||||
|
||||
let no_environment_thread = test
|
||||
.thread_manager
|
||||
.start_thread_with_options(StartThreadOptions {
|
||||
config: test.config.clone(),
|
||||
initial_history: InitialHistory::New,
|
||||
session_source: None,
|
||||
thread_source: None,
|
||||
dynamic_tools: Vec::new(),
|
||||
metrics_service_name: None,
|
||||
parent_trace: None,
|
||||
environments: Vec::new(),
|
||||
thread_extension_init: Default::default(),
|
||||
})
|
||||
.await?;
|
||||
assert_eq!(provider.load_count(), 2);
|
||||
assert_eq!(
|
||||
no_environment_thread.thread.instruction_sources().await,
|
||||
vec![global_source]
|
||||
);
|
||||
|
||||
no_environment_thread
|
||||
.thread
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "inspect global instructions without an environment".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: Default::default(),
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&no_environment_thread.thread, |event| {
|
||||
matches!(event, EventMsg::TurnComplete(_))
|
||||
})
|
||||
.await;
|
||||
|
||||
let instruction_fragments = instruction_fragments(&response_mock.single_request());
|
||||
assert_eq!(instruction_fragments.len(), 1);
|
||||
assert!(instruction_fragments[0].contains(GLOBAL_INSTRUCTIONS));
|
||||
assert!(!instruction_fragments[0].contains(PROJECT_INSTRUCTIONS));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn fresh_thread_composes_global_before_project_and_reports_sources() -> Result<()> {
|
||||
// Set up one global source, one project source, and two ordinary model turns.
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use codex_config::ConfigLayerStack;
|
||||
use codex_config::types::AuthCredentialsStoreMode;
|
||||
use codex_core::LoadedAgentsMd;
|
||||
use codex_core::ModelClient;
|
||||
use codex_core::NewThread;
|
||||
use codex_core::Prompt;
|
||||
@@ -365,9 +364,8 @@ async fn resume_includes_initial_messages_and_sends_prior_items() {
|
||||
let codex_home = Arc::new(TempDir::new().unwrap());
|
||||
let mut builder = test_codex()
|
||||
.with_home(codex_home.clone())
|
||||
.with_config(|config| {
|
||||
// Ensure user instructions are NOT delivered on resume.
|
||||
config.user_instructions = Some(LoadedAgentsMd::from_text_for_testing("be nice"));
|
||||
.with_pre_build_hook(|home| {
|
||||
std::fs::write(home.join("AGENTS.md"), "be nice").expect("write global instructions");
|
||||
});
|
||||
let test = builder
|
||||
.resume(&server, codex_home, session_path.clone())
|
||||
@@ -1137,6 +1135,7 @@ async fn prefers_apikey_when_config_prefers_apikey_even_with_chatgpt_tokens() {
|
||||
SessionSource::Exec,
|
||||
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
empty_extension_registry(),
|
||||
Arc::new(codex_core::test_support::EmptyUserInstructionsProvider),
|
||||
/*analytics_events_client*/ None,
|
||||
thread_store_from_config(&config, /*state_db*/ None),
|
||||
/*state_db*/ None,
|
||||
@@ -1178,8 +1177,8 @@ async fn includes_user_instructions_message_in_request() {
|
||||
|
||||
let mut builder = test_codex()
|
||||
.with_auth(CodexAuth::from_api_key("Test API Key"))
|
||||
.with_config(|config| {
|
||||
config.user_instructions = Some(LoadedAgentsMd::from_text_for_testing("be nice"));
|
||||
.with_pre_build_hook(|home| {
|
||||
std::fs::write(home.join("AGENTS.md"), "be nice").expect("write global instructions");
|
||||
});
|
||||
let codex = builder
|
||||
.build(&server)
|
||||
@@ -2246,8 +2245,10 @@ async fn includes_developer_instructions_message_in_request() {
|
||||
.await;
|
||||
let mut builder = test_codex()
|
||||
.with_auth(CodexAuth::from_api_key("Test API Key"))
|
||||
.with_pre_build_hook(|home| {
|
||||
std::fs::write(home.join("AGENTS.md"), "be nice").expect("write global instructions");
|
||||
})
|
||||
.with_config(|config| {
|
||||
config.user_instructions = Some(LoadedAgentsMd::from_text_for_testing("be nice"));
|
||||
config.developer_instructions = Some("be useful".to_string());
|
||||
});
|
||||
let codex = builder
|
||||
|
||||
@@ -5,7 +5,6 @@ use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Result;
|
||||
use codex_core::LoadedAgentsMd;
|
||||
use codex_features::Feature;
|
||||
use codex_login::CodexAuth;
|
||||
use codex_protocol::config_types::ServiceTier;
|
||||
@@ -29,6 +28,7 @@ const FIXED_CWD: &str = "/tmp/codex_remote_compaction_parity_workspace";
|
||||
const IMAGE_URL: &str = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+/p9sAAAAASUVORK5CYII=";
|
||||
const SUMMARY: &str = "REMOTE_COMPACTION_PARITY_ENCRYPTED_SUMMARY";
|
||||
const DUMMY_FUNCTION_NAME: &str = "test_tool";
|
||||
const USER_INSTRUCTIONS: &str = "PARITY_USER_INSTRUCTIONS";
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
enum Mode {
|
||||
@@ -509,7 +509,12 @@ async fn build_harness_inner(
|
||||
auto_compact_limit: Option<i64>,
|
||||
) -> Result<TestCodexHarness> {
|
||||
fs::create_dir_all(FIXED_CWD)?;
|
||||
let mut builder = test_codex().with_auth(settings.auth.build());
|
||||
let mut builder = test_codex()
|
||||
.with_auth(settings.auth.build())
|
||||
.with_pre_build_hook(|home| {
|
||||
fs::write(home.join("AGENTS.md"), USER_INSTRUCTIONS)
|
||||
.expect("write global instructions");
|
||||
});
|
||||
if hooks {
|
||||
builder = builder.with_pre_build_hook(write_manual_compact_hooks);
|
||||
}
|
||||
@@ -518,9 +523,6 @@ async fn build_harness_inner(
|
||||
FIXED_CWD,
|
||||
))
|
||||
.expect("fixed cwd should be absolute");
|
||||
config.user_instructions = Some(LoadedAgentsMd::from_text_for_testing(
|
||||
"PARITY_USER_INSTRUCTIONS",
|
||||
));
|
||||
config.developer_instructions = Some("PARITY_DEVELOPER_INSTRUCTIONS".to_string());
|
||||
if settings.service_tier_fast {
|
||||
config.service_tier = Some(ServiceTier::Fast.request_value().to_string());
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use codex_core::LoadedAgentsMd;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
use codex_core::shell::default_user_shell;
|
||||
use codex_features::Feature;
|
||||
use codex_prompts::APPLY_PATCH_TOOL_INSTRUCTIONS;
|
||||
@@ -32,6 +34,11 @@ use core_test_support::wait_for_event;
|
||||
use pretty_assertions::assert_eq;
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn write_global_instructions(home: &Path) {
|
||||
fs::write(home.join("AGENTS.md"), "be consistent and helpful")
|
||||
.unwrap_or_else(|err| panic!("write global instructions: {err}"));
|
||||
}
|
||||
|
||||
fn text_user_input(text: String) -> serde_json::Value {
|
||||
text_user_input_parts(vec![text])
|
||||
}
|
||||
@@ -123,10 +130,8 @@ async fn prompt_tools_are_consistent_across_requests() -> anyhow::Result<()> {
|
||||
thread_manager,
|
||||
..
|
||||
} = test_codex()
|
||||
.with_pre_build_hook(write_global_instructions)
|
||||
.with_config(|config| {
|
||||
config.user_instructions = Some(LoadedAgentsMd::from_text_for_testing(
|
||||
"be consistent and helpful",
|
||||
));
|
||||
config.model = Some("gpt-5.2".to_string());
|
||||
// Keep tool expectations stable when the default web_search mode changes.
|
||||
config
|
||||
@@ -235,10 +240,8 @@ async fn gpt_5_tools_without_apply_patch_append_apply_patch_instructions() -> an
|
||||
.await;
|
||||
|
||||
let TestCodex { codex, .. } = test_codex()
|
||||
.with_pre_build_hook(write_global_instructions)
|
||||
.with_config(|config| {
|
||||
config.user_instructions = Some(LoadedAgentsMd::from_text_for_testing(
|
||||
"be consistent and helpful",
|
||||
));
|
||||
config
|
||||
.features
|
||||
.enable(Feature::CollaborationModes)
|
||||
@@ -317,10 +320,8 @@ async fn prefixes_context_and_instructions_once_and_consistently_across_requests
|
||||
.await;
|
||||
|
||||
let TestCodex { codex, config, .. } = test_codex()
|
||||
.with_pre_build_hook(write_global_instructions)
|
||||
.with_config(|config| {
|
||||
config.user_instructions = Some(LoadedAgentsMd::from_text_for_testing(
|
||||
"be consistent and helpful",
|
||||
));
|
||||
config
|
||||
.features
|
||||
.enable(Feature::CollaborationModes)
|
||||
@@ -415,10 +416,8 @@ async fn overrides_turn_context_but_keeps_cached_prefix_and_key_constant() -> an
|
||||
.await;
|
||||
|
||||
let TestCodex { codex, config, .. } = test_codex()
|
||||
.with_pre_build_hook(write_global_instructions)
|
||||
.with_config(|config| {
|
||||
config.user_instructions = Some(LoadedAgentsMd::from_text_for_testing(
|
||||
"be consistent and helpful",
|
||||
));
|
||||
config
|
||||
.features
|
||||
.enable(Feature::CollaborationModes)
|
||||
@@ -706,10 +705,8 @@ async fn per_turn_overrides_keep_cached_prefix_and_key_constant() -> anyhow::Res
|
||||
.await;
|
||||
|
||||
let TestCodex { codex, .. } = test_codex()
|
||||
.with_pre_build_hook(write_global_instructions)
|
||||
.with_config(|config| {
|
||||
config.user_instructions = Some(LoadedAgentsMd::from_text_for_testing(
|
||||
"be consistent and helpful",
|
||||
));
|
||||
config
|
||||
.features
|
||||
.enable(Feature::CollaborationModes)
|
||||
@@ -841,10 +838,8 @@ async fn send_user_turn_with_no_changes_does_not_send_environment_context() -> a
|
||||
session_configured,
|
||||
..
|
||||
} = test_codex()
|
||||
.with_pre_build_hook(write_global_instructions)
|
||||
.with_config(|config| {
|
||||
config.user_instructions = Some(LoadedAgentsMd::from_text_for_testing(
|
||||
"be consistent and helpful",
|
||||
));
|
||||
config
|
||||
.features
|
||||
.enable(Feature::CollaborationModes)
|
||||
@@ -982,10 +977,8 @@ async fn send_user_turn_with_changes_sends_environment_context() -> anyhow::Resu
|
||||
session_configured,
|
||||
..
|
||||
} = test_codex()
|
||||
.with_pre_build_hook(write_global_instructions)
|
||||
.with_config(|config| {
|
||||
config.user_instructions = Some(LoadedAgentsMd::from_text_for_testing(
|
||||
"be consistent and helpful",
|
||||
));
|
||||
config
|
||||
.features
|
||||
.enable(Feature::CollaborationModes)
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::Result;
|
||||
use codex_core::LoadedAgentsMd;
|
||||
use codex_core::build_prompt_input;
|
||||
use codex_core::config::ConfigBuilder;
|
||||
use codex_core::config::ConfigOverrides;
|
||||
use codex_home::CodexHomeUserInstructionsProvider;
|
||||
use codex_protocol::models::ContentItem;
|
||||
use codex_protocol::models::ResponseItem;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use pretty_assertions::assert_eq;
|
||||
use tempfile::TempDir;
|
||||
|
||||
const TEST_INSTRUCTIONS: &str = "Global test instructions";
|
||||
|
||||
#[tokio::test]
|
||||
async fn build_prompt_input_includes_context_and_user_message() -> Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
let cwd = TempDir::new()?;
|
||||
let mut config = ConfigBuilder::default()
|
||||
std::fs::write(codex_home.path().join("AGENTS.md"), TEST_INSTRUCTIONS)?;
|
||||
let config = ConfigBuilder::default()
|
||||
.codex_home(codex_home.path().to_path_buf())
|
||||
.harness_overrides(ConfigOverrides {
|
||||
cwd: Some(cwd.path().to_path_buf()),
|
||||
@@ -22,8 +27,8 @@ async fn build_prompt_input_includes_context_and_user_message() -> Result<()> {
|
||||
})
|
||||
.build()
|
||||
.await?;
|
||||
config.user_instructions = Some(LoadedAgentsMd::from_text_for_testing(
|
||||
"Project-specific test instructions",
|
||||
let user_instructions_provider = Arc::new(CodexHomeUserInstructionsProvider::new(
|
||||
config.codex_home.clone(),
|
||||
));
|
||||
|
||||
let input = build_prompt_input(
|
||||
@@ -33,6 +38,7 @@ async fn build_prompt_input_includes_context_and_user_message() -> Result<()> {
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
/*state_db*/ None,
|
||||
user_instructions_provider,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -55,7 +61,7 @@ async fn build_prompt_input_includes_context_and_user_message() -> Result<()> {
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
text.contains("Project-specific test instructions")
|
||||
text.contains(TEST_INSTRUCTIONS)
|
||||
})
|
||||
}));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user