Skip to main content

codetether_agent/tool/session_task/
tool.rs

1//! `session_task` [`Tool`] implementation — the agent-facing entrypoint.
2
3use super::handlers::{clear_goal, list, reaffirm, set_goal, task_add, task_status};
4use super::params::Params;
5use crate::session::tasks::TaskLog;
6use crate::tool::{Tool, ToolResult};
7use anyhow::{Result, anyhow};
8use async_trait::async_trait;
9use serde_json::{Value, json};
10
11pub struct SessionTaskTool;
12
13impl Default for SessionTaskTool {
14    fn default() -> Self {
15        Self
16    }
17}
18
19impl SessionTaskTool {
20    pub fn new() -> Self {
21        Self
22    }
23}
24
25#[async_trait]
26impl Tool for SessionTaskTool {
27    fn id(&self) -> &str {
28        "session_task"
29    }
30    fn name(&self) -> &str {
31        "Session Task & Goal"
32    }
33    fn description(&self) -> &str {
34        "Manage the session's goal and task list. Actions: \
35         `set_goal` (objective, success_criteria?, forbidden?), \
36         `reaffirm` (progress_note), \
37         `clear_goal` (reason?), \
38         `task_add` (content, id?, parent_id?), \
39         `task_status` (id, status: pending|in_progress|done|blocked|cancelled, note?), \
40         `list`. Events are appended to the session's .tasks.jsonl."
41    }
42    fn parameters(&self) -> Value {
43        json!({
44            "type": "object",
45            "properties": {
46                "action": {"type": "string", "enum": [
47                    "set_goal", "reaffirm", "clear_goal",
48                    "task_add", "task_status", "list"
49                ]},
50                "objective": {"type": "string"},
51                "success_criteria": {"type": "array", "items": {"type": "string"}},
52                "forbidden": {"type": "array", "items": {"type": "string"}},
53                "progress_note": {"type": "string"},
54                "reason": {"type": "string"},
55                "id": {"type": "string"},
56                "content": {"type": "string"},
57                "parent_id": {"type": "string"},
58                "status": {"type": "string",
59                    "enum": ["pending", "in_progress", "done", "blocked", "cancelled"]},
60                "note": {"type": "string"}
61            },
62            "required": ["action"]
63        })
64    }
65
66    async fn execute(&self, params: Value) -> Result<ToolResult> {
67        let p: Params = serde_json::from_value(params)?;
68        let sid = p
69            .ct_session_id
70            .clone()
71            .or_else(|| std::env::var("CODETETHER_SESSION_ID").ok())
72            .ok_or_else(|| anyhow!("session id not available; cannot locate task log"))?;
73        let log = TaskLog::for_session(&sid)?;
74        match p.action.as_str() {
75            "set_goal" => set_goal(&log, p).await,
76            "reaffirm" => reaffirm(&log, p).await,
77            "clear_goal" => clear_goal(&log, p).await,
78            "task_add" => task_add(&log, p).await,
79            "task_status" => task_status(&log, p).await,
80            "list" => list(&log).await,
81            other => Ok(ToolResult::error(format!("unknown action: {other}"))),
82        }
83    }
84}