Skip to content

[RAR] CREATE agent @kody-w/thread_tracker_agent #657

Description

@kody-w
{
  "schema": "rar-change-request/1.0",
  "request_id": "req_17281478c9e845cbb478c5554ce0cb60",
  "idempotency_key": "req_17281478c9e845cbb478c5554ce0cb60",
  "operation": "create",
  "resource": {
    "kind": "agent",
    "id": "@kody-w/thread_tracker_agent"
  },
  "preconditions": {
    "if_none_match": "*"
  },
  "payload": {
    "source": {
      "media_type": "text/x-python",
      "encoding": "utf-8",
      "sha256": "sha256:dcf4d630cab0eaa9a6919e052cb14429416a1607f4e581a397a58430c7f8ad98",
      "content": "\"\"\"Thread Tracker \u2014 local append-only topic routing that keeps work from getting lost.\"\"\"\n\n__manifest__ = {\n    \"schema\": \"rapp-agent/1.0\",\n    \"name\": \"@kody-w/thread_tracker_agent\",\n    \"version\": \"1.0.0\",\n    \"display_name\": \"Thread Tracker\",\n    \"description\": \"Routes remarks into durable local topic threads, lists open work, and parks or closes threads without deleting their history.\",\n    \"author\": \"kody-w\",\n    \"tags\": [\"threads\", \"notes\", \"routing\", \"append-only\", \"offline\"],\n    \"category\": \"productivity\",\n    \"quality_tier\": \"community\",\n    \"requires_env\": [],\n    \"dependencies\": [\"@rapp/basic_agent\"],\n}\n\nfrom collections import Counter\nfrom datetime import datetime, timezone\nimport hashlib\nimport json\nimport os\nfrom pathlib import Path\nimport re\nimport threading\nimport uuid\n\ntry:\n    from agents.basic_agent import BasicAgent\nexcept ImportError:\n    try:\n        from basic_agent import BasicAgent\n    except ImportError:\n        class BasicAgent:\n            def __init__(self, name=None, metadata=None):\n                if name is not None:\n                    self.name = name\n                if metadata is not None:\n                    self.metadata = metadata\n\n            def perform(self, **kwargs):\n                return \"Not implemented.\"\n\n\n_LOCK = threading.RLock()\n_WORDS = re.compile(r\"[a-z0-9][a-z0-9_-]{1,}\")\n_STOP = {\n    \"about\", \"after\", \"again\", \"also\", \"been\", \"being\", \"from\", \"have\",\n    \"into\", \"just\", \"more\", \"that\", \"their\", \"then\", \"this\", \"what\", \"when\",\n    \"where\", \"which\", \"with\", \"would\", \"your\",\n}\n\n\ndef _store():\n    configured = os.environ.get(\"RAPP_THREAD_STORE\")\n    if configured:\n        return Path(configured).expanduser()\n    return Path.home() / \".rapp\" / \"agent_data\" / \"thread_tracker.jsonl\"\n\n\ndef _now():\n    return datetime.now(timezone.utc).isoformat(timespec=\"seconds\")\n\n\ndef _terms(text):\n    return {\n        word for word in _WORDS.findall(text.casefold())\n        if word not in _STOP\n    }\n\n\ndef _load():\n    path = _store()\n    if not path.exists():\n        return []\n    events = []\n    previous = \"\"\n    with path.open(encoding=\"utf-8\") as handle:\n        for number, line in enumerate(handle, 1):\n            event = json.loads(line)\n            payload = {key: value for key, value in event.items() if key != \"hash\"}\n            expected = hashlib.sha256(\n                json.dumps(payload, sort_keys=True, separators=(\",\", \":\")).encode()\n            ).hexdigest()\n            if event.get(\"previous\") != previous or event.get(\"hash\") != expected:\n                raise ValueError(f\"thread record is corrupt at line {number}\")\n            events.append(event)\n            previous = event[\"hash\"]\n    return events\n\n\ndef _append(kind, payload):\n    with _LOCK:\n        events = _load()\n        path = _store()\n        path.parent.mkdir(mode=0o700, parents=True, exist_ok=True)\n        if os.name != \"nt\":\n            path.parent.chmod(0o700)\n        event = {\n            \"utc\": _now(),\n            \"kind\": kind,\n            \"payload\": payload,\n            \"previous\": events[-1][\"hash\"] if events else \"\",\n        }\n        event[\"hash\"] = hashlib.sha256(\n            json.dumps(event, sort_keys=True, separators=(\",\", \":\")).encode()\n        ).hexdigest()\n        with path.open(\"a\", encoding=\"utf-8\") as handle:\n            handle.write(json.dumps(event, sort_keys=True) + \"\\n\")\n        if os.name != \"nt\":\n            path.chmod(0o600)\n        return event\n\n\ndef _threads():\n    threads = {}\n    for event in _load():\n        payload = event[\"payload\"]\n        identifier = payload.get(\"thread\")\n        if not identifier:\n            continue\n        item = threads.setdefault(identifier, {\n            \"thread\": identifier,\n            \"topic\": \"\",\n            \"notes\": [],\n            \"state\": \"open\",\n            \"opened\": event[\"utc\"],\n            \"touched\": event[\"utc\"],\n            \"terms\": set(),\n        })\n        item[\"touched\"] = event[\"utc\"]\n        if event[\"kind\"] == \"thread.opened\":\n            item[\"topic\"] = payload[\"topic\"]\n            item[\"terms\"].update(payload.get(\"terms\", []))\n        elif event[\"kind\"] == \"thread.note\":\n            item[\"notes\"].append(payload[\"note\"])\n            item[\"terms\"].update(payload.get(\"terms\", []))\n        elif event[\"kind\"] == \"thread.closed\":\n            item[\"state\"] = \"closed\"\n            item[\"reason\"] = payload.get(\"reason\", \"\")\n        elif event[\"kind\"] == \"thread.parked\":\n            item[\"state\"] = \"parked\"\n    return threads\n\n\ndef _best_match(terms, threads, floor=2):\n    candidates = []\n    for item in threads.values():\n        if item[\"state\"] == \"closed\":\n            continue\n        score = len(terms & item[\"terms\"])\n        candidates.append((score, item[\"touched\"], item[\"thread\"], item))\n    if not candidates:\n        return None, 0\n    score, _, _, item = max(candidates)\n    return (item, score) if score >= floor else (None, score)\n\n\nclass ThreadTrackerAgent(BasicAgent):\n    def __init__(self):\n        self.name = \"ThreadTracker\"\n        self.metadata = {\n            \"name\": self.name,\n            \"display_name\": __manifest__[\"display_name\"],\n            \"description\": __manifest__[\"description\"],\n            \"parameters\": {\n                \"type\": \"object\",\n                \"properties\": {\n                    \"action\": {\n                        \"type\": \"string\",\n                        \"enum\": [\n                            \"place\", \"open\", \"list\", \"topics\",\n                            \"close\", \"park\", \"show\",\n                        ],\n                    },\n                    \"text\": {\"type\": \"string\"},\n                    \"thread\": {\"type\": \"string\"},\n                    \"reason\": {\"type\": \"string\"},\n                },\n                \"required\": [\"action\"],\n            },\n        }\n        super().__init__(self.name, self.metadata)\n\n    def perform(self, **kwargs) -> str:\n        action = str(kwargs.get(\"action\") or \"list\").strip().lower()\n        threads = _threads()\n        text = str(kwargs.get(\"text\") or \"\").strip()\n        if action in (\"place\", \"open\"):\n            if not text:\n                return \"Provide a remark or topic.\"\n            terms = _terms(text)\n            match, score = (None, 0) if action == \"open\" else _best_match(\n                terms, threads\n            )\n            if match:\n                _append(\"thread.note\", {\n                    \"thread\": match[\"thread\"],\n                    \"note\": text[:1000],\n                    \"terms\": sorted(terms),\n                })\n                return (\n                    f\"Placed on thread {match['thread']} \"\n                    f\"({score} shared terms): {match['topic'][:100]}\"\n                )\n            identifier = uuid.uuid4().hex[:10]\n            _append(\"thread.opened\", {\n                \"thread\": identifier,\n                \"topic\": text[:500],\n                \"terms\": sorted(terms),\n            })\n            return f\"Opened thread {identifier}: {text[:120]}\"\n        if action in (\"close\", \"park\"):\n            identifier = str(kwargs.get(\"thread\") or \"\").strip()\n            if identifier not in threads:\n                return f\"No thread {identifier}.\"\n            _append(\n                \"thread.closed\" if action == \"close\" else \"thread.parked\",\n                {\n                    \"thread\": identifier,\n                    \"reason\": str(kwargs.get(\"reason\") or \"\")[:500],\n                },\n            )\n            return f\"Thread {identifier} {action}d. History was preserved.\"\n        if action == \"show\":\n            identifier = str(kwargs.get(\"thread\") or \"\").strip()\n            item = threads.get(identifier)\n            if not item:\n                return f\"No thread {identifier}.\"\n            safe = {**item, \"terms\": sorted(item[\"terms\"])}\n            return json.dumps(safe, indent=2, sort_keys=True)\n        if action == \"topics\":\n            if not threads:\n                return \"Nothing tracked yet.\"\n            latest_day = max(item[\"touched\"][:10] for item in threads.values())\n            items = [\n                item for item in threads.values()\n                if item[\"touched\"][:10] == latest_day\n            ]\n            counts = Counter()\n            for item in items:\n                counts.update(item[\"terms\"])\n            lines = [f\"Covered on {latest_day}:\"]\n            lines.extend(\n                f\"[{item['state']}] {item['thread']} {item['topic'][:100]}\"\n                for item in sorted(items, key=lambda value: value[\"touched\"])\n            )\n            recurring = [\n                term for term, count in counts.most_common(8) if count > 1\n            ]\n            if recurring:\n                lines.append(\"Recurring terms: \" + \", \".join(recurring))\n            return \"\\n\".join(lines)\n        active = [\n            item for item in threads.values() if item[\"state\"] != \"closed\"\n        ]\n        if not active:\n            return \"No open threads.\"\n        return \"\\n\".join(\n            f\"{item['thread']} [{item['state']}] \"\n            f\"{len(item['notes'])} note(s): {item['topic'][:100]}\"\n            for item in sorted(active, key=lambda value: value[\"touched\"])\n        )\n\n\nif __name__ == \"__main__\":\n    print(ThreadTrackerAgent().perform(action=\"list\"))\n"
    }
  },
  "client": {
    "name": "rapp_sdk",
    "version": "1.1.0"
  }
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions