feat: reminders_add and reminders_list tools

- New cortex/tools/reminders.py with reminders_add, reminders_list, reminders_clear
- reminders_clear moved here from cron.py (cron still imports from same file)
- __init__.py: wired up new callables and Gemini declarations
- Inara can now add/read reminders in Agent mode via the orchestrator

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-03-29 21:14:22 -04:00
parent 6b725afc3e
commit e5b6d58889
2 changed files with 111 additions and 0 deletions

View File

@@ -28,6 +28,10 @@ from tools.cron import (
cron_add as _cron_add,
cron_remove as _cron_remove,
cron_toggle as _cron_toggle,
)
from tools.reminders import (
reminders_add as _reminders_add,
reminders_list as _reminders_list,
reminders_clear as _reminders_clear,
)
from tools.scratch import (
@@ -196,6 +200,8 @@ _CALLABLES: dict[str, callable] = {
"cron_add": _cron_add,
"cron_remove": _cron_remove,
"cron_toggle": _cron_toggle,
"reminders_add": _reminders_add,
"reminders_list": _reminders_list,
"reminders_clear": _reminders_clear,
"scratch_read": _scratch_read,
"scratch_write": _scratch_write,
@@ -409,6 +415,40 @@ _cron_toggle_declaration = types.FunctionDeclaration(
),
)
_reminders_add_declaration = types.FunctionDeclaration(
name="reminders_add",
description=(
"Add a new reminder to REMINDERS.md. Reminders are automatically surfaced "
"in your context at the start of each session (Tier 2+). "
"Use this when the user asks you to remember something, follow up on something, "
"or surface a note at the next session."
),
parameters=types.Schema(
type=types.Type.OBJECT,
properties={
"text": types.Schema(
type=types.Type.STRING,
description="The reminder text to add",
),
"label": types.Schema(
type=types.Type.STRING,
description="Optional heading for this reminder (e.g. 'Follow up on NC Talk'). Defaults to current timestamp.",
),
},
required=["text"],
),
)
_reminders_list_declaration = types.FunctionDeclaration(
name="reminders_list",
description=(
"Read all current pending reminders from REMINDERS.md. "
"Use this to check what reminders are queued before adding duplicates, "
"or to show the user what's pending."
),
parameters=types.Schema(type=types.Type.OBJECT, properties={}),
)
_reminders_clear_declaration = types.FunctionDeclaration(
name="reminders_clear",
description=(
@@ -494,6 +534,8 @@ TOOL_DECLARATIONS = [
_cron_add_declaration,
_cron_remove_declaration,
_cron_toggle_declaration,
_reminders_add_declaration,
_reminders_list_declaration,
_reminders_clear_declaration,
_scratch_read_declaration,
_scratch_write_declaration,

69
cortex/tools/reminders.py Normal file
View File

@@ -0,0 +1,69 @@
"""
Reminders tools.
Reminders are stored in persona/REMINDERS.md and automatically surfaced
in the system prompt at Tier 2+. Use these tools to add, list, and clear
pending reminders.
Operations:
reminders_add — append a new reminder entry
reminders_list — return all current reminders (or a message if empty)
reminders_clear — erase all reminders (moved here from cron.py for consistency;
cron.py still calls the same underlying file)
"""
import asyncio
from datetime import datetime, timezone
from pathlib import Path
from persona import persona_path
def _reminders_path() -> Path:
return persona_path() / "REMINDERS.md"
def _now_label() -> str:
return datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M UTC")
# ---------------------------------------------------------------------------
# Sync implementations
# ---------------------------------------------------------------------------
def _reminders_list() -> str:
p = _reminders_path()
if not p.exists() or not p.read_text().strip():
return "No pending reminders."
return p.read_text()
def _reminders_add(text: str, label: str | None = None) -> str:
p = _reminders_path()
existing = p.read_text() if p.exists() else ""
heading = label or _now_label()
section = f"\n## {heading}\n\n{text.strip()}\n"
p.write_text(existing.rstrip() + "\n" + section)
return f"Reminder added: {heading}"
def _reminders_clear() -> str:
p = _reminders_path()
p.write_text("")
return "All reminders cleared."
# ---------------------------------------------------------------------------
# Async wrappers
# ---------------------------------------------------------------------------
async def reminders_list() -> str:
return await asyncio.to_thread(_reminders_list)
async def reminders_add(text: str, label: str | None = None) -> str:
return await asyncio.to_thread(_reminders_add, text, label)
async def reminders_clear() -> str:
return await asyncio.to_thread(_reminders_clear)