mirror of
https://github.com/openai/codex.git
synced 2026-05-23 20:44:50 +00:00
[codex] Make contextual user fragments dyn-renderable (#23397)
## Why `ContextualUserFragment` needs to be usable behind `dyn` for render-only paths, but associated constants made the trait non-object-safe. ## What changed - Replaced associated constants with trait methods so `dyn ContextualUserFragment` can render fragments. - Preserved the existing typed `T::matches_text(text)` registration pattern via `type_markers()`. - Kept default `render()` on the main trait so implementations only provide role, markers, and body. - Added unit coverage for rendering a `Box<dyn ContextualUserFragment>`. ## Verification - `cargo test -p codex-core contextual_user_fragment_is_dyn_compatible` - `just fix -p codex-core`
This commit is contained in:
@@ -14,9 +14,17 @@ impl ApprovedCommandPrefixSaved {
|
||||
}
|
||||
|
||||
impl ContextualUserFragment for ApprovedCommandPrefixSaved {
|
||||
const ROLE: &'static str = "developer";
|
||||
const START_MARKER: &'static str = "";
|
||||
const END_MARKER: &'static str = "";
|
||||
fn role() -> &'static str {
|
||||
"developer"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
("", "")
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
format!("Approved command prefix saved:\n{}", self.prefixes)
|
||||
|
||||
@@ -18,9 +18,17 @@ impl AppsInstructions {
|
||||
}
|
||||
|
||||
impl ContextualUserFragment for AppsInstructions {
|
||||
const ROLE: &'static str = "developer";
|
||||
const START_MARKER: &'static str = APPS_INSTRUCTIONS_OPEN_TAG;
|
||||
const END_MARKER: &'static str = APPS_INSTRUCTIONS_CLOSE_TAG;
|
||||
fn role() -> &'static str {
|
||||
"developer"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
(APPS_INSTRUCTIONS_OPEN_TAG, APPS_INSTRUCTIONS_CLOSE_TAG)
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
format!(
|
||||
|
||||
@@ -22,9 +22,20 @@ impl AvailablePluginsInstructions {
|
||||
}
|
||||
|
||||
impl ContextualUserFragment for AvailablePluginsInstructions {
|
||||
const ROLE: &'static str = "developer";
|
||||
const START_MARKER: &'static str = PLUGINS_INSTRUCTIONS_OPEN_TAG;
|
||||
const END_MARKER: &'static str = PLUGINS_INSTRUCTIONS_CLOSE_TAG;
|
||||
fn role() -> &'static str {
|
||||
"developer"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
(
|
||||
PLUGINS_INSTRUCTIONS_OPEN_TAG,
|
||||
PLUGINS_INSTRUCTIONS_CLOSE_TAG,
|
||||
)
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
let mut lines = vec![
|
||||
|
||||
@@ -21,9 +21,17 @@ impl From<AvailableSkills> for AvailableSkillsInstructions {
|
||||
}
|
||||
|
||||
impl ContextualUserFragment for AvailableSkillsInstructions {
|
||||
const ROLE: &'static str = "developer";
|
||||
const START_MARKER: &'static str = SKILLS_INSTRUCTIONS_OPEN_TAG;
|
||||
const END_MARKER: &'static str = SKILLS_INSTRUCTIONS_CLOSE_TAG;
|
||||
fn role() -> &'static str {
|
||||
"developer"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
(SKILLS_INSTRUCTIONS_OPEN_TAG, SKILLS_INSTRUCTIONS_CLOSE_TAG)
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
render_available_skills_body(&self.skill_root_lines, &self.skill_lines)
|
||||
|
||||
@@ -22,9 +22,17 @@ impl CollaborationModeInstructions {
|
||||
}
|
||||
|
||||
impl ContextualUserFragment for CollaborationModeInstructions {
|
||||
const ROLE: &'static str = "developer";
|
||||
const START_MARKER: &'static str = COLLABORATION_MODE_OPEN_TAG;
|
||||
const END_MARKER: &'static str = COLLABORATION_MODE_CLOSE_TAG;
|
||||
fn role() -> &'static str {
|
||||
"developer"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
(COLLABORATION_MODE_OPEN_TAG, COLLABORATION_MODE_CLOSE_TAG)
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
self.instructions.clone()
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
use super::*;
|
||||
use crate::context::ContextualUserFragment;
|
||||
use crate::context::GoalContext;
|
||||
use crate::context::SubagentNotification;
|
||||
use codex_protocol::items::HookPromptFragment;
|
||||
use codex_protocol::items::build_hook_prompt_message;
|
||||
use codex_protocol::models::ResponseItem;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn detects_environment_context_fragment() {
|
||||
@@ -38,6 +41,18 @@ fn detects_goal_context_fragment() {
|
||||
}));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn contextual_user_fragment_is_dyn_compatible() {
|
||||
let fragment: Box<dyn ContextualUserFragment> = Box::new(GoalContext {
|
||||
prompt: "Continue working toward the active thread goal.".to_string(),
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
fragment.render(),
|
||||
"<goal_context>\nContinue working toward the active thread goal.\n</goal_context>"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ignores_regular_user_text() {
|
||||
assert!(!is_contextual_user_fragment(&ContentItem::InputText {
|
||||
|
||||
@@ -269,9 +269,20 @@ impl EnvironmentContext {
|
||||
}
|
||||
|
||||
impl ContextualUserFragment for EnvironmentContext {
|
||||
const ROLE: &'static str = "user";
|
||||
const START_MARKER: &'static str = codex_protocol::protocol::ENVIRONMENT_CONTEXT_OPEN_TAG;
|
||||
const END_MARKER: &'static str = codex_protocol::protocol::ENVIRONMENT_CONTEXT_CLOSE_TAG;
|
||||
fn role() -> &'static str {
|
||||
"user"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
(
|
||||
codex_protocol::protocol::ENVIRONMENT_CONTEXT_OPEN_TAG,
|
||||
codex_protocol::protocol::ENVIRONMENT_CONTEXT_CLOSE_TAG,
|
||||
)
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
let mut lines = Vec::new();
|
||||
|
||||
@@ -38,37 +38,34 @@ impl<T: ContextualUserFragment> FragmentRegistration for FragmentRegistrationPro
|
||||
/// in which case the default helpers render only the body and never match
|
||||
/// arbitrary text.
|
||||
pub trait ContextualUserFragment {
|
||||
const ROLE: &'static str;
|
||||
const START_MARKER: &'static str;
|
||||
const END_MARKER: &'static str;
|
||||
fn role() -> &'static str
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str);
|
||||
|
||||
fn body(&self) -> String;
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str)
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
fn matches_text(text: &str) -> bool
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
if Self::START_MARKER.is_empty() || Self::END_MARKER.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let trimmed = text.trim_start();
|
||||
let starts_with_marker = trimmed
|
||||
.get(..Self::START_MARKER.len())
|
||||
.is_some_and(|candidate| candidate.eq_ignore_ascii_case(Self::START_MARKER));
|
||||
let trimmed = trimmed.trim_end();
|
||||
let ends_with_marker = trimmed
|
||||
.get(trimmed.len().saturating_sub(Self::END_MARKER.len())..)
|
||||
.is_some_and(|candidate| candidate.eq_ignore_ascii_case(Self::END_MARKER));
|
||||
starts_with_marker && ends_with_marker
|
||||
let (start_marker, end_marker) = Self::type_markers();
|
||||
matches_marked_text(start_marker, end_marker, text)
|
||||
}
|
||||
|
||||
fn render(&self) -> String {
|
||||
if Self::START_MARKER.is_empty() && Self::END_MARKER.is_empty() {
|
||||
return self.body();
|
||||
let (start_marker, end_marker) = self.markers();
|
||||
let body = self.body();
|
||||
if start_marker.is_empty() && end_marker.is_empty() {
|
||||
return body;
|
||||
}
|
||||
|
||||
format!("{}{}{}", Self::START_MARKER, self.body(), Self::END_MARKER)
|
||||
format!("{start_marker}{body}{end_marker}")
|
||||
}
|
||||
|
||||
fn into(self) -> ResponseItem
|
||||
@@ -77,7 +74,7 @@ pub trait ContextualUserFragment {
|
||||
{
|
||||
ResponseItem::Message {
|
||||
id: None,
|
||||
role: Self::ROLE.to_string(),
|
||||
role: Self::role().to_string(),
|
||||
content: vec![ContentItem::InputText {
|
||||
text: self.render(),
|
||||
}],
|
||||
@@ -85,3 +82,19 @@ pub trait ContextualUserFragment {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn matches_marked_text(start_marker: &str, end_marker: &str, text: &str) -> bool {
|
||||
if start_marker.is_empty() || end_marker.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let trimmed = text.trim_start();
|
||||
let starts_with_marker = trimmed
|
||||
.get(..start_marker.len())
|
||||
.is_some_and(|candidate| candidate.eq_ignore_ascii_case(start_marker));
|
||||
let trimmed = trimmed.trim_end();
|
||||
let ends_with_marker = trimmed
|
||||
.get(trimmed.len().saturating_sub(end_marker.len())..)
|
||||
.is_some_and(|candidate| candidate.eq_ignore_ascii_case(end_marker));
|
||||
starts_with_marker && ends_with_marker
|
||||
}
|
||||
|
||||
@@ -8,9 +8,17 @@ pub(crate) struct GoalContext {
|
||||
}
|
||||
|
||||
impl ContextualUserFragment for GoalContext {
|
||||
const ROLE: &'static str = "user";
|
||||
const START_MARKER: &'static str = "<goal_context>";
|
||||
const END_MARKER: &'static str = "</goal_context>";
|
||||
fn role() -> &'static str {
|
||||
"user"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
("<goal_context>", "</goal_context>")
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
format!("\n{}\n", self.prompt)
|
||||
|
||||
@@ -4,9 +4,17 @@ use super::ContextualUserFragment;
|
||||
pub(crate) struct GuardianFollowupReviewReminder;
|
||||
|
||||
impl ContextualUserFragment for GuardianFollowupReviewReminder {
|
||||
const ROLE: &'static str = "developer";
|
||||
const START_MARKER: &'static str = "";
|
||||
const END_MARKER: &'static str = "";
|
||||
fn role() -> &'static str {
|
||||
"developer"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
("", "")
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
concat!(
|
||||
|
||||
@@ -12,9 +12,17 @@ impl HookAdditionalContext {
|
||||
}
|
||||
|
||||
impl ContextualUserFragment for HookAdditionalContext {
|
||||
const ROLE: &'static str = "developer";
|
||||
const START_MARKER: &'static str = "";
|
||||
const END_MARKER: &'static str = "";
|
||||
fn role() -> &'static str {
|
||||
"developer"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
("", "")
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
self.text.clone()
|
||||
|
||||
@@ -17,9 +17,17 @@ impl ImageGenerationInstructions {
|
||||
}
|
||||
|
||||
impl ContextualUserFragment for ImageGenerationInstructions {
|
||||
const ROLE: &'static str = "developer";
|
||||
const START_MARKER: &'static str = "";
|
||||
const END_MARKER: &'static str = "";
|
||||
fn role() -> &'static str {
|
||||
"developer"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
("", "")
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
format!(
|
||||
|
||||
@@ -5,9 +5,17 @@ use super::ContextualUserFragment;
|
||||
pub(crate) struct LegacyApplyPatchExecCommandWarning;
|
||||
|
||||
impl ContextualUserFragment for LegacyApplyPatchExecCommandWarning {
|
||||
const ROLE: &'static str = "user";
|
||||
const START_MARKER: &'static str = "";
|
||||
const END_MARKER: &'static str = "";
|
||||
fn role() -> &'static str {
|
||||
"user"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
("", "")
|
||||
}
|
||||
|
||||
fn matches_text(text: &str) -> bool {
|
||||
let trimmed = text.trim();
|
||||
|
||||
@@ -5,9 +5,17 @@ use super::ContextualUserFragment;
|
||||
pub(crate) struct LegacyModelMismatchWarning;
|
||||
|
||||
impl ContextualUserFragment for LegacyModelMismatchWarning {
|
||||
const ROLE: &'static str = "user";
|
||||
const START_MARKER: &'static str = "";
|
||||
const END_MARKER: &'static str = "";
|
||||
fn role() -> &'static str {
|
||||
"user"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
("", "")
|
||||
}
|
||||
|
||||
fn matches_text(text: &str) -> bool {
|
||||
text.trim().starts_with(
|
||||
|
||||
@@ -5,9 +5,17 @@ use super::ContextualUserFragment;
|
||||
pub(crate) struct LegacyUnifiedExecProcessLimitWarning;
|
||||
|
||||
impl ContextualUserFragment for LegacyUnifiedExecProcessLimitWarning {
|
||||
const ROLE: &'static str = "user";
|
||||
const START_MARKER: &'static str = "";
|
||||
const END_MARKER: &'static str = "";
|
||||
fn role() -> &'static str {
|
||||
"user"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
("", "")
|
||||
}
|
||||
|
||||
fn matches_text(text: &str) -> bool {
|
||||
text.trim().starts_with(
|
||||
|
||||
@@ -14,9 +14,17 @@ impl ModelSwitchInstructions {
|
||||
}
|
||||
|
||||
impl ContextualUserFragment for ModelSwitchInstructions {
|
||||
const ROLE: &'static str = "developer";
|
||||
const START_MARKER: &'static str = "<model_switch>";
|
||||
const END_MARKER: &'static str = "</model_switch>";
|
||||
fn role() -> &'static str {
|
||||
"developer"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
("<model_switch>", "</model_switch>")
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
format!(
|
||||
|
||||
@@ -18,9 +18,17 @@ impl NetworkRuleSaved {
|
||||
}
|
||||
|
||||
impl ContextualUserFragment for NetworkRuleSaved {
|
||||
const ROLE: &'static str = "developer";
|
||||
const START_MARKER: &'static str = "";
|
||||
const END_MARKER: &'static str = "";
|
||||
fn role() -> &'static str {
|
||||
"developer"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
("", "")
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
let (action, list_name) = match self.action {
|
||||
|
||||
@@ -145,9 +145,17 @@ fn network_access_from_policy(network_policy: NetworkSandboxPolicy) -> NetworkAc
|
||||
}
|
||||
|
||||
impl ContextualUserFragment for PermissionsInstructions {
|
||||
const ROLE: &'static str = "developer";
|
||||
const START_MARKER: &'static str = "<permissions instructions>";
|
||||
const END_MARKER: &'static str = "</permissions instructions>";
|
||||
fn role() -> &'static str {
|
||||
"developer"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
("<permissions instructions>", "</permissions instructions>")
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
self.text.clone()
|
||||
|
||||
@@ -12,9 +12,17 @@ impl PersonalitySpecInstructions {
|
||||
}
|
||||
|
||||
impl ContextualUserFragment for PersonalitySpecInstructions {
|
||||
const ROLE: &'static str = "developer";
|
||||
const START_MARKER: &'static str = "<personality_spec>";
|
||||
const END_MARKER: &'static str = "</personality_spec>";
|
||||
fn role() -> &'static str {
|
||||
"developer"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
("<personality_spec>", "</personality_spec>")
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
format!(
|
||||
|
||||
@@ -12,9 +12,17 @@ impl PluginInstructions {
|
||||
}
|
||||
|
||||
impl ContextualUserFragment for PluginInstructions {
|
||||
const ROLE: &'static str = "developer";
|
||||
const START_MARKER: &'static str = "";
|
||||
const END_MARKER: &'static str = "";
|
||||
fn role() -> &'static str {
|
||||
"developer"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
("", "")
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
self.text.clone()
|
||||
|
||||
@@ -18,9 +18,20 @@ impl RealtimeEndInstructions {
|
||||
}
|
||||
|
||||
impl ContextualUserFragment for RealtimeEndInstructions {
|
||||
const ROLE: &'static str = "developer";
|
||||
const START_MARKER: &'static str = REALTIME_CONVERSATION_OPEN_TAG;
|
||||
const END_MARKER: &'static str = REALTIME_CONVERSATION_CLOSE_TAG;
|
||||
fn role() -> &'static str {
|
||||
"developer"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
(
|
||||
REALTIME_CONVERSATION_OPEN_TAG,
|
||||
REALTIME_CONVERSATION_CLOSE_TAG,
|
||||
)
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
format!(
|
||||
|
||||
@@ -8,9 +8,20 @@ const REALTIME_START_INSTRUCTIONS: &str = include_str!("prompts/realtime/realtim
|
||||
pub(crate) struct RealtimeStartInstructions;
|
||||
|
||||
impl ContextualUserFragment for RealtimeStartInstructions {
|
||||
const ROLE: &'static str = "developer";
|
||||
const START_MARKER: &'static str = REALTIME_CONVERSATION_OPEN_TAG;
|
||||
const END_MARKER: &'static str = REALTIME_CONVERSATION_CLOSE_TAG;
|
||||
fn role() -> &'static str {
|
||||
"developer"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
(
|
||||
REALTIME_CONVERSATION_OPEN_TAG,
|
||||
REALTIME_CONVERSATION_CLOSE_TAG,
|
||||
)
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
format!("\n{}\n", REALTIME_START_INSTRUCTIONS.trim())
|
||||
|
||||
@@ -16,9 +16,20 @@ impl RealtimeStartWithInstructions {
|
||||
}
|
||||
|
||||
impl ContextualUserFragment for RealtimeStartWithInstructions {
|
||||
const ROLE: &'static str = "developer";
|
||||
const START_MARKER: &'static str = REALTIME_CONVERSATION_OPEN_TAG;
|
||||
const END_MARKER: &'static str = REALTIME_CONVERSATION_CLOSE_TAG;
|
||||
fn role() -> &'static str {
|
||||
"developer"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
(
|
||||
REALTIME_CONVERSATION_OPEN_TAG,
|
||||
REALTIME_CONVERSATION_CLOSE_TAG,
|
||||
)
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
format!("\n{}\n", self.instructions)
|
||||
|
||||
@@ -20,9 +20,17 @@ impl From<&SkillInjection> for SkillInstructions {
|
||||
}
|
||||
|
||||
impl ContextualUserFragment for SkillInstructions {
|
||||
const ROLE: &'static str = "user";
|
||||
const START_MARKER: &'static str = "<skill>";
|
||||
const END_MARKER: &'static str = "</skill>";
|
||||
fn role() -> &'static str {
|
||||
"user"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
("<skill>", "</skill>")
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
format!(
|
||||
|
||||
@@ -18,9 +18,17 @@ impl SubagentNotification {
|
||||
}
|
||||
|
||||
impl ContextualUserFragment for SubagentNotification {
|
||||
const ROLE: &'static str = "user";
|
||||
const START_MARKER: &'static str = "<subagent_notification>";
|
||||
const END_MARKER: &'static str = "</subagent_notification>";
|
||||
fn role() -> &'static str {
|
||||
"user"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
("<subagent_notification>", "</subagent_notification>")
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
format!(
|
||||
|
||||
@@ -17,9 +17,17 @@ impl TurnAborted {
|
||||
}
|
||||
|
||||
impl ContextualUserFragment for TurnAborted {
|
||||
const ROLE: &'static str = "user";
|
||||
const START_MARKER: &'static str = "<turn_aborted>";
|
||||
const END_MARKER: &'static str = "</turn_aborted>";
|
||||
fn role() -> &'static str {
|
||||
"user"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
("<turn_aborted>", "</turn_aborted>")
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
format!("\n{}\n", self.guidance)
|
||||
|
||||
@@ -7,9 +7,17 @@ pub(crate) struct UserInstructions {
|
||||
}
|
||||
|
||||
impl ContextualUserFragment for UserInstructions {
|
||||
const ROLE: &'static str = "user";
|
||||
const START_MARKER: &'static str = "# AGENTS.md instructions for ";
|
||||
const END_MARKER: &'static str = "</INSTRUCTIONS>";
|
||||
fn role() -> &'static str {
|
||||
"user"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
("# AGENTS.md instructions for ", "</INSTRUCTIONS>")
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
format!("{}\n\n<INSTRUCTIONS>\n{}\n", self.directory, self.text)
|
||||
|
||||
@@ -27,9 +27,17 @@ impl UserShellCommand {
|
||||
}
|
||||
|
||||
impl ContextualUserFragment for UserShellCommand {
|
||||
const ROLE: &'static str = "user";
|
||||
const START_MARKER: &'static str = "<user_shell_command>";
|
||||
const END_MARKER: &'static str = "</user_shell_command>";
|
||||
fn role() -> &'static str {
|
||||
"user"
|
||||
}
|
||||
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
("<user_shell_command>", "</user_shell_command>")
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
format!(
|
||||
|
||||
@@ -1634,7 +1634,7 @@ fn budget_limit_steering_item(goal: &ThreadGoal) -> ResponseInputItem {
|
||||
fn goal_context_input_item(prompt: String) -> ResponseInputItem {
|
||||
let context = GoalContext { prompt };
|
||||
ResponseInputItem::Message {
|
||||
role: <GoalContext as ContextualUserFragment>::ROLE.to_string(),
|
||||
role: GoalContext::role().to_string(),
|
||||
content: vec![ContentItem::InputText {
|
||||
text: context.render(),
|
||||
}],
|
||||
|
||||
Reference in New Issue
Block a user