Compare commits
1 Commits
gemini/for
...
gemini/pas
| Author | SHA1 | Date | |
|---|---|---|---|
| fe05c03283 |
@@ -353,3 +353,11 @@ cp ~/.hermes/sessions/sessions.json ~/.hermes/sessions/sessions.json.bak.$(date
|
||||
4. Keep docs-only PRs and script-import PRs on clean branches from `origin/main`; do not mix them with unrelated local history.
|
||||
|
||||
Until those are reconciled, trust this inventory over older prose.
|
||||
|
||||
### Memory & Audit Capabilities (Added 2026-04-06)
|
||||
|
||||
| Capability | Task/Helper | Purpose | State Carrier |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **Continuity Flush** | `flush_continuity` | Pre-compaction session state persistence. | `~/.timmy/continuity/active.md` |
|
||||
| **Sovereign Audit** | `audit_log` | Automated action logging with confidence signaling. | `~/.timmy/logs/audit.jsonl` |
|
||||
| **Fallback Routing** | `get_model_for_task` | Dynamic model selection based on portfolio doctrine. | `fallback-portfolios.yaml` |
|
||||
|
||||
@@ -19,7 +19,6 @@ import os
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
import urllib.parse
|
||||
import time
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
@@ -212,53 +211,37 @@ class GiteaClient:
|
||||
|
||||
# -- HTTP layer ----------------------------------------------------------
|
||||
|
||||
|
||||
def _request(
|
||||
self,
|
||||
method: str,
|
||||
path: str,
|
||||
data: Optional[dict] = None,
|
||||
params: Optional[dict] = None,
|
||||
retries: int = 3,
|
||||
backoff: float = 1.5,
|
||||
) -> Any:
|
||||
"""Make an authenticated API request with exponential backoff retries."""
|
||||
"""Make an authenticated API request. Returns parsed JSON."""
|
||||
url = f"{self.api}{path}"
|
||||
if params:
|
||||
url += "?" + urllib.parse.urlencode(params)
|
||||
|
||||
body = json.dumps(data).encode() if data else None
|
||||
|
||||
for attempt in range(retries):
|
||||
req = urllib.request.Request(url, data=body, method=method)
|
||||
req.add_header("Authorization", f"token {self.token}")
|
||||
req.add_header("Content-Type", "application/json")
|
||||
req.add_header("Accept", "application/json")
|
||||
req = urllib.request.Request(url, data=body, method=method)
|
||||
req.add_header("Authorization", f"token {self.token}")
|
||||
req.add_header("Content-Type", "application/json")
|
||||
req.add_header("Accept", "application/json")
|
||||
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=30) as resp:
|
||||
raw = resp.read().decode()
|
||||
if not raw:
|
||||
return {}
|
||||
return json.loads(raw)
|
||||
except urllib.error.HTTPError as e:
|
||||
body_text = ""
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=30) as resp:
|
||||
raw = resp.read().decode()
|
||||
if not raw:
|
||||
return {}
|
||||
return json.loads(raw)
|
||||
except urllib.error.HTTPError as e:
|
||||
# Don't retry client errors (4xx) except 429
|
||||
if 400 <= e.code < 500 and e.code != 429:
|
||||
body_text = ""
|
||||
try:
|
||||
body_text = e.read().decode()
|
||||
except Exception:
|
||||
pass
|
||||
raise GiteaError(e.code, body_text, url) from e
|
||||
|
||||
if attempt == retries - 1:
|
||||
raise GiteaError(e.code, str(e), url) from e
|
||||
|
||||
time.sleep(backoff ** attempt)
|
||||
except (urllib.error.URLError, TimeoutError) as e:
|
||||
if attempt == retries - 1:
|
||||
raise GiteaError(500, str(e), url) from e
|
||||
time.sleep(backoff ** attempt)
|
||||
body_text = e.read().decode()
|
||||
except Exception:
|
||||
pass
|
||||
raise GiteaError(e.code, body_text, url) from e
|
||||
|
||||
def _get(self, path: str, **params) -> Any:
|
||||
# Filter out None values
|
||||
|
||||
Reference in New Issue
Block a user