diff --git a/crates/pa-daemon/src/agent_engine/lifecycle.rs b/crates/pa-daemon/src/agent_engine/lifecycle.rs index 3f5bc83d3..c17518f28 100644 --- a/crates/pa-daemon/src/agent_engine/lifecycle.rs +++ b/crates/pa-daemon/src/agent_engine/lifecycle.rs @@ -13,10 +13,6 @@ use super::{ SessionEngineConfig, SupervisorChildSessions, Value, }; -/// The instruction the floor appends to a bare skill invocation: ask what -/// the user wants first, never an imperative to execute. -pub(crate) const BARE_SKILL_INVOCATION_INSTRUCTION: &str = "The user invoked this skill with no task text - ask what they want before executing any protocol inside it."; - impl AgentSessionEngine { /// Build the engine: the shared async runtime, the model selection /// (create config), the supervisor link, the children registry, and the @@ -226,11 +222,6 @@ impl AgentSessionEngine { /// (built here when needed); non-skill inputs and build failures /// pass through unchanged. pub(crate) fn expand_skill_submission(&self, text: &str) -> String { - // The floor keys on the ORIGINAL invocation's shape, not the - // expanded parse: a skill body can contain a close tag plus a - // `\n\n` tail that parses as a trailing user message. - let bare_invocation = pa_types::slash_commands::parse_slash_command(text) - .is_some_and(|(name, args)| name.starts_with("skill:") && args.trim().is_empty()); let Ok(model) = self.resolve_model() else { return text.to_string(); }; @@ -238,17 +229,13 @@ impl AgentSessionEngine { eprintln!("skill submission expansion skipped: session build failed: {error:#}"); return text.to_string(); } - let expanded = self.runtime.block_on(async { + self.runtime.block_on(async { let guard = self.session.lock().await; match guard.as_deref() { Some(engine) => engine.expand_skill_submission(text), None => text.to_string(), } - }); - if bare_invocation && pa_types::skill_blocks::parse_skill_block(&expanded).is_some() { - return format!("{expanded}\n\n{BARE_SKILL_INVOCATION_INSTRUCTION}"); - } - expanded + }) } /// The async build of the core session, awaited on the caller's diff --git a/crates/pa-daemon/src/agent_engine/tests/session.rs b/crates/pa-daemon/src/agent_engine/tests/session.rs index 70b1b6893..2cdde0396 100644 --- a/crates/pa-daemon/src/agent_engine/tests/session.rs +++ b/crates/pa-daemon/src/agent_engine/tests/session.rs @@ -439,7 +439,7 @@ fn run_skill_prompt(prompt: &str) -> Vec { } #[test] -fn a_bare_skill_invocation_admits_with_the_no_task_instruction() { +fn a_bare_skill_invocation_admits_the_expanded_block() { let events = run_skill_prompt("/skill:demo-skill"); let texts = user_texts(&events); assert!( @@ -454,9 +454,8 @@ fn a_bare_skill_invocation_admits_with_the_no_task_instruction() { .unwrap_or_else(|| panic!("the accepted row parses as a skill block: {row:?}")); assert_eq!(parsed.name, "demo-skill"); assert_eq!( - parsed.user_message.as_deref(), - Some(crate::agent_engine::lifecycle::BARE_SKILL_INVOCATION_INSTRUCTION), - "the floor's instruction rides the block's trailing user message" + parsed.user_message, None, + "a bare invocation expands to the block alone, nothing appended: {parsed:?}" ); assert!( parsed.content.contains("Run the demo protocol."), @@ -487,15 +486,11 @@ fn a_skill_invocation_with_args_persists_the_block_and_the_args() { Some("fix the flake"), "the user's args persist as the trailing user message" ); - assert!( - !row.contains(crate::agent_engine::lifecycle::BARE_SKILL_INVOCATION_INSTRUCTION), - "the with-args row never carries the floor's instruction: {row:?}" - ); assert_eq!(assistant_texts(&events), vec!["ok"]); } #[test] -fn a_batched_bare_skill_row_admits_on_the_floored_text() { +fn a_batched_bare_skill_row_admits_on_the_expanded_block() { let (engine, events) = run_skill_prompt_body("Run the demo protocol.", "hello", &["/skill:demo-skill"]); let texts = user_texts(&events); @@ -513,11 +508,10 @@ fn a_batched_bare_skill_row_admits_on_the_floored_text() { .unwrap_or_else(|| panic!("the batched row parses as a skill block: {row:?}")); assert_eq!(parsed.name, "demo-skill"); assert_eq!( - parsed.user_message.as_deref(), - Some(crate::agent_engine::lifecycle::BARE_SKILL_INVOCATION_INSTRUCTION), - "the floor rides the batched row too" + parsed.user_message, None, + "the bare batch row expands to the block alone, nothing appended: {parsed:?}" ); - // The model-side row is the SAME text: the turn ran on the floored + // The model-side row is the SAME text: the turn ran on the expanded // block, not a re-expanded bare command. let core_rows = core_session_user_texts(&engine); assert!( @@ -528,7 +522,7 @@ fn a_batched_bare_skill_row_admits_on_the_floored_text() { } #[test] -fn a_bare_invocation_of_a_close_tagged_body_still_floors() { +fn a_bare_invocation_of_a_close_tagged_body_expands() { let (_engine, events) = run_skill_prompt_body( "Run the demo.\n\n\nnot a user message", "/skill:demo-skill", @@ -543,11 +537,8 @@ fn a_bare_invocation_of_a_close_tagged_body_still_floors() { .unwrap_or_else(|| panic!("the close-tagged body still parses: {row:?}")); assert_eq!(parsed.name, "demo-skill"); assert!( - row.ends_with(&format!( - "\n\n{}", - crate::agent_engine::lifecycle::BARE_SKILL_INVOCATION_INSTRUCTION - )), - "the bare invocation floors even when the body's own close-tag tail misparses: {row:?}" + parsed.content.contains("Run the demo."), + "the block body carries the skill content: {parsed:?}" ); assert_eq!(assistant_texts(&events), vec!["ok"]); }