| from __future__ import annotations |
| from src.game_state import get_state |
|
|
| TOOL_SCHEMAS = [ |
| { |
| "type": "function", |
| "function": { |
| "name": "start_timer", |
| "description": ( |
| "Start the user's focus timer. Use this when they want to begin a work " |
| "session, Pomodoro, or free-flow focus block." |
| ), |
| "parameters": { |
| "type": "object", |
| "properties": { |
| "duration_minutes": { |
| "type": "integer", |
| "description": "Duration in minutes (1-180). Ignored in freeflow mode.", |
| "default": 25, |
| }, |
| "mode": { |
| "type": "string", |
| "enum": ["pomodoro", "freeflow"], |
| "description": ( |
| "'pomodoro' counts down from duration_minutes; " |
| "'freeflow' counts up indefinitely." |
| ), |
| "default": "pomodoro", |
| }, |
| }, |
| "required": [], |
| }, |
| }, |
| }, |
| { |
| "type": "function", |
| "function": { |
| "name": "stop_timer", |
| "description": "Pause/stop the currently running timer without resetting it.", |
| "parameters": { |
| "type": "object", |
| "properties": {}, |
| "required": [], |
| }, |
| }, |
| }, |
| { |
| "type": "function", |
| "function": { |
| "name": "reset_timer", |
| "description": "Stop and reset the timer back to zero, clearing the current session.", |
| "parameters": { |
| "type": "object", |
| "properties": {}, |
| "required": [], |
| }, |
| }, |
| }, |
| { |
| "type": "function", |
| "function": { |
| "name": "add_todo", |
| "description": "Add a new task (quest) to the user's todo list.", |
| "parameters": { |
| "type": "object", |
| "properties": { |
| "task": { |
| "type": "string", |
| "description": "The task description to add.", |
| }, |
| }, |
| "required": ["task"], |
| }, |
| }, |
| }, |
| { |
| "type": "function", |
| "function": { |
| "name": "complete_todo", |
| "description": ( |
| "Mark an existing task as done. Identify it by its id (preferred, shown " |
| "as id=N in the quest list) or by matching task text." |
| ), |
| "parameters": { |
| "type": "object", |
| "properties": { |
| "todo_id": { |
| "type": "integer", |
| "description": "The id of the task to complete.", |
| }, |
| "task": { |
| "type": "string", |
| "description": "Task text to match if the id is unknown.", |
| }, |
| }, |
| "required": [], |
| }, |
| }, |
| }, |
| { |
| "type": "function", |
| "function": { |
| "name": "remove_todo", |
| "description": ( |
| "Delete a task from the list entirely. Identify it by its id (preferred) " |
| "or by matching task text." |
| ), |
| "parameters": { |
| "type": "object", |
| "properties": { |
| "todo_id": { |
| "type": "integer", |
| "description": "The id of the task to remove.", |
| }, |
| "task": { |
| "type": "string", |
| "description": "Task text to match if the id is unknown.", |
| }, |
| }, |
| "required": [], |
| }, |
| }, |
| }, |
| ] |
|
|
|
|
| def _find_todo(state, arguments: dict) -> dict | None: |
| """Resolve a todo from a tool's arguments by id (preferred) or task text.""" |
| tid = arguments.get("todo_id") |
| if tid is not None: |
| try: |
| tid = int(tid) |
| for t in state.todos: |
| if t["id"] == tid: |
| return t |
| except (ValueError, TypeError): |
| pass |
| task = (arguments.get("task") or "").strip().lower() |
| if task: |
| for t in state.todos: |
| if task in t["task"].lower(): |
| return t |
| return None |
|
|
|
|
| def execute_tool(name: str, arguments: dict) -> tuple[str, str | None]: |
| """Execute a tool by name. Returns (text_result, js_command_or_None).""" |
| state = get_state() |
|
|
| if name == "start_timer": |
| duration = max(1, min(180, int(arguments.get("duration_minutes") or 25))) |
| mode = arguments.get("mode", "pomodoro") |
| if mode not in ("pomodoro", "freeflow"): |
| mode = "pomodoro" |
| state.timer_state.update({ |
| "running": True, |
| "mode": mode, |
| "duration_minutes": duration, |
| "phase": "work", |
| }) |
| label = f"{duration}-minute {mode}" if mode == "pomodoro" else "free-flow" |
| js = f"timerStart({duration}, '{mode}')" |
| return f"Timer started: {label} session.", js |
|
|
| if name == "stop_timer": |
| state.timer_state["running"] = False |
| return "Timer stopped.", "timerStop()" |
|
|
| if name == "reset_timer": |
| state.timer_state.update({"running": False, "phase": "work"}) |
| return "Timer reset.", "timerReset()" |
|
|
| if name == "add_todo": |
| task = (arguments.get("task") or "").strip() |
| if not task: |
| return "I couldn't tell what task to add.", None |
| state.add_todo(task) |
| return f"Added quest: {task}", None |
|
|
| if name == "complete_todo": |
| t = _find_todo(state, arguments) |
| if not t: |
| return "I couldn't find that quest on your list.", None |
| if t["done"]: |
| return f"'{t['task']}' is already complete.", None |
| state.mark_done(t["id"]) |
| return f"Marked '{t['task']}' complete. +{state.XP_PER_TODO} XP! 🎉", "avatarPlay('questDone')" |
|
|
| if name == "remove_todo": |
| t = _find_todo(state, arguments) |
| if not t: |
| return "I couldn't find that quest on your list.", None |
| task = t["task"] |
| state.remove_todo(t["id"]) |
| return f"Removed quest: {task}", None |
|
|
| return f"Unknown tool: {name}", None |
|
|