diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 15370dd..632003c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,6 +47,9 @@ jobs: timeout-minutes: 10 needs: [test] if: github.event_name == 'pull_request' + permissions: + pull-requests: write + contents: read steps: - uses: actions/checkout@v4 diff --git a/src/eling/as_brain/mcp_server.py b/src/eling/as_brain/mcp_server.py index 3ae597f..f8217b1 100644 --- a/src/eling/as_brain/mcp_server.py +++ b/src/eling/as_brain/mcp_server.py @@ -468,6 +468,9 @@ def _handle_tool_call(rid: int | str | None, params: dict) -> dict: def ok(data: Any) -> dict: try: text = json.dumps(data, default=str) + # Limit response to 50KB to prevent provider context overflow + if len(text) > 50_000: + text = json.dumps({"warning": "response truncated (50KB limit)", "truncated": True}, default=str) except Exception: text = json.dumps({"error": "result not serializable", "raw": str(data)[:500]}) return { diff --git a/src/eling/layers/notion.py b/src/eling/layers/notion.py index 743ea65..1707376 100644 --- a/src/eling/layers/notion.py +++ b/src/eling/layers/notion.py @@ -47,13 +47,21 @@ def __init__( @property def available(self) -> bool: + global _HAS_HTTPX if _HAS_HTTPX is None: - _require_httpx() + try: + _require_httpx() + except RuntimeError: + _HAS_HTTPX = False return _HAS_HTTPX and bool(self.api_key) def _has_httpx(self) -> bool: + global _HAS_HTTPX if _HAS_HTTPX is None: - _require_httpx() + try: + _require_httpx() + except RuntimeError: + _HAS_HTTPX = False return bool(_HAS_HTTPX) def _get_client(self) -> "httpx.Client": diff --git a/src/eling/zero_plugin/eling-hook.py b/src/eling/zero_plugin/eling-hook.py index 2c9fe7a..2d21916 100644 --- a/src/eling/zero_plugin/eling-hook.py +++ b/src/eling/zero_plugin/eling-hook.py @@ -42,8 +42,9 @@ def handle_before_tool(payload: dict) -> str | None: try: brain = get_brain() results = brain.recall(query, limit=3) - if results: - return f"eling: recalled {len(results)} memory items for {tool}" + merged = results.get("merged", []) + if merged: + return f"eling: recalled {len(merged)} memory items for {tool}" except Exception as e: log.warning("before_tool recall failed: %s", e) return None @@ -58,6 +59,7 @@ def handle_after_tool(payload: dict) -> str | None: result = payload.get("result", "") or payload.get("output", "") msgs = [] + brain = None # Remember file edits as facts if changed_files and status in ("success", "ok", "", None): @@ -78,7 +80,8 @@ def handle_after_tool(payload: dict) -> str | None: # Remember tool results as observations if result and tool and status in ("success", "ok", "", None): try: - brain = get_brain() + if brain is None: + brain = get_brain() summary = str(result)[:300] brain.remember( f"Tool [{tool}] returned: {summary}",