Ctrl K
ComunidadGuías…

butler/tools/session_todos_tools.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"""Agent tools for session-scoped todo lists (OpenCode todowrite subset)."""

from __future__ import annotations

import json
from typing import Any, Callable, cast


def _session_key() -> str:
    from butler.tools.session_todos_tools_ops import current_session_key_safe

    return cast(str, current_session_key_safe())


def _tool_session_todos_list(**_: Any) -> str:
    from butler.core.session_todos import load_session_todos, session_todos_enabled

    if not session_todos_enabled():
        return json.dumps({"ok": False, "error": "BUTLER_SESSION_TODOS=0"})
    sk = _session_key()
    items = load_session_todos(sk)
    open_count = sum(
        1 for t in items if str(t.get("status") or "") in ("pending", "in_progress")
    )
    return json.dumps({
        "ok": True,
        "session_key": sk,
        "count": len(items),
        "open_count": open_count,
        "items": items,
        "hint": "用 session_todos_write 提交完整列表,或 merge=true 按 id 局部更新",
    }, ensure_ascii=False)


def _tool_session_todos_write(
    items: list[Any] | None = None,
    merge: bool = False,
    **_: Any,
) -> str:
    from butler.core.session_todos import (
        merge_session_todos,
        replace_session_todos,
        session_todos_enabled,
    )

    if not session_todos_enabled():
        return json.dumps({"ok": False, "error": "BUTLER_SESSION_TODOS=0"})
    if not isinstance(items, list):
        return json.dumps({"ok": False, "error": "items must be an array"})
    sk = _session_key()
    if merge:
        result = merge_session_todos(sk, items)
    else:
        result = replace_session_todos(sk, items)
    if result.get("skipped"):
        return json.dumps({"ok": False, **result})
    if not result.get("ok", True):
        return json.dumps({"ok": False, **result})
    return json.dumps({
        "ok": True,
        "session_key": sk,
        "count": result.get("count", 0),
        "mode": "merge" if merge else "replace",
        "wechat": "主公可发 /待办 查看",
    }, ensure_ascii=False)


def register_session_todos_tools(register: Callable[..., None]) -> None:
    register(
        name="session_todos_list",
        description=(
            "List the current session todo checklist (WeChat session scope). "
            "Use before session_todos_write to see open items."
        ),
        schema={"type": "object", "properties": {}},
        handler=_tool_session_todos_list,
        toolset="planning",
    )
    register(
        name="session_todos_write",
        description=(
            "【ephemeral·WeChat session】Replace or merge the in-memory session checklist "
            "(OpenCode todowrite style). merge=true updates by id. Cleared on /new."
        ),
        schema={
            "type": "object",
            "properties": {
                "items": {
                    "type": "array",
                    "description": "Todo rows: {id?, content, status?}",
                    "items": {
                        "type": "object",
                        "properties": {
                            "id": {"type": "string"},
                            "content": {"type": "string"},
                            "status": {
                                "type": "string",
                                "enum": [
                                    "pending",
                                    "in_progress",
                                    "completed",
                                    "cancelled",
                                ],
                            },
                        },
                        "required": ["content"],
                    },
                },
                "merge": {
                    "type": "boolean",
                    "description": "If true, merge by id into existing todos instead of replace-all",
                    "default": False,
                },
            },
            "required": ["items"],
        },
        handler=_tool_session_todos_write,
        toolset="planning",
    )