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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//! 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 ;
/// 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),
/// - a single system message built by [`build_system_message`] that embeds the
/// parent process's current working directory 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"`.
///
/// # 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",
/// // ).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 *parent* process's current working directory 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.
///
/// The directory is read from [`std::env::current_dir`] at spawn time and
/// falls back to the literal string `"<unknown>"` on failure (e.g. the cwd
/// was deleted). This never panics.
///
/// # Arguments
///
/// * `name` — Sub-agent identifier injected as `@{name}`.
/// * `instructions` — Task description appended to the role preamble.
///
/// # Returns
///
/// A multi-line system prompt string.