mindroot 9.24.0__py3-none-any.whl → 10.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of mindroot might be problematic. Click here for more details.

@@ -1,100 +1,131 @@
1
1
  """
2
- checklist helper for an LLMagent system
3
- —————————————————————————————————————————————————————————————————————————————
2
+ checklist helper for an LLM-agent system
3
+ ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
4
4
  Purpose
5
5
  -------
6
- • Parse a Markdown "##\tChecklist" section where each subtask is
7
- written as a task‑list line:
8
6
 
9
- - [ ] label of subtask
10
- arbitrary markdown body… (until next task or heading)
11
-
12
- Store parsed tasks + cursor in `context.data['checklist']`.
13
-
14
- • Runtime helpers:
15
- load_checklist(md, ctx) → parse markdown + reset state
16
- complete_subtask(subtask_id, context) → mark subtask done, advance cursor
17
- goto_subtask(subtask_id, context) → move to a specific subtask
18
- clear_subtask(subtask_id, context) → mark a subtask as incomplete
19
- get_checklist_status(context) → show the full checklist status
7
+ Parse a Markdown checklist section where each subtask is written as a task-list line
8
+ Store parsed tasks + cursor in `context.data['checklist']`
9
+ • Support nested subtasks within parent task bodies
10
+ Runtime helpers for managing both top-level and nested subtasks
20
11
 
21
12
  `complete_subtask` and other commands live at module level so the agent can call them
22
- as tools. No thirdparty deps—only Python's `re` module.
13
+ as tools. No third-party deps—only Python's `re` module.
23
14
  """
24
15
 
25
16
  import re
26
- from lib.providers.commands import command
17
+ from lib.providers.commands import command, command_manager
27
18
  from lib.providers.services import service
28
19
  import traceback
20
+ from collections import Counter
21
+ from .helpers import (
22
+ find_nested_subtask,
23
+ update_nested_subtask_status,
24
+ resolve_subtask_id_with_nesting,
25
+ format_nested_task_status,
26
+ get_next_incomplete_task,
27
+ has_incomplete_nested_tasks
28
+ )
29
29
 
30
- # ---------- parsing ------------------------------------------------------
30
+ # ---------- simple parsing -----------------------------------------------
31
31
 
32
- TASK_RE = re.compile(r'^-\s*\[(?P<done>[ xX])\]\s*(?P<label>.*?)\s*$')
33
- HEADER_RE = re.compile(r'^#{1,6}\s') # any Markdown heading
34
- CHECKLIST_HEADER_RE = re.compile(r'^#{1,6}\s+Checklist\b', re.IGNORECASE) # Checklist heading
35
-
36
- def _parse(md: str):
37
- """Extract tasks as a list of dicts: {label, body, done}."""
38
- lines, tasks, i = md.splitlines(), [], 0
32
+ def _parse(text):
33
+ """Simple, robust checklist parser.
34
+
35
+ Finds checklist items (- [ ] or - [x]) at any indentation level,
36
+ but only processes items at the same indentation as the first one found.
37
+
38
+ Returns list of {label, body, done} dicts.
39
+ """
40
+ print("parsing:")
41
+ print("---------------------------------------------")
42
+ print(text)
43
+ print('---------------------------------------------')
44
+ lines = text.splitlines()
45
+ tasks = []
46
+ i = 0
47
+ first_task_indent = None
48
+
49
+ # Find all task lines and their indentations first
50
+ task_indents = []
51
+ for line in lines:
52
+ stripped = line.lstrip()
53
+ if stripped.startswith('- [ ]') or stripped.startswith('- [x]') or stripped.startswith('- [X]'):
54
+ indent = len(line) - len(stripped)
55
+ task_indents.append(indent)
56
+
57
+ if not task_indents:
58
+ return tasks
59
+
60
+ # Use the SMALLEST indentation level as reference (top-level tasks)
61
+ reference_indent = min(task_indents)
62
+ print("reference indent:", reference_indent)
39
63
  while i < len(lines):
40
- m = TASK_RE.match(lines[i])
41
- if not m: # not a task‑list line
42
- i += 1
43
- continue
44
-
45
- done = m.group("done").strip().lower() in ("x", "✓")
46
- label = m.group("label").strip()
47
-
48
- # collect everything until next task or heading
49
- body_lines = []
64
+ line = lines[i]
65
+ stripped = line.lstrip()
66
+ print(i)
67
+ # Check if this line is a checklist item
68
+ if stripped.startswith('- [ ]') or stripped.startswith('- [x]') or stripped.startswith('- [X]'):
69
+ # Calculate indentation
70
+ current_indent = len(line) - len(stripped)
71
+ print("found task at indent:", current_indent)
72
+ print("reference indent:", reference_indent)
73
+ # Only process tasks at the reference indentation level
74
+ if current_indent == reference_indent:
75
+ # Extract task info
76
+ done = stripped.startswith('- [x]') or stripped.startswith('- [X]')
77
+
78
+ # Extract label (everything after the checkbox)
79
+ if stripped.startswith('- [ ]'):
80
+ label = stripped[5:].strip()
81
+ else: # - [x] or - [X]
82
+ label = stripped[5:].strip()
83
+
84
+ # Collect body lines until next task at same level or end
85
+ body_lines = []
86
+ i += 1
87
+
88
+ while i < len(lines):
89
+ print("checking line for body:",i, lines[i])
90
+ next_line = lines[i]
91
+ next_stripped = next_line.lstrip()
92
+ next_indent = len(next_line) - len(next_stripped)
93
+ print("next_stripped:", next_stripped)
94
+ print("next_indent:", next_indent)
95
+ print("reference_indent:", reference_indent)
96
+ # Stop if we hit another task at the same indentation level
97
+ if ((next_stripped.startswith('- [ ]') or
98
+ next_stripped.startswith('- [x]') or
99
+ next_stripped.startswith('- [X]')) and
100
+ next_indent <= reference_indent):
101
+ break
102
+
103
+ # Stop if we hit a markdown heading
104
+ if next_stripped.startswith('#'):
105
+ break
106
+
107
+ body_lines.append(next_line)
108
+ i += 1
109
+
110
+ tasks.append({
111
+ 'label': label,
112
+ 'body': '\n'.join(body_lines), #.strip(),
113
+ 'done': done
114
+ })
115
+ continue
116
+
50
117
  i += 1
51
- while i < len(lines) and not (
52
- TASK_RE.match(lines[i]) or HEADER_RE.match(lines[i])
53
- ):
54
- body_lines.append(lines[i])
55
- i += 1
56
-
57
- tasks.append({
58
- "label": label,
59
- "body": "\n".join(body_lines).strip(),
60
- "done": done,
61
- })
118
+
62
119
  return tasks
63
120
 
64
121
 
65
122
  def extract_checklist_section(md: str):
66
- """Extract the checklist section from larger text.
123
+ """Extract checklist items from the entire markdown text.
67
124
 
68
- Looks for a heading like '# Checklist', '## Checklist', etc., and extracts
69
- all content from that heading until the next heading of the same or lower level,
70
- or the end of the text.
71
-
72
- Returns the extracted section, or the original text if no checklist section is found.
125
+ No longer requires a specific 'Checklist' heading - processes the entire text
126
+ and extracts only top-level checklist items, leaving nested ones intact.
73
127
  """
74
- lines = md.splitlines()
75
- start_idx = None
76
- checklist_level = 0
77
-
78
- # Find the checklist heading
79
- for i, line in enumerate(lines):
80
- match = CHECKLIST_HEADER_RE.match(line)
81
- if match:
82
- start_idx = i
83
- # Count the number of # to determine heading level
84
- checklist_level = len(line) - len(line.lstrip('#'))
85
- break
86
-
87
- if start_idx is None:
88
- return md # No checklist section found, return original text
89
-
90
- # Find the end of the section (next heading of same or lower level)
91
- end_idx = len(lines)
92
- for i in range(start_idx + 1, len(lines)):
93
- if HEADER_RE.match(lines[i]) and len(lines[i]) - len(lines[i].lstrip('#')) <= checklist_level:
94
- end_idx = i
95
- break
96
-
97
- return "\n".join(lines[start_idx:end_idx])
128
+ return md
98
129
 
99
130
 
100
131
  # ---------- state helpers ------------------------------------------------
@@ -115,12 +146,9 @@ def load_checklist(md: str, ctx):
115
146
 
116
147
  @service()
117
148
  async def load_checklist_from_instructions(md: str, context=None):
118
- """Extract checklist section from instructions and load it.
149
+ """Load checklist from instructions.
119
150
 
120
- Looks for a section starting with '# Checklist' or similar heading.
121
-
122
- Example:
123
- { "load_checklist_from_instructions": { "md": "Full instructions with embedded checklist" } }
151
+ Processes the entire text and extracts top-level checklist items.
124
152
  """
125
153
  checklist_section = extract_checklist_section(md)
126
154
  load_checklist(checklist_section, context)
@@ -130,31 +158,17 @@ async def load_checklist_from_instructions(md: str, context=None):
130
158
  # ---------- helper functions ---------------------------------------------
131
159
 
132
160
  def _resolve_subtask_id(subtask_id, context):
133
- """Resolve a subtask_id to an index (0-based).
161
+ """Resolve a subtask_id to an index (0-based) with nested task support.
134
162
 
135
163
  subtask_id can be:
136
164
  - A number (1-based index, converted to 0-based)
137
- - A string matching a subtask label
165
+ - A string matching a subtask label (top-level or nested)
138
166
  - None/default (-1) to use the current cursor position
167
+
168
+ Returns tuple of (index, nested_info) where nested_info is None for top-level tasks
139
169
  """
140
170
  st = _state(context)
141
-
142
- # Default to current cursor position
143
- if subtask_id is None or subtask_id == -1:
144
- return st["cursor"]
145
-
146
- # If it's a number, convert from 1-based to 0-based
147
- if isinstance(subtask_id, int):
148
- idx = subtask_id - 1
149
- else:
150
- # It's a string, try to find a matching label
151
- for i, task in enumerate(st["tasks"]):
152
- if task["label"] == subtask_id:
153
- return i
154
- # No match found
155
- return -1
156
-
157
- return idx
171
+ return resolve_subtask_id_with_nesting(subtask_id, st["tasks"], st["cursor"])
158
172
 
159
173
 
160
174
  def _format_checklist_status(context):
@@ -176,25 +190,34 @@ def _format_checklist_status(context):
176
190
 
177
191
  # Add task line
178
192
  lines.append(f"{status}**Subtask**: {task['label']}")
193
+
194
+ # Show nested task status if any
195
+ nested_tasks = _parse(task['body'])
196
+ if nested_tasks:
197
+ for nested_task in nested_tasks:
198
+ nested_status = "✅" if nested_task["done"] else "❌"
199
+ lines.append(f" {nested_status} {nested_task['label']}")
179
200
 
180
201
  return "\n".join(lines)
181
202
 
182
203
 
183
- # ---------- modulelevel tool commands ----------------------------------
204
+ # ---------- module-level tool commands ----------------------------------
184
205
 
185
206
  @command()
186
207
  async def complete_subtask(subtask_id=None, context=None):
187
208
  """
188
209
  Mark a subtask complete and return a Markdown status message.
210
+ Now supports both top-level and nested subtasks.
189
211
 
190
212
  Parameters:
191
213
  - subtask_id: Optional. The subtask to complete, specified by:
192
- - The exact subtask label text
214
+ - The exact subtask label text (top-level or nested)
193
215
  - Omit to complete the current subtask
194
216
 
195
217
  Example:
196
218
  { "complete_subtask": {} } # Complete current subtask
197
219
  { "complete_subtask": { "subtask_id": "Review documents" } } # Complete by label
220
+ { "complete_subtask": { "subtask_id": "USP" } } # Complete nested subtask
198
221
  """
199
222
  if context is None:
200
223
  return "_Context is required._"
@@ -213,19 +236,56 @@ async def complete_subtask(subtask_id=None, context=None):
213
236
  print(trace)
214
237
  return "_No checklist found. Make sure to include a checklist in your instructions._"
215
238
 
216
- idx = _resolve_subtask_id(subtask_id, context)
239
+ idx, nested_info = _resolve_subtask_id(subtask_id, context)
217
240
  if idx < 0 or idx >= len(st["tasks"]):
218
241
  return "_Invalid subtask identifier._"
219
242
 
220
- # mark as done
243
+ # Handle nested subtask completion
244
+ if nested_info is not None:
245
+ # Mark nested subtask as done
246
+ nested_info['nested_task']['done'] = True
247
+
248
+ # Update the parent task's body with the new nested task status
249
+ parent_task = st["tasks"][idx]
250
+ updated_body = update_nested_subtask_status(
251
+ parent_task,
252
+ nested_info['nested_index'],
253
+ nested_info['parent_nested_tasks'],
254
+ True
255
+ )
256
+ parent_task['body'] = updated_body
257
+
258
+ # Check if all nested tasks in this parent are complete
259
+ all_nested_complete = all(task['done'] for task in nested_info['parent_nested_tasks'])
260
+ if all_nested_complete:
261
+ parent_task['done'] = True
262
+ # Advance cursor to next incomplete top-level task
263
+ st["cursor"] = get_next_incomplete_task(st["tasks"], idx + 1)
264
+
265
+ completed_msg = f"Completed Nested Subtask: - [x] {nested_info['nested_task']['label']} (within '{parent_task['label']}')"
266
+
267
+ if all_nested_complete:
268
+ completed_msg += f"\n\nParent task '{parent_task['label']}' is now complete!"
269
+
270
+ # Show next task info
271
+ if st["cursor"] >= len(st["tasks"]):
272
+ return f"{completed_msg}\n\nAll subtasks complete ✅\n\n{_format_checklist_status(context)}"
273
+
274
+ next_task = st["tasks"][st['cursor']]
275
+ return f"""{completed_msg}
276
+
277
+ Next subtask (Subtask {st['cursor']+1})
278
+ - [ ] {next_task['label']}
279
+ {next_task['body']}
280
+
281
+ {_format_checklist_status(context)}"""
282
+
283
+ # Handle top-level subtask completion
221
284
  done_task = st["tasks"][idx]
222
285
  done_task["done"] = True
223
286
 
224
287
  # advance cursor to next open subtask
225
- st["cursor"] = next(
226
- (i for i, t in enumerate(st["tasks"][idx + 1:], idx + 1) if not t["done"]),
227
- len(st["tasks"]),
228
- )
288
+ st["cursor"] = get_next_incomplete_task(st["tasks"], idx + 1)
229
289
 
230
290
  # build markdown response
231
291
  completed = f"Completed Subtask {idx+1}: - [x] {done_task['label']}"
@@ -233,27 +293,28 @@ async def complete_subtask(subtask_id=None, context=None):
233
293
  return f"{completed}\n\nAll subtasks complete ✅\n\n{_format_checklist_status(context)}"
234
294
 
235
295
  next_task = st["tasks"][st['cursor']]
236
- return f"""
237
- {completed}
296
+ return f"""{completed}
238
297
 
239
- Next subtask (Subtask {st['cursor']+1})
240
- - [ ] {next_task['label']}
241
- {next_task['body']}
298
+ Next subtask (Subtask {st['cursor']+1})
299
+ - [ ] {next_task['label']}
300
+ {next_task['body']}
301
+
302
+ {_format_checklist_status(context)}"""
242
303
 
243
- {_format_checklist_status(context)}
244
- """
245
304
 
246
305
  @command()
247
306
  async def goto_subtask(subtask_id, context=None):
248
307
  """
249
308
  Move to a specific subtask without changing its completion status.
309
+ Now supports both top-level and nested subtasks.
250
310
 
251
311
  Parameters:
252
312
  - subtask_id: Required. The subtask to navigate to, specified by:
253
- - The exact subtask label text
313
+ - The exact subtask label text (top-level or nested)
254
314
 
255
315
  Example:
256
- { "goto_subtask": { "subtask_id": "Data analysis" } } # Go to by label
316
+ { "goto_subtask": { "subtask_id": "Data analysis" } } # Go to top-level task
317
+ { "goto_subtask": { "subtask_id": "USP" } } # Go to nested task
257
318
  """
258
319
  if context is None:
259
320
  return "_Context is required._"
@@ -262,17 +323,22 @@ async def goto_subtask(subtask_id, context=None):
262
323
  if not st["tasks"]:
263
324
  return "_No checklist found. Make sure to include a checklist in your instructions._"
264
325
 
265
- idx = _resolve_subtask_id(subtask_id, context)
326
+ idx, nested_info = _resolve_subtask_id(subtask_id, context)
266
327
  if idx < 0 or idx >= len(st["tasks"]):
267
328
  return "_Invalid subtask identifier._"
268
329
 
269
- # Update cursor position
330
+ # Update cursor position to the parent task
270
331
  st["cursor"] = idx
271
332
 
272
- # Get the current task
273
- current_task = st["tasks"][idx]
333
+ # Handle nested subtask navigation
334
+ if nested_info is not None:
335
+ return (
336
+ f"Moved to Nested Subtask: {format_nested_task_status(nested_info)}\n\n"
337
+ f"{_format_checklist_status(context)}"
338
+ )
274
339
 
275
- # Build response
340
+ # Handle top-level subtask navigation
341
+ current_task = st["tasks"][idx]
276
342
  status = "✅" if current_task["done"] else "❌"
277
343
  return (
278
344
  f"Moved to Subtask {idx+1}: {status} {current_task['label']}\n"
@@ -285,15 +351,17 @@ async def goto_subtask(subtask_id, context=None):
285
351
  async def clear_subtask(subtask_id=None, context=None):
286
352
  """
287
353
  Mark a subtask as incomplete (not done).
354
+ Now supports both top-level and nested subtasks.
288
355
 
289
356
  Parameters:
290
357
  - subtask_id: Optional. The subtask to clear, specified by:
291
- - The exact subtask label text
358
+ - The exact subtask label text (top-level or nested)
292
359
  - Omit to clear the current subtask
293
360
 
294
361
  Example:
295
362
  { "clear_subtask": {} } # Clear current subtask
296
- { "clear_subtask": { "subtask_id": "Review documents" } } # Clear by label
363
+ { "clear_subtask": { "subtask_id": "Review documents" } } # Clear top-level by label
364
+ { "clear_subtask": { "subtask_id": "USP" } } # Clear nested subtask
297
365
  """
298
366
  if context is None:
299
367
  return "_Context is required._"
@@ -302,11 +370,43 @@ async def clear_subtask(subtask_id=None, context=None):
302
370
  if not st["tasks"]:
303
371
  return "_No checklist found. Make sure to include a checklist in your instructions._"
304
372
 
305
- idx = _resolve_subtask_id(subtask_id, context)
373
+ idx, nested_info = _resolve_subtask_id(subtask_id, context)
306
374
  if idx < 0 or idx >= len(st["tasks"]):
307
375
  return "_Invalid subtask identifier._"
308
376
 
309
- # Mark as not done
377
+ # Handle nested subtask clearing
378
+ if nested_info is not None:
379
+ # Mark nested subtask as not done
380
+ nested_task = nested_info['nested_task']
381
+ was_done = nested_task['done']
382
+ nested_task['done'] = False
383
+
384
+ # Update the parent task's body
385
+ parent_task = st["tasks"][idx]
386
+ updated_body = update_nested_subtask_status(
387
+ parent_task,
388
+ nested_info['nested_index'],
389
+ nested_info['parent_nested_tasks'],
390
+ False
391
+ )
392
+ parent_task['body'] = updated_body
393
+
394
+ # If parent was complete but now has incomplete nested tasks, mark parent incomplete
395
+ if parent_task['done'] and has_incomplete_nested_tasks(parent_task):
396
+ parent_task['done'] = False
397
+
398
+ # Update cursor to this parent task if needed
399
+ if idx <= st["cursor"]:
400
+ st["cursor"] = idx
401
+
402
+ action = "Cleared" if was_done else "Already clear"
403
+ return (
404
+ f"{action} Nested Subtask: - [ ] {nested_task['label']} (within '{parent_task['label']}')\n"
405
+ f"Current subtask is now Subtask {st['cursor']+1}\n\n"
406
+ f"{_format_checklist_status(context)}"
407
+ )
408
+
409
+ # Handle top-level subtask clearing
310
410
  task = st["tasks"][idx]
311
411
  was_done = task["done"]
312
412
  task["done"] = False
@@ -336,3 +436,160 @@ async def get_checklist_status(context=None):
336
436
  return "_Context is required._"
337
437
 
338
438
  return _format_checklist_status(context)
439
+
440
+
441
+ @command()
442
+ async def get_parsed_subtasks(subtask_id=None, context=None):
443
+ """
444
+ Return parsed subtasks with their name/id and body for verification.
445
+ Now supports getting nested subtasks from within parent tasks.
446
+
447
+ Parameters:
448
+ - subtask_id: Optional. If provided, parse subtasks from the body of this specific subtask.
449
+ If omitted, returns all top-level subtasks from the main checklist.
450
+
451
+ Returns a list of dictionaries with:
452
+ - label: The subtask name/label
453
+ - body: The subtask body content
454
+ - done: Whether the subtask is marked as complete
455
+ - index: The 0-based index of the subtask
456
+
457
+ Example:
458
+ { "get_parsed_subtasks": {} } # Get all top-level subtasks
459
+ { "get_parsed_subtasks": { "subtask_id": "Research phase" } } # Get nested subtasks from "Research phase"
460
+ { "get_parsed_subtasks": { "subtask_id": "Core" } } # Get nested subtasks from "Core"
461
+ """
462
+ if context is None:
463
+ return "_Context is required._"
464
+
465
+ st = _state(context)
466
+ if not st["tasks"]:
467
+ try:
468
+ print("Loading checklist from instructions...")
469
+ instructions = context.agent["instructions"]
470
+ await load_checklist_from_instructions(instructions, context)
471
+ st = _state(context) # Refresh state after loading
472
+ except Exception as e:
473
+ print(f"Error loading checklist: {e}")
474
+ return "_No checklist found. Make sure to include a checklist in your instructions._"
475
+
476
+ # If no subtask_id provided, return all top-level subtasks
477
+ if subtask_id is None:
478
+ result = []
479
+ for i, task in enumerate(st["tasks"]):
480
+ result.append({
481
+ "index": i,
482
+ "label": task["label"],
483
+ "body": task["body"],
484
+ "done": task["done"]
485
+ })
486
+ return {
487
+ "source": "top-level checklist",
488
+ "subtasks": result
489
+ }
490
+
491
+ # Find the specified subtask and parse its body for nested subtasks
492
+ idx, nested_info = _resolve_subtask_id(subtask_id, context)
493
+ if idx < 0 or idx >= len(st["tasks"]):
494
+ return "_Invalid subtask identifier._"
495
+
496
+ # If it's a nested subtask, get its nested tasks
497
+ if nested_info is not None:
498
+ target_task = nested_info['nested_task']
499
+ source_desc = f"nested subtasks from '{target_task['label']}' (within '{nested_info['parent_task']['label']}')"
500
+ else:
501
+ target_task = st["tasks"][idx]
502
+ source_desc = f"nested subtasks from '{target_task['label']}'"
503
+
504
+ print("Parsing nested subtasks from:", subtask_id)
505
+ nested_tasks = _parse(target_task["body"])
506
+
507
+ result = []
508
+ for i, task in enumerate(nested_tasks):
509
+ result.append({
510
+ "index": i,
511
+ "label": task["label"],
512
+ "body": task["body"],
513
+ "done": task["done"]
514
+ })
515
+
516
+ return {
517
+ "source": source_desc,
518
+ "parent_task": {
519
+ "index": idx,
520
+ "label": target_task["label"],
521
+ "done": target_task["done"]
522
+ },
523
+ "subtasks": result
524
+ }
525
+
526
+
527
+ @command()
528
+ async def delegate_subtask(subtask_id, details: str, agent=None, context=None):
529
+ """
530
+ Delegate a subtask to an agent, automatically passing the subtask body as
531
+ instructions, along with any details you add.
532
+ Now supports both top-level and nested subtasks.
533
+
534
+ IMPORTANT: You can only delegate ONE task a time.
535
+ You must wait for this task delegation to complete before issuing
536
+ more delegate_subtask commands.
537
+
538
+ If agent is not specified, the current agent name will be used for the subtask.
539
+
540
+ IMPORTANT: Subtask ID may only contain alphanumerics; all other special characters are invalid.
541
+
542
+ Example:
543
+ { "delegate_subtask": { "subtask_id": "Research",
544
+ "details": "Session data in /data/sess_1234/" }}
545
+ { "delegate_subtask": { "subtask_id": "USP",
546
+ "details": "Focus on unique selling proposition analysis" }}
547
+
548
+ Note that you do not need to repeat the text of the subtask item from the checklist
549
+ in your details.
550
+ """
551
+ st = _state(context)
552
+ if not st["tasks"]:
553
+ try:
554
+ print("Loading checklist from instructions...")
555
+ print("Agent is")
556
+ print(context.agent)
557
+ instructions = context.agent["instructions"]
558
+ await load_checklist_from_instructions(instructions, context)
559
+ except Exception as e:
560
+ print(f"Error loading checklist: {e}")
561
+ trace = traceback.format_exc()
562
+ print(trace)
563
+ return "_No checklist found. Make sure to include a checklist in your instructions._"
564
+
565
+ idx, nested_info = _resolve_subtask_id(subtask_id, context)
566
+ if idx < 0 or idx >= len(st["tasks"]):
567
+ return "_Invalid subtask identifier._"
568
+
569
+ # Get the appropriate task body for delegation
570
+ if nested_info is not None:
571
+ # Delegating a nested subtask
572
+ current_task = nested_info['nested_task']
573
+ task_context = f"nested subtask '{current_task['label']}' within parent task '{nested_info['parent_task']['label']}'"
574
+ else:
575
+ # Delegating a top-level subtask
576
+ current_task = st["tasks"][idx]
577
+ task_context = f"subtask '{current_task['label']}'"
578
+
579
+ subtask_body = current_task["body"]
580
+
581
+ reminder = f"""Important: you may see system instructions for the full process. However, you are to ONLY
582
+ do (or delegate) the specified part of the process and then return a task result. If you have a sub-checklist assigned,
583
+ use delegate_subtask as needed for complex checklist items or per user instructions.
584
+
585
+ You are working on {task_context}."""
586
+
587
+ instructions = f"You are working as part of a multi-step process. Please complete the following subtask:\n\n{subtask_body}\n\n{details}\n\n{reminder}\n"
588
+
589
+ if agent is None:
590
+ agent_name = context.agent["name"]
591
+ else:
592
+ agent_name = agent
593
+
594
+ return await command_manager.delegate_task(instructions, agent_name, context=context)
595
+