codetether_agent/session/tasks/
render.rs1use super::state::TaskState;
4
5pub fn governance_block(state: &TaskState) -> Option<String> {
12 if state.goal.is_none() && state.tasks.is_empty() {
13 return None;
14 }
15
16 let mut out = String::from("## Goal Governance\n");
17
18 if let Some(g) = &state.goal {
19 out.push_str("\nOBJECTIVE: ");
20 out.push_str(&g.objective);
21 out.push('\n');
22
23 if !g.success_criteria.is_empty() {
24 out.push_str("\nDONE WHEN:\n");
25 for c in &g.success_criteria {
26 out.push_str("- ");
27 out.push_str(c);
28 out.push('\n');
29 }
30 }
31
32 out.push_str("\nFORBIDDEN:\n");
33 out.push_str(
34 "- Entering credentials, passwords, or OAuth codes on behalf of the user. \
35 Stop at login walls and hand control back.\n",
36 );
37 for f in &g.forbidden {
38 out.push_str("- ");
39 out.push_str(f);
40 out.push('\n');
41 }
42
43 out.push_str(
44 "\nIf the next action does not advance OBJECTIVE, stop and ask the user \
45 before proceeding. Do not attempt to solve sub-problems that require \
46 information you do not have.\n",
47 );
48
49 if state.tool_calls_since_reaffirm >= 10 || state.errors_since_reaffirm >= 3 {
50 out.push_str(&format!(
51 "\nDRIFT WARNING: {} tool calls and {} errors since last goal \
52 reaffirmation. State concretely what is done, what remains, or \
53 whether you are blocked — then call `session_task` with \
54 `action = \"reaffirm\"`.\n",
55 state.tool_calls_since_reaffirm, state.errors_since_reaffirm,
56 ));
57 }
58 }
59
60 let open = state.open_tasks();
61 if !open.is_empty() {
62 out.push_str("\nOPEN TASKS:\n");
63 for t in open {
64 let marker = match t.status {
65 super::event::TaskStatus::InProgress => "◐",
66 _ => "○",
67 };
68 out.push_str(&format!("{} [{}] {}\n", marker, t.id, t.content));
69 }
70 }
71
72 Some(out)
73}