mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-08 22:20:54 +08:00
- Add SQLAlchemy Core repos, pg adapter/compat, assistant_store factory, Alembic bootstrap and migration/cutover scripts. - Harden chat_message writes (NUL scrub for PG), turn_uuid on attempt failure, WS turn_runner fallbacks and gateway executed_turn_uuid init. - start_gateway: log paths, PS7 stderr handling via cmd, background stdout/stderr redirect; runtime assistant_runtime_log_dir export. - Ops: clear_all_chat_sessions with PG-only --postgresql and env-gated wipe; clear_postgres_chat_sessions.ps1. - Tests: SA repos, pg compat, persist fallback, smoke env isolation; CI and docs touch-ups. Co-authored-by: Cursor <cursoragent@cursor.com>
147 lines
5.6 KiB
Python
147 lines
5.6 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from svc.config.paths import db_path
|
|
from svc.persistence.sqlite_store import SqliteStore
|
|
from svc.persistence.assistant_store import get_assistant_store
|
|
from runtime.tools.base import ToolSpec
|
|
|
|
|
|
def _require(s: str, name: str) -> str:
|
|
v = (s or "").strip()
|
|
if not v:
|
|
raise ValueError(f"{name} is required")
|
|
return v
|
|
|
|
|
|
def todo_create_tool() -> ToolSpec:
|
|
def handler(args: dict[str, Any]) -> dict[str, Any]:
|
|
try:
|
|
tenant_id = _require(str(args.get("tenant_id") or ""), "tenant_id")
|
|
owner_user_id = _require(str(args.get("owner_user_id") or ""), "owner_user_id")
|
|
title = _require(str(args.get("title") or ""), "title")
|
|
due_at = str(args.get("due_at") or "").strip() or None
|
|
assignee_user_id = str(args.get("assignee_user_id") or "").strip() or None
|
|
store = get_assistant_store()
|
|
row = store.todo_create(
|
|
tenant_id=tenant_id,
|
|
owner_user_id=owner_user_id,
|
|
title=title,
|
|
due_at=due_at,
|
|
assignee_user_id=assignee_user_id,
|
|
)
|
|
return {"ok": True, "todo": row}
|
|
except Exception as e:
|
|
return {"ok": False, "error": f"{type(e).__name__}: {e}"}
|
|
|
|
return ToolSpec(
|
|
name="todo_create",
|
|
description="Create a todo item for a tenant/user.",
|
|
parameters={
|
|
"type": "object",
|
|
"properties": {
|
|
"tenant_id": {"type": "string"},
|
|
"owner_user_id": {"type": "string"},
|
|
"title": {"type": "string"},
|
|
"due_at": {"type": "string", "description": "Optional ISO timestamp or natural text."},
|
|
"assignee_user_id": {"type": "string", "description": "Optional user id to assign."},
|
|
},
|
|
"required": ["tenant_id", "owner_user_id", "title"],
|
|
"additionalProperties": False,
|
|
},
|
|
handler=handler,
|
|
tags=frozenset({"productivity", "write"}),
|
|
)
|
|
|
|
|
|
def todo_list_tool() -> ToolSpec:
|
|
def handler(args: dict[str, Any]) -> dict[str, Any]:
|
|
try:
|
|
tenant_id = _require(str(args.get("tenant_id") or ""), "tenant_id")
|
|
assignee_user_id = str(args.get("assignee_user_id") or "").strip() or None
|
|
status = str(args.get("status") or "open").strip() or None
|
|
limit = int(args.get("limit") or 50)
|
|
store = get_assistant_store()
|
|
rows = store.todo_list(
|
|
tenant_id=tenant_id,
|
|
assignee_user_id=assignee_user_id,
|
|
status=status,
|
|
limit=limit,
|
|
)
|
|
return {"ok": True, "items": rows}
|
|
except Exception as e:
|
|
return {"ok": False, "error": f"{type(e).__name__}: {e}"}
|
|
|
|
return ToolSpec(
|
|
name="todo_list",
|
|
description="List todo items by tenant (optionally by assignee and status).",
|
|
parameters={
|
|
"type": "object",
|
|
"properties": {
|
|
"tenant_id": {"type": "string"},
|
|
"assignee_user_id": {"type": "string"},
|
|
"status": {"type": "string", "default": "open"},
|
|
"limit": {"type": "integer", "default": 50},
|
|
},
|
|
"required": ["tenant_id"],
|
|
"additionalProperties": False,
|
|
},
|
|
handler=handler,
|
|
tags=frozenset({"productivity"}),
|
|
)
|
|
|
|
|
|
def todo_done_tool() -> ToolSpec:
|
|
def handler(args: dict[str, Any]) -> dict[str, Any]:
|
|
try:
|
|
tenant_id = _require(str(args.get("tenant_id") or ""), "tenant_id")
|
|
todo_id = _require(str(args.get("todo_id") or ""), "todo_id")
|
|
store = get_assistant_store()
|
|
ok = store.todo_set_status(tenant_id=tenant_id, todo_id=todo_id, status="done")
|
|
return {"ok": bool(ok), "todo_id": todo_id}
|
|
except Exception as e:
|
|
return {"ok": False, "error": f"{type(e).__name__}: {e}"}
|
|
|
|
return ToolSpec(
|
|
name="todo_done",
|
|
description="Mark a todo item as done.",
|
|
parameters={
|
|
"type": "object",
|
|
"properties": {"tenant_id": {"type": "string"}, "todo_id": {"type": "string"}},
|
|
"required": ["tenant_id", "todo_id"],
|
|
"additionalProperties": False,
|
|
},
|
|
handler=handler,
|
|
tags=frozenset({"productivity", "write"}),
|
|
)
|
|
|
|
|
|
def todo_assign_tool() -> ToolSpec:
|
|
def handler(args: dict[str, Any]) -> dict[str, Any]:
|
|
try:
|
|
tenant_id = _require(str(args.get("tenant_id") or ""), "tenant_id")
|
|
todo_id = _require(str(args.get("todo_id") or ""), "todo_id")
|
|
assignee_user_id = _require(str(args.get("assignee_user_id") or ""), "assignee_user_id")
|
|
store = get_assistant_store()
|
|
ok = store.todo_assign(tenant_id=tenant_id, todo_id=todo_id, assignee_user_id=assignee_user_id)
|
|
return {"ok": bool(ok), "todo_id": todo_id, "assignee_user_id": assignee_user_id}
|
|
except Exception as e:
|
|
return {"ok": False, "error": f"{type(e).__name__}: {e}"}
|
|
|
|
return ToolSpec(
|
|
name="todo_assign",
|
|
description="Assign a todo item to a user.",
|
|
parameters={
|
|
"type": "object",
|
|
"properties": {"tenant_id": {"type": "string"}, "todo_id": {"type": "string"}, "assignee_user_id": {"type": "string"}},
|
|
"required": ["tenant_id", "todo_id", "assignee_user_id"],
|
|
"additionalProperties": False,
|
|
},
|
|
handler=handler,
|
|
tags=frozenset({"productivity", "write"}),
|
|
)
|
|
|
|
|
|
__all__ = ["todo_create_tool", "todo_list_tool", "todo_done_tool", "todo_assign_tool"]
|
|
|