PlanOpticon
| 0981a08… | noreply | 1 | """Skill: Break down goals into tasks with dependencies.""" |
| 0981a08… | noreply | 2 | |
| 0981a08… | noreply | 3 | from video_processor.agent.skills.base import ( |
| 0981a08… | noreply | 4 | AgentContext, |
| 0981a08… | noreply | 5 | Artifact, |
| 0981a08… | noreply | 6 | Skill, |
| 0981a08… | noreply | 7 | register_skill, |
| 0981a08… | noreply | 8 | ) |
| 0981a08… | noreply | 9 | from video_processor.utils.json_parsing import parse_json_from_response |
| 0981a08… | noreply | 10 | |
| 0981a08… | noreply | 11 | |
| 0981a08… | noreply | 12 | class TaskBreakdownSkill(Skill): |
| 0981a08… | noreply | 13 | name = "task_breakdown" |
| 0981a08… | noreply | 14 | description = "Break down goals into tasks with dependencies" |
| 0981a08… | noreply | 15 | |
| 0981a08… | noreply | 16 | def execute(self, context: AgentContext, **kwargs) -> Artifact: |
| 0981a08… | noreply | 17 | stats = context.query_engine.stats() |
| 0981a08… | noreply | 18 | entities = context.query_engine.entities() |
| 0981a08… | noreply | 19 | relationships = context.query_engine.relationships() |
| 0981a08… | noreply | 20 | |
| 0981a08… | noreply | 21 | task_types = {"goal", "feature", "milestone"} |
| 0981a08… | noreply | 22 | relevant = [ |
| 0981a08… | noreply | 23 | e for e in context.planning_entities if getattr(e, "type", "").lower() in task_types |
| 0981a08… | noreply | 24 | ] |
| 0981a08… | noreply | 25 | |
| 0981a08… | noreply | 26 | parts = [ |
| 0981a08… | noreply | 27 | "You are a project manager. Using the following knowledge " |
| 0981a08… | noreply | 28 | "graph context, decompose goals and features into tasks.", |
| 0981a08… | noreply | 29 | "", |
| 0981a08… | noreply | 30 | "## Knowledge Graph Overview", |
| 0981a08… | noreply | 31 | stats.to_text(), |
| 0981a08… | noreply | 32 | "", |
| 0981a08… | noreply | 33 | "## Entities", |
| 0981a08… | noreply | 34 | entities.to_text(), |
| 0981a08… | noreply | 35 | "", |
| 0981a08… | noreply | 36 | "## Relationships", |
| 0981a08… | noreply | 37 | relationships.to_text(), |
| 0981a08… | noreply | 38 | "", |
| 0981a08… | noreply | 39 | "## Goals, Features & Milestones", |
| 0981a08… | noreply | 40 | ] |
| 0981a08… | noreply | 41 | for e in relevant: |
| 0981a08… | noreply | 42 | parts.append(f"- [{getattr(e, 'type', 'unknown')}] {e}") |
| 0981a08… | noreply | 43 | |
| 0981a08… | noreply | 44 | if not relevant: |
| 0981a08… | noreply | 45 | parts.append("(No pre-filtered entities; derive tasks from the full context above.)") |
| 0981a08… | noreply | 46 | |
| 0981a08… | noreply | 47 | parts.append( |
| 0981a08… | noreply | 48 | "\nReturn a JSON array of task objects with:\n" |
| 0981a08… | noreply | 49 | '- "id": string (e.g. "T1", "T2")\n' |
| 0981a08… | noreply | 50 | '- "title": string\n' |
| 0981a08… | noreply | 51 | '- "description": string\n' |
| 0981a08… | noreply | 52 | '- "depends_on": list of task id strings\n' |
| 0981a08… | noreply | 53 | '- "priority": "high" | "medium" | "low"\n' |
| 0981a08… | noreply | 54 | '- "estimate": string (e.g. "2d", "1w")\n' |
| 0981a08… | noreply | 55 | '- "assignee_role": string\n\n' |
| 0981a08… | noreply | 56 | "Return ONLY the JSON." |
| 0981a08… | noreply | 57 | ) |
| 0981a08… | noreply | 58 | |
| 0981a08… | noreply | 59 | prompt = "\n".join(parts) |
| 0981a08… | noreply | 60 | response = context.provider_manager.chat(messages=[{"role": "user", "content": prompt}]) |
| 0981a08… | noreply | 61 | parsed = parse_json_from_response(response) |
| 0981a08… | noreply | 62 | |
| 0981a08… | noreply | 63 | import json |
| 0981a08… | noreply | 64 | |
| 0981a08… | noreply | 65 | content = json.dumps(parsed, indent=2) if isinstance(parsed, list) else response |
| 0981a08… | noreply | 66 | |
| 0981a08… | noreply | 67 | return Artifact( |
| 0981a08… | noreply | 68 | name="Task Breakdown", |
| 0981a08… | noreply | 69 | content=content, |
| 0981a08… | noreply | 70 | artifact_type="task_list", |
| 0981a08… | noreply | 71 | format="json", |
| 0981a08… | noreply | 72 | metadata={"tasks": parsed if isinstance(parsed, list) else []}, |
| 0981a08… | noreply | 73 | ) |
| 0981a08… | noreply | 74 | |
| 0981a08… | noreply | 75 | |
| 0981a08… | noreply | 76 | register_skill(TaskBreakdownSkill()) |