1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//! Session construction helpers for spawned agents.
//!
//! Creates an initialized sub-agent [`Session`] with:
//! - a scoped **agent name** for routing messages,
//! - a **model** override distinct from the parent,
//! - a **system prompt** that inherits the parent's working directory so the
//! sub-agent does not waste turns rediscovering the workspace.
//!
//! Keeping this separate from [`super::spawn_validation`] and
//! [`super::spawn_store`] enforces SRP: construction is one concern, policy
//! checks and persistence are others.
//!
//! # Examples
//!
//! ```rust,no_run
//! # tokio::runtime::Runtime::new().unwrap().block_on(async {
//! // `create_agent_session` is crate-private; this snippet illustrates how the
//! // module is wired from `handle_spawn`.
//! # async fn demo() -> anyhow::Result<()> {
//! # use codetether_agent::session::Session;
//! // inside crate::tool::agent::spawn::handle_spawn:
//! // let session = create_agent_session("reviewer", "Audit the PR", "glm-5.1").await?;
//! # Ok(()) }
//! # });
//! ```
use crate;
use crateSession;
use ;
use PathBuf;
/// Create a fresh [`Session`] for a spawned sub-agent.
///
/// The session is initialized with:
/// - `agent_name` set to `name` (used by the TUI / bus for message routing),
/// - `metadata.model` set to `model` (independent of the parent's model),
/// - `metadata.directory` set to the parent's workspace/worktree when provided,
/// - a single system message built by [`build_system_message`] that embeds the
/// same workspace plus explicit guidance not to spend turns on workspace
/// discovery.
///
/// # Arguments
///
/// * `name` — Sub-agent identifier, e.g. `"reviewer"`. Referenced by users as `@reviewer`.
/// * `instructions` — Free-form task description merged into the system prompt.
/// * `model` — Provider model id, e.g. `"zai/glm-5.1"`.
/// * `parent_workspace` — Workspace/worktree inherited from the parent session.
///
/// # Returns
///
/// A fully initialized [`Session`] ready to be persisted via
/// [`super::spawn_store::persist_spawned_agent`].
///
/// # Errors
///
/// Returns [`anyhow::Error`] if [`Session::new`] fails (typically disk I/O
/// when initializing the session directory).
///
/// # Examples
///
/// ```rust,no_run
/// # tokio::runtime::Runtime::new().unwrap().block_on(async {
/// # async fn demo() -> anyhow::Result<()> {
/// // Crate-private: shown here for illustration. Real callers live in
/// // crate::tool::agent::spawn.
/// // let session = create_agent_session(
/// // "tui-cache-fix",
/// // "Apply the cache-clone fix in src/tui/app/state.rs and verify cargo check.",
/// // "zai/glm-5.1",
/// // Some(std::path::PathBuf::from("/workspace/project")),
/// // ).await?;
/// // assert_eq!(session.metadata.model.as_deref(), Some("zai/glm-5.1"));
/// # Ok(()) }
/// # });
/// ```
pub async
/// Build the system prompt injected into every spawned sub-agent.
///
/// The prompt embeds the same workspace stored on the spawned child session so
/// the sub-agent can resolve relative paths immediately, and includes explicit
/// directives to avoid workspace-discovery tool calls (`pwd`, `ls`, `glob`)
/// that were observed burning 4–6 turns before any real edit.
///
/// If no workspace was passed from the parent, the directory falls back to
/// [`std::env::current_dir`] and then the literal string `"<unknown>"`. This
/// never panics.
///
/// # Arguments
///
/// * `name` — Sub-agent identifier injected as `@{name}`.
/// * `instructions` — Task description appended to the role preamble.
/// * `workspace` — Resolved parent workspace/worktree.
///
/// # Returns
///
/// A multi-line system prompt string.