@@ -24,13 +24,14 @@ use crate::config::CodeConfig;
2424use crate :: error:: { read_or_recover, write_or_recover, CodeError , Result } ;
2525use crate :: hitl:: PendingConfirmationInfo ;
2626use crate :: llm:: { LlmClient , Message } ;
27- use crate :: prompts:: SystemPromptSlots ;
27+ use crate :: prompts:: { PlanningMode , SystemPromptSlots } ;
2828use crate :: queue:: {
2929 ExternalTask , ExternalTaskResult , LaneHandlerConfig , SessionLane , SessionQueueConfig ,
3030 SessionQueueStats ,
3131} ;
3232use crate :: scheduler:: { CronScheduler , ScheduledFire } ;
3333use crate :: session_lane_queue:: SessionLaneQueue ;
34+ use crate :: task:: { ProgressTracker , TaskManager } ;
3435use crate :: text:: truncate_utf8;
3536use crate :: tools:: { ToolContext , ToolExecutor } ;
3637use a3s_lane:: { DeadLetter , MetricsSnapshot } ;
@@ -104,7 +105,7 @@ pub struct SessionOptions {
104105 /// Optional permission checker
105106 pub permission_checker : Option < Arc < dyn crate :: permissions:: PermissionChecker > > ,
106107 /// Enable planning
107- pub planning_enabled : bool ,
108+ pub planning_mode : PlanningMode ,
108109 /// Enable goal tracking
109110 pub goal_tracking : bool ,
110111 /// Extra directories to scan for skill files (*.md).
@@ -226,7 +227,7 @@ impl std::fmt::Debug for SessionOptions {
226227 . field ( "context_providers" , & self . context_providers . len ( ) )
227228 . field ( "confirmation_manager" , & self . confirmation_manager . is_some ( ) )
228229 . field ( "permission_checker" , & self . permission_checker . is_some ( ) )
229- . field ( "planning_enabled " , & self . planning_enabled )
230+ . field ( "planning_mode " , & self . planning_mode )
230231 . field ( "goal_tracking" , & self . goal_tracking )
231232 . field (
232233 "skill_registry" ,
@@ -377,9 +378,19 @@ impl SessionOptions {
377378 self . with_permission_checker ( Arc :: new ( crate :: permissions:: PermissionPolicy :: permissive ( ) ) )
378379 }
379380
380- /// Enable planning
381+ /// Set planning mode
382+ pub fn with_planning_mode ( mut self , mode : PlanningMode ) -> Self {
383+ self . planning_mode = mode;
384+ self
385+ }
386+
387+ /// Enable planning (shortcut for `with_planning_mode(PlanningMode::Enabled)`)
381388 pub fn with_planning ( mut self , enabled : bool ) -> Self {
382- self . planning_enabled = enabled;
389+ self . planning_mode = if enabled {
390+ PlanningMode :: Enabled
391+ } else {
392+ PlanningMode :: Disabled
393+ } ;
383394 self
384395 }
385396
@@ -1317,7 +1328,7 @@ impl Agent {
13171328 permission_checker : opts. permission_checker . clone ( ) ,
13181329 confirmation_manager : opts. confirmation_manager . clone ( ) ,
13191330 context_providers : opts. context_providers . clone ( ) ,
1320- planning_enabled : opts. planning_enabled ,
1331+ planning_mode : opts. planning_mode ,
13211332 goal_tracking : opts. goal_tracking ,
13221333 skill_registry : Some ( Arc :: clone ( & effective_registry) ) ,
13231334 max_parse_retries : opts. max_parse_retries . unwrap_or ( base. max_parse_retries ) ,
@@ -1511,6 +1522,8 @@ impl Agent {
15111522 cron_started : AtomicBool :: new ( false ) ,
15121523 cancel_token : Arc :: new ( tokio:: sync:: Mutex :: new ( None ) ) ,
15131524 active_tools : Arc :: new ( tokio:: sync:: RwLock :: new ( HashMap :: new ( ) ) ) ,
1525+ task_manager : Arc :: new ( TaskManager :: new ( ) ) ,
1526+ progress_tracker : Arc :: new ( tokio:: sync:: RwLock :: new ( ProgressTracker :: new ( 30 ) ) ) ,
15141527 } )
15151528 }
15161529}
@@ -1590,6 +1603,10 @@ pub struct AgentSession {
15901603 cancel_token : Arc < tokio:: sync:: Mutex < Option < tokio_util:: sync:: CancellationToken > > > ,
15911604 /// Currently executing tools observed from runtime events.
15921605 active_tools : Arc < tokio:: sync:: RwLock < HashMap < String , ActiveToolSnapshot > > > ,
1606+ /// Task manager for centralized task lifecycle tracking.
1607+ task_manager : Arc < TaskManager > ,
1608+ /// Progress tracker for real-time tool/token usage tracking.
1609+ progress_tracker : Arc < tokio:: sync:: RwLock < ProgressTracker > > ,
15931610}
15941611
15951612#[ derive( Debug , Clone ) ]
@@ -1682,6 +1699,8 @@ impl AgentSession {
16821699 if let Some ( ref queue) = self . command_queue {
16831700 agent_loop = agent_loop. with_queue ( Arc :: clone ( queue) ) ;
16841701 }
1702+ agent_loop = agent_loop. with_progress_tracker ( Arc :: clone ( & self . progress_tracker ) ) ;
1703+ agent_loop = agent_loop. with_task_manager ( Arc :: clone ( & self . task_manager ) ) ;
16851704 agent_loop
16861705 }
16871706
@@ -2375,6 +2394,69 @@ impl AgentSession {
23752394 . collect ( )
23762395 }
23772396
2397+ // ========================================================================
2398+ // Task & Progress API
2399+ // ========================================================================
2400+
2401+ /// Return the task manager for this session.
2402+ ///
2403+ /// The task manager tracks all task lifecycles (tool calls, agent executions, etc.)
2404+ /// and supports subscription to task events.
2405+ pub fn task_manager ( & self ) -> & Arc < TaskManager > {
2406+ & self . task_manager
2407+ }
2408+
2409+ /// Spawn a new task and return its ID.
2410+ ///
2411+ /// # Arguments
2412+ ///
2413+ /// * `task` - The task to spawn
2414+ ///
2415+ /// # Example
2416+ ///
2417+ /// ```rust,ignore
2418+ /// use a3s_code_core::task::Task;
2419+ ///
2420+ /// let task = Task::tool("read", json!({"file_path": "test.txt"}));
2421+ /// let task_id = session.spawn_task(task);
2422+ /// ```
2423+ pub fn spawn_task ( & self , task : crate :: task:: Task ) -> crate :: task:: TaskId {
2424+ self . task_manager . spawn ( task)
2425+ }
2426+
2427+ /// Track a tool call in the progress tracker.
2428+ ///
2429+ /// This is called automatically during tool execution but can also be called manually.
2430+ pub fn track_tool_call ( & self , tool_name : & str , args_summary : & str , success : bool ) {
2431+ if let Ok ( mut guard) = self . progress_tracker . try_write ( ) {
2432+ guard. track_tool_call ( tool_name, args_summary, success) ;
2433+ }
2434+ }
2435+
2436+ /// Get current execution progress.
2437+ ///
2438+ /// Returns a snapshot of tool counts, token usage, and recent activities.
2439+ pub async fn get_progress ( & self ) -> crate :: task:: AgentProgress {
2440+ self . progress_tracker . read ( ) . await . progress ( )
2441+ }
2442+
2443+ /// Subscribe to task events.
2444+ ///
2445+ /// Returns a receiver that will receive all task lifecycle events.
2446+ pub fn subscribe_tasks (
2447+ & self ,
2448+ task_id : crate :: task:: TaskId ,
2449+ ) -> Option < tokio:: sync:: broadcast:: Receiver < crate :: task:: manager:: TaskEvent > > {
2450+ self . task_manager . subscribe ( task_id)
2451+ }
2452+
2453+ /// Subscribe to all task events (global).
2454+ pub fn subscribe_all_tasks (
2455+ & self ,
2456+ ) -> tokio:: sync:: broadcast:: Receiver < crate :: task:: manager:: TaskEvent > {
2457+ self . task_manager . subscribe_all ( )
2458+ }
2459+
23782460 // ========================================================================
23792461 // Hook API
23802462 // ========================================================================
@@ -2436,7 +2518,7 @@ impl AgentSession {
24362518 parent_id : None ,
24372519 security_config : None ,
24382520 hook_engine : None ,
2439- planning_enabled : self . config . planning_enabled ,
2521+ planning_mode : self . config . planning_mode ,
24402522 goal_tracking : self . config . goal_tracking ,
24412523 } ,
24422524 state : crate :: session:: SessionState :: Active ,
@@ -3343,6 +3425,7 @@ dir content
33433425 . with_max_steps ( 3 ) ;
33443426
33453427 let opts = SessionOptions :: new ( ) . with_prompt_slots ( SystemPromptSlots {
3428+ style : None ,
33463429 role : Some ( "Custom role" . to_string ( ) ) ,
33473430 guidelines : None ,
33483431 response_style : None ,
0 commit comments