chore: checkpoint local wip for issue 892

This commit is contained in:
Alexander Whitestone
2026-04-05 13:31:06 -04:00
parent f8f5d08678
commit d7abb7db36
47 changed files with 113 additions and 149 deletions

View File

@@ -1,6 +1,12 @@
#!/usr/bin/env python3
"""Tiny auth gate for nginx auth_request. Sets a cookie after successful basic auth."""
import hashlib, hmac, http.server, time, base64, os, sys
import base64
import hashlib
import hmac
import http.server
import os
import sys
import time
SECRET = os.environ.get("AUTH_GATE_SECRET", "")
USER = os.environ.get("AUTH_GATE_USER", "")

View File

@@ -1,5 +1,4 @@
import os
import sys
from pathlib import Path
@@ -8,6 +7,7 @@ sys.path.insert(0, str(Path(__file__).parent / "src"))
from timmy.memory_system import memory_store
def index_research_documents():
research_dir = Path("docs/research")
if not research_dir.is_dir():

View File

@@ -1,9 +1,7 @@
from logging.config import fileConfig
from sqlalchemy import engine_from_config
from sqlalchemy import pool
from alembic import context
from sqlalchemy import engine_from_config, pool
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
@@ -19,7 +17,7 @@ if config.config_file_name is not None:
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
from src.dashboard.models.database import Base
from src.dashboard.models.calm import Task, JournalEntry
target_metadata = Base.metadata
# other values from the config, defined by the needs of env.py,

View File

@@ -5,17 +5,16 @@ Revises:
Create Date: 2026-03-02 10:57:55.537090
"""
from typing import Sequence, Union
from collections.abc import Sequence
from alembic import op
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision: str = '0093c15b4bbf'
down_revision: Union[str, Sequence[str], None] = None
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
down_revision: str | Sequence[str] | None = None
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def upgrade() -> None:

View File

@@ -5,7 +5,6 @@ Usage:
python scripts/add_pytest_markers.py
"""
import re
from pathlib import Path
@@ -93,7 +92,7 @@ def main():
print(f"⏭️ {rel_path:<50} (already marked)")
print(f"\n📊 Total files marked: {marked_count}")
print(f"\n✨ Pytest markers configured. Run 'pytest -m unit' to test specific categories.")
print("\n✨ Pytest markers configured. Run 'pytest -m unit' to test specific categories.")
if __name__ == "__main__":

View File

@@ -1,8 +1,7 @@
import os
def fix_l402_proxy():
path = "src/timmy_serve/l402_proxy.py"
with open(path, "r") as f:
with open(path) as f:
content = f.read()
# 1. Add hmac_secret to Macaroon dataclass
@@ -132,7 +131,7 @@ if _MACAROON_SECRET_RAW == _MACAROON_SECRET_DEFAULT or _HMAC_SECRET_RAW == _HMAC
def fix_xss():
# Fix chat_message.html
path = "src/dashboard/templates/partials/chat_message.html"
with open(path, "r") as f:
with open(path) as f:
content = f.read()
content = content.replace("{{ user_message }}", "{{ user_message | e }}")
content = content.replace("{{ response }}", "{{ response | e }}")
@@ -142,7 +141,7 @@ def fix_xss():
# Fix history.html
path = "src/dashboard/templates/partials/history.html"
with open(path, "r") as f:
with open(path) as f:
content = f.read()
content = content.replace("{{ msg.content }}", "{{ msg.content | e }}")
with open(path, "w") as f:
@@ -150,7 +149,7 @@ def fix_xss():
# Fix briefing.html
path = "src/dashboard/templates/briefing.html"
with open(path, "r") as f:
with open(path) as f:
content = f.read()
content = content.replace("{{ briefing.summary }}", "{{ briefing.summary | e }}")
with open(path, "w") as f:
@@ -158,7 +157,7 @@ def fix_xss():
# Fix approval_card_single.html
path = "src/dashboard/templates/partials/approval_card_single.html"
with open(path, "r") as f:
with open(path) as f:
content = f.read()
content = content.replace("{{ item.title }}", "{{ item.title | e }}")
content = content.replace("{{ item.description }}", "{{ item.description | e }}")
@@ -168,7 +167,7 @@ def fix_xss():
# Fix marketplace.html
path = "src/dashboard/templates/marketplace.html"
with open(path, "r") as f:
with open(path) as f:
content = f.read()
content = content.replace("{{ agent.name }}", "{{ agent.name | e }}")
content = content.replace("{{ agent.role }}", "{{ agent.role | e }}")

View File

@@ -8,8 +8,7 @@ from existing history so the LOOPSTAT panel isn't empty.
import json
import os
import re
import subprocess
from datetime import datetime, timezone
from datetime import UTC, datetime
from pathlib import Path
from urllib.request import Request, urlopen
@@ -227,7 +226,7 @@ def generate_summary(entries: list[dict]):
stats["avg_duration"] = round(stats["total_duration"] / stats["count"])
summary = {
"updated_at": datetime.now(timezone.utc).isoformat(),
"updated_at": datetime.now(UTC).isoformat(),
"window": len(recent),
"total_cycles": len(entries),
"success_rate": round(len(successes) / len(recent), 2) if recent else 0,

View File

@@ -17,7 +17,7 @@ import importlib.util
import json
import sys
import time
from datetime import datetime, timezone
from datetime import UTC, datetime
from pathlib import Path
import requests
@@ -216,7 +216,7 @@ def generate_markdown(all_results: dict, run_date: str) -> str:
lines.append(f"- **Result:** {bres.get('detail', bres.get('error', 'n/a'))}")
snippet = bres.get("code_snippet", "")
if snippet:
lines.append(f"- **Generated code snippet:**")
lines.append("- **Generated code snippet:**")
lines.append(" ```python")
for ln in snippet.splitlines()[:8]:
lines.append(f" {ln}")
@@ -287,7 +287,7 @@ def parse_args() -> argparse.Namespace:
def main() -> int:
args = parse_args()
run_date = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M UTC")
run_date = datetime.now(UTC).strftime("%Y-%m-%d %H:%M UTC")
print(f"Model Benchmark Suite — {run_date}")
print(f"Testing {len(args.models)} model(s): {', '.join(args.models)}")

View File

@@ -46,8 +46,7 @@ import argparse
import json
import re
import subprocess
import sys
from datetime import datetime, timezone
from datetime import UTC, datetime
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parent.parent
@@ -91,7 +90,7 @@ def _epoch_tag(now: datetime | None = None) -> tuple[str, dict]:
When the date rolls over, the counter resets to 1.
"""
if now is None:
now = datetime.now(timezone.utc)
now = datetime.now(UTC)
iso_cal = now.isocalendar() # (year, week, weekday)
week = iso_cal[1]
@@ -221,7 +220,7 @@ def update_summary() -> None:
for k, v in sorted(by_weekday.items())}
summary = {
"updated_at": datetime.now(timezone.utc).isoformat(),
"updated_at": datetime.now(UTC).isoformat(),
"current_epoch": current_epoch,
"window": len(recent),
"measured_cycles": len(measured),
@@ -293,7 +292,7 @@ def main() -> None:
truly_success = args.success and args.main_green
# Generate epoch turnover tag
now = datetime.now(timezone.utc)
now = datetime.now(UTC)
epoch_tag, epoch_parts = _epoch_tag(now)
entry = {

View File

@@ -11,7 +11,6 @@ Usage: python scripts/dev_server.py [--port PORT]
"""
import argparse
import datetime
import os
import socket
import subprocess
@@ -81,8 +80,8 @@ def _ollama_url() -> str:
def _smoke_ollama(url: str) -> str:
"""Quick connectivity check against Ollama."""
import urllib.request
import urllib.error
import urllib.request
try:
req = urllib.request.Request(url, method="GET")
@@ -101,14 +100,14 @@ def _print_banner(port: int) -> None:
hr = "" * 62
print(flush=True)
print(f" {hr}")
print(f" ┃ Timmy Time — Development Server")
print(" ┃ Timmy Time — Development Server")
print(f" {hr}")
print()
print(f" Dashboard: http://localhost:{port}")
print(f" API docs: http://localhost:{port}/docs")
print(f" Health: http://localhost:{port}/health")
print()
print(f" ── Status ──────────────────────────────────────────────")
print(" ── Status ──────────────────────────────────────────────")
print(f" Backend: {ollama_url} [{ollama_status}]")
print(f" Version: {version}")
print(f" Git commit: {git}")

View File

@@ -319,9 +319,9 @@ def main(argv: list[str] | None = None) -> int:
print(f"Exported {count} training examples to: {args.output}")
print()
print("Next steps:")
print(f" mkdir -p ~/timmy-lora-training")
print(" mkdir -p ~/timmy-lora-training")
print(f" cp {args.output} ~/timmy-lora-training/train.jsonl")
print(f" python scripts/lora_finetune.py --data ~/timmy-lora-training")
print(" python scripts/lora_finetune.py --data ~/timmy-lora-training")
else:
print("No training examples exported.")
return 1

View File

@@ -18,9 +18,8 @@ Called by: deep_triage.sh (before the LLM triage), timmy-loop.sh (every 50 cycle
from __future__ import annotations
import json
import sys
from collections import defaultdict
from datetime import datetime, timezone, timedelta
from datetime import UTC, datetime, timedelta
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parent.parent
@@ -52,7 +51,7 @@ def parse_ts(ts_str: str) -> datetime | None:
try:
dt = datetime.fromisoformat(ts_str.replace("Z", "+00:00"))
if dt.tzinfo is None:
dt = dt.replace(tzinfo=timezone.utc)
dt = dt.replace(tzinfo=UTC)
return dt
except (ValueError, TypeError):
return None
@@ -60,7 +59,7 @@ def parse_ts(ts_str: str) -> datetime | None:
def window(entries: list[dict], days: int) -> list[dict]:
"""Filter entries to the last N days."""
cutoff = datetime.now(timezone.utc) - timedelta(days=days)
cutoff = datetime.now(UTC) - timedelta(days=days)
result = []
for e in entries:
ts = parse_ts(e.get("timestamp", ""))
@@ -344,7 +343,7 @@ def main() -> None:
recommendations = generate_recommendations(trends, types, repeats, outliers, triage_eff)
insights = {
"generated_at": datetime.now(timezone.utc).isoformat(),
"generated_at": datetime.now(UTC).isoformat(),
"total_cycles_analyzed": len(cycles),
"trends": trends,
"by_type": types,
@@ -371,7 +370,7 @@ def main() -> None:
header += f" · current epoch: {latest_epoch}"
print(header)
print(f"\n TRENDS (7d vs previous 7d):")
print("\n TRENDS (7d vs previous 7d):")
r7 = trends["recent_7d"]
p7 = trends["previous_7d"]
print(f" Cycles: {r7['count']:>3d} (was {p7['count']})")
@@ -383,14 +382,14 @@ def main() -> None:
print(f" PRs merged: {r7['prs_merged']:>3d} (was {p7['prs_merged']})")
print(f" Lines net: {r7['lines_net']:>+5d}")
print(f"\n BY TYPE:")
print("\n BY TYPE:")
for t, info in sorted(types.items(), key=lambda x: -x[1]["count"]):
print(f" {t:12s} n={info['count']:>2d} "
f"ok={info['success_rate']*100:>3.0f}% "
f"avg={info['avg_duration']//60}m{info['avg_duration']%60:02d}s")
if repeats:
print(f"\n REPEAT FAILURES:")
print("\n REPEAT FAILURES:")
for rf in repeats[:3]:
print(f" #{rf['issue']} failed {rf['failure_count']}x")

View File

@@ -360,7 +360,7 @@ def main(argv: list[str] | None = None) -> int:
return rc
# Default: train
print(f"Starting LoRA fine-tuning")
print("Starting LoRA fine-tuning")
print(f" Model: {model_path}")
print(f" Data: {args.data}")
print(f" Adapter path: {args.adapter_path}")

View File

@@ -9,11 +9,10 @@ This script runs before commits to catch issues early:
- Syntax errors in test files
"""
import sys
import subprocess
from pathlib import Path
import ast
import re
import subprocess
import sys
from pathlib import Path
def check_imports():
@@ -70,7 +69,7 @@ def check_test_syntax():
for test_file in tests_dir.rglob("test_*.py"):
try:
with open(test_file, "r") as f:
with open(test_file) as f:
ast.parse(f.read())
print(f"{test_file.relative_to(tests_dir.parent)} has valid syntax")
except SyntaxError as e:
@@ -86,7 +85,7 @@ def check_platform_specific_tests():
# Check for hardcoded /Users/ paths in tests
tests_dir = Path("tests").resolve()
for test_file in tests_dir.rglob("test_*.py"):
with open(test_file, "r") as f:
with open(test_file) as f:
content = f.read()
if 'startswith("/Users/")' in content:
issues.append(
@@ -110,7 +109,7 @@ def check_docker_availability():
if docker_test_files:
for test_file in docker_test_files:
with open(test_file, "r") as f:
with open(test_file) as f:
content = f.read()
has_skipif = "@pytest.mark.skipif" in content or "pytestmark = pytest.mark.skipif" in content
if not has_skipif and "docker" in content.lower():

View File

@@ -83,8 +83,8 @@ def test_tcp_connection(host: str, port: int, timeout: float) -> tuple[bool, soc
return True, sock
except OSError as exc:
print(f" ✗ Connection failed: {exc}")
print(f" Checklist:")
print(f" - Is Bannerlord running with GABS mod enabled?")
print(" Checklist:")
print(" - Is Bannerlord running with GABS mod enabled?")
print(f" - Is port {port} open in Windows Firewall?")
print(f" - Is the VM IP correct? (got: {host})")
return False, None
@@ -92,7 +92,7 @@ def test_tcp_connection(host: str, port: int, timeout: float) -> tuple[bool, soc
def test_ping(sock: socket.socket) -> bool:
"""PASS: JSON-RPC ping returns a 2.0 response."""
print(f"\n[2/4] JSON-RPC ping")
print("\n[2/4] JSON-RPC ping")
try:
t0 = time.monotonic()
resp = _rpc(sock, "ping", req_id=1)
@@ -109,7 +109,7 @@ def test_ping(sock: socket.socket) -> bool:
def test_game_state(sock: socket.socket) -> bool:
"""PASS: get_game_state returns a result (game must be in a campaign)."""
print(f"\n[3/4] get_game_state call")
print("\n[3/4] get_game_state call")
try:
t0 = time.monotonic()
resp = _rpc(sock, "get_game_state", req_id=2)
@@ -120,7 +120,7 @@ def test_game_state(sock: socket.socket) -> bool:
if code == -32601:
# Method not found — GABS version may not expose this method
print(f" ~ Method not available ({elapsed_ms:.1f} ms): {msg}")
print(f" This is acceptable if game is not yet in a campaign.")
print(" This is acceptable if game is not yet in a campaign.")
return True
print(f" ✗ RPC error ({elapsed_ms:.1f} ms) [{code}]: {msg}")
return False
@@ -191,7 +191,7 @@ def main() -> int:
args = parser.parse_args()
print("=" * 60)
print(f"GABS Connectivity Test Suite")
print("GABS Connectivity Test Suite")
print(f"Target: {args.host}:{args.port}")
print(f"Timeout: {args.timeout}s")
print("=" * 60)

View File

@@ -150,7 +150,7 @@ def test_model_available(model: str) -> bool:
def test_basic_response(model: str) -> bool:
"""PASS: model responds coherently to a simple prompt."""
print(f"\n[2/5] Basic response test")
print("\n[2/5] Basic response test")
messages = [
{"role": "user", "content": "Reply with exactly: HERMES_OK"},
]
@@ -188,7 +188,7 @@ def test_memory_usage() -> bool:
def test_tool_calling(model: str) -> bool:
"""PASS: model produces a tool_calls response (not raw text) for a tool-use prompt."""
print(f"\n[4/5] Tool-calling test")
print("\n[4/5] Tool-calling test")
messages = [
{
"role": "user",
@@ -236,7 +236,7 @@ def test_tool_calling(model: str) -> bool:
def test_timmy_persona(model: str) -> bool:
"""PASS: model accepts a Timmy persona system prompt and responds in-character."""
print(f"\n[5/5] Timmy-persona smoke test")
print("\n[5/5] Timmy-persona smoke test")
messages = [
{
"role": "system",

View File

@@ -26,7 +26,7 @@ import argparse
import json
import sys
import time
from dataclasses import dataclass, field
from dataclasses import dataclass
from typing import Any
try:

View File

@@ -16,7 +16,7 @@ import json
import os
import re
import sys
from datetime import datetime, timezone
from datetime import UTC, datetime
from pathlib import Path
# ── Config ──────────────────────────────────────────────────────────────
@@ -277,7 +277,7 @@ def update_quarantine(scored: list[dict]) -> list[dict]:
"""Auto-quarantine issues that have failed >= 2 times. Returns filtered list."""
failures = load_cycle_failures()
quarantine = load_quarantine()
now = datetime.now(timezone.utc).isoformat()
now = datetime.now(UTC).isoformat()
filtered = []
for item in scored:
@@ -366,7 +366,7 @@ def run_triage() -> list[dict]:
backup_data = QUEUE_BACKUP_FILE.read_text()
json.loads(backup_data) # Validate backup
QUEUE_FILE.write_text(backup_data)
print(f"[triage] Restored queue.json from backup")
print("[triage] Restored queue.json from backup")
except (json.JSONDecodeError, OSError) as restore_exc:
print(f"[triage] ERROR: Backup restore failed: {restore_exc}", file=sys.stderr)
# Write empty list as last resort
@@ -377,7 +377,7 @@ def run_triage() -> list[dict]:
# Write retro entry
retro_entry = {
"timestamp": datetime.now(timezone.utc).isoformat(),
"timestamp": datetime.now(UTC).isoformat(),
"total_open": len(all_issues),
"scored": len(scored),
"ready": len(ready),

View File

@@ -35,9 +35,9 @@ from dashboard.routes.chat_api_v1 import router as chat_api_v1_router
from dashboard.routes.daily_run import router as daily_run_router
from dashboard.routes.db_explorer import router as db_explorer_router
from dashboard.routes.discord import router as discord_router
from dashboard.routes.energy import router as energy_router
from dashboard.routes.experiments import router as experiments_router
from dashboard.routes.grok import router as grok_router
from dashboard.routes.energy import router as energy_router
from dashboard.routes.health import router as health_router
from dashboard.routes.hermes import router as hermes_router
from dashboard.routes.loop_qa import router as loop_qa_router
@@ -48,6 +48,7 @@ from dashboard.routes.models import router as models_router
from dashboard.routes.nexus import router as nexus_router
from dashboard.routes.quests import router as quests_router
from dashboard.routes.scorecards import router as scorecards_router
from dashboard.routes.self_correction import router as self_correction_router
from dashboard.routes.sovereignty_metrics import router as sovereignty_metrics_router
from dashboard.routes.sovereignty_ws import router as sovereignty_ws_router
from dashboard.routes.spark import router as spark_router
@@ -55,7 +56,6 @@ from dashboard.routes.system import router as system_router
from dashboard.routes.tasks import router as tasks_router
from dashboard.routes.telegram import router as telegram_router
from dashboard.routes.thinking import router as thinking_router
from dashboard.routes.self_correction import router as self_correction_router
from dashboard.routes.three_strike import router as three_strike_router
from dashboard.routes.tools import router as tools_router
from dashboard.routes.tower import router as tower_router

View File

@@ -19,7 +19,6 @@ Refs: #1009
"""
import asyncio
import json
import logging
import subprocess
import time

View File

@@ -24,8 +24,8 @@ from infrastructure.models.registry import (
model_registry,
)
from infrastructure.models.router import (
TierLabel,
TieredModelRouter,
TierLabel,
classify_tier,
get_tiered_router,
)

View File

@@ -27,7 +27,6 @@ References:
- Issue #882 — Model Tiering Router: Local 8B / Hermes 70B / Cloud API Cascade
"""
import asyncio
import logging
import re
import time

View File

@@ -20,13 +20,11 @@ Usage::
from __future__ import annotations
import json
import logging
import sqlite3
import uuid
from collections.abc import Generator
from contextlib import closing, contextmanager
from datetime import UTC, datetime
from pathlib import Path
logger = logging.getLogger(__name__)

View File

@@ -21,7 +21,6 @@ import base64
import json
import logging
from datetime import UTC, datetime
from pathlib import Path
from typing import Any
import httpx

View File

@@ -22,21 +22,20 @@ import sqlite3
from datetime import datetime
from pathlib import Path
from timmy.thinking._db import Thought, _get_conn
from timmy.thinking.engine import ThinkingEngine
from timmy.thinking.seeds import (
SEED_TYPES,
_SENSITIVE_PATTERNS,
_META_OBSERVATION_PHRASES,
_THINK_TAG_RE,
_THINKING_PROMPT,
)
# Re-export HOT_MEMORY_PATH and SOUL_PATH so existing patch targets continue to work.
# Tests that patch "timmy.thinking.HOT_MEMORY_PATH" or "timmy.thinking.SOUL_PATH"
# should instead patch "timmy.thinking._snapshot.HOT_MEMORY_PATH" etc., but these
# re-exports are kept for any code that reads them from the top-level namespace.
from timmy.memory_system import HOT_MEMORY_PATH, SOUL_PATH # noqa: F401
from timmy.thinking._db import Thought, _get_conn
from timmy.thinking.engine import ThinkingEngine
from timmy.thinking.seeds import (
_META_OBSERVATION_PHRASES,
_SENSITIVE_PATTERNS,
_THINK_TAG_RE,
_THINKING_PROMPT,
SEED_TYPES,
)
logger = logging.getLogger(__name__)

View File

@@ -4,7 +4,6 @@ import logging
from pathlib import Path
from config import settings
from timmy.thinking.seeds import _META_OBSERVATION_PHRASES, _SENSITIVE_PATTERNS
logger = logging.getLogger(__name__)

View File

@@ -5,11 +5,11 @@ import random
from datetime import UTC, datetime
from timmy.thinking.seeds import (
SEED_TYPES,
_CREATIVE_SEEDS,
_EXISTENTIAL_SEEDS,
_OBSERVATION_SEEDS,
_SOVEREIGNTY_SEEDS,
SEED_TYPES,
)
logger = logging.getLogger(__name__)

View File

@@ -1,7 +1,7 @@
"""System snapshot and memory context mixin for the thinking engine."""
import logging
from datetime import UTC, datetime
from datetime import datetime
from timmy.memory_system import HOT_MEMORY_PATH, SOUL_PATH

View File

@@ -7,8 +7,7 @@ from difflib import SequenceMatcher
from pathlib import Path
from config import settings
from timmy.thinking._db import Thought, _DEFAULT_DB, _get_conn, _row_to_thought
from timmy.thinking._db import _DEFAULT_DB, Thought, _get_conn, _row_to_thought
from timmy.thinking._distillation import _DistillationMixin
from timmy.thinking._issue_filing import _IssueFilingMixin
from timmy.thinking._seeds_mixin import _SeedsMixin

View File

@@ -27,7 +27,6 @@ from infrastructure.router.cascade import (
ProviderStatus,
)
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

View File

@@ -10,13 +10,13 @@ Covers:
- "Plan the optimal path to become Hortator" → LOCAL_HEAVY
"""
from unittest.mock import AsyncMock, MagicMock, patch
from unittest.mock import AsyncMock, MagicMock
import pytest
from infrastructure.models.router import (
TierLabel,
TieredModelRouter,
TierLabel,
_is_low_quality,
classify_tier,
get_tiered_router,

View File

@@ -5,7 +5,6 @@ from __future__ import annotations
from datetime import UTC, datetime, timedelta
from unittest.mock import AsyncMock, MagicMock, patch
import httpx
import pytest
from timmy.backlog_triage import (
@@ -28,7 +27,6 @@ from timmy.backlog_triage import (
score_issue,
)
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

View File

@@ -4,7 +4,6 @@ from unittest.mock import AsyncMock, MagicMock, patch
import pytest
# ---------------------------------------------------------------------------
# exceeds_local_capacity
# ---------------------------------------------------------------------------

View File

@@ -34,7 +34,6 @@ from timmy.quest_system import (
update_quest_progress,
)
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

View File

@@ -15,7 +15,6 @@ if "serpapi" not in sys.modules:
from timmy.research_tools import get_llm_client, google_web_search # noqa: E402
# ---------------------------------------------------------------------------
# google_web_search
# ---------------------------------------------------------------------------

View File

@@ -6,8 +6,7 @@ Refs: #957 (Session Sovereignty Report Generator)
import base64
import json
import time
from datetime import UTC, datetime
from pathlib import Path
from datetime import UTC
from unittest.mock import MagicMock, patch
import pytest
@@ -18,14 +17,12 @@ from timmy.sovereignty.session_report import (
_format_duration,
_gather_session_data,
_gather_sovereignty_data,
_render_markdown,
commit_report,
generate_and_commit_report,
generate_report,
mark_session_start,
)
# ---------------------------------------------------------------------------
# _format_duration
# ---------------------------------------------------------------------------

View File

@@ -7,11 +7,8 @@ from __future__ import annotations
from unittest.mock import MagicMock, patch
import pytest
from timmy.tools.search import _extract_crawl_content, scrape_url, web_search
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

View File

@@ -12,9 +12,7 @@ import argparse
import json
import sys
from pathlib import Path
from unittest.mock import MagicMock, patch
import pytest
from unittest.mock import patch
# Add timmy_automations to path for imports
_TA_PATH = Path(__file__).resolve().parent.parent.parent / "timmy_automations" / "daily_run"

View File

@@ -7,7 +7,6 @@ falls back to the Ollama backend without crashing.
Refs #1284
"""
import sys
from unittest.mock import MagicMock, patch
import pytest

View File

@@ -11,11 +11,9 @@ from unittest.mock import MagicMock, patch
import pytest
from infrastructure.energy.monitor import (
_DEFAULT_MODEL_SIZE_GB,
EnergyBudgetMonitor,
InferenceSample,
_DEFAULT_MODEL_SIZE_GB,
_EFFICIENCY_SCORE_CEILING,
_WATTS_PER_GB_HEURISTIC,
)

View File

@@ -1,9 +1,5 @@
"""Unit tests for infrastructure.self_correction."""
import os
import tempfile
from pathlib import Path
from unittest.mock import patch
import pytest

View File

@@ -13,10 +13,9 @@ Usage:
import argparse
import dataclasses
import json
import os
import sys
import time
from datetime import datetime, timezone
from datetime import UTC, datetime
from pathlib import Path
try:
@@ -28,12 +27,14 @@ except ImportError:
# Add parent dir to path so levels can be imported
sys.path.insert(0, str(Path(__file__).parent))
from levels import level_0_coin_flip
from levels import level_1_tic_tac_toe
from levels import level_2_resource_mgmt
from levels import level_3_battle_tactics
from levels import level_4_trade_route
from levels import level_5_mini_campaign
from levels import (
level_0_coin_flip,
level_1_tic_tac_toe,
level_2_resource_mgmt,
level_3_battle_tactics,
level_4_trade_route,
level_5_mini_campaign,
)
ALL_LEVELS = [
level_0_coin_flip,
@@ -86,7 +87,7 @@ def run_benchmark(
levels_to_run = list(range(len(ALL_LEVELS)))
print(f"\n{'=' * 60}")
print(f" Timmy Cognitive Benchmark — Project Bannerlord M0")
print(" Timmy Cognitive Benchmark — Project Bannerlord M0")
print(f"{'=' * 60}")
print(f" Model: {model}")
print(f" Levels: {levels_to_run}")
@@ -100,7 +101,7 @@ def run_benchmark(
"model": model,
"skipped": True,
"reason": f"Model '{model}' not available",
"timestamp": datetime.now(timezone.utc).isoformat(),
"timestamp": datetime.now(UTC).isoformat(),
}
else:
print(f" ERROR: Model '{model}' not found in Ollama.", file=sys.stderr)
@@ -110,7 +111,7 @@ def run_benchmark(
results = {
"model": model,
"timestamp": datetime.now(timezone.utc).isoformat(),
"timestamp": datetime.now(UTC).isoformat(),
"skipped": False,
"levels": {},
"summary": {},

View File

@@ -21,11 +21,10 @@ import json
import os
import sys
from dataclasses import dataclass, field
from datetime import datetime, timezone
from datetime import UTC, datetime
from pathlib import Path
from typing import Any
from urllib.request import Request, urlopen
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen
# ── Configuration ─────────────────────────────────────────────────────────
@@ -260,7 +259,7 @@ def score_issue_for_path(issue: dict) -> int:
if updated_at:
try:
updated = datetime.fromisoformat(updated_at.replace("Z", "+00:00"))
days_old = (datetime.now(timezone.utc) - updated).days
days_old = (datetime.now(UTC) - updated).days
if days_old < 7:
score += 2
elif days_old < 30:
@@ -388,7 +387,7 @@ def build_golden_path(
4. One more micro-fix or docs (closure)
"""
path = GoldenPath(
generated_at=datetime.now(timezone.utc).isoformat(),
generated_at=datetime.now(UTC).isoformat(),
target_minutes=target_minutes,
)
@@ -478,7 +477,7 @@ def generate_golden_path(
if not client.is_available():
# Return empty path with error indication
return GoldenPath(
generated_at=datetime.now(timezone.utc).isoformat(),
generated_at=datetime.now(UTC).isoformat(),
target_minutes=target_minutes,
items=[],
)

View File

@@ -17,11 +17,11 @@ import json
import os
import sys
from dataclasses import dataclass, field
from datetime import datetime, timedelta, timezone
from datetime import UTC, datetime, timedelta
from pathlib import Path
from typing import Any
from urllib.request import Request, urlopen
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen
# ── Configuration ─────────────────────────────────────────────────────────
@@ -327,7 +327,7 @@ def check_critical_issues(client: GiteaClient, config: dict) -> IssueSignal:
issues=all_critical[:10], # Limit stored issues
)
except (HTTPError, URLError) as exc:
except (HTTPError, URLError):
return IssueSignal(
count=0,
p0_count=0,
@@ -419,7 +419,7 @@ def check_token_economy(config: dict) -> TokenEconomySignal:
try:
# Read last 24 hours of transactions
since = datetime.now(timezone.utc) - timedelta(hours=24)
since = datetime.now(UTC) - timedelta(hours=24)
recent_mint = 0
recent_burn = 0
@@ -511,7 +511,7 @@ def generate_snapshot(config: dict, token: str | None) -> HealthSnapshot:
overall = calculate_overall_status(ci, issues, flakiness)
return HealthSnapshot(
timestamp=datetime.now(timezone.utc).isoformat(),
timestamp=datetime.now(UTC).isoformat(),
overall_status=overall,
ci=ci,
issues=issues,

View File

@@ -19,11 +19,11 @@ import argparse
import json
import os
import sys
from datetime import datetime, timedelta, timezone
from datetime import UTC, datetime, timedelta
from pathlib import Path
from typing import Any
from urllib.request import Request, urlopen
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen
# ── Token Economy Integration ──────────────────────────────────────────────
# Import token rules helpers for tracking Daily Run rewards
@@ -31,12 +31,11 @@ from urllib.error import HTTPError, URLError
sys.path.insert(
0, str(Path(__file__).resolve().parent.parent)
)
from utils.token_rules import TokenRules, compute_token_reward
# Health snapshot lives in the same package
from health_snapshot import generate_snapshot as _generate_health_snapshot
from health_snapshot import get_token as _hs_get_token
from health_snapshot import load_config as _hs_load_config
from utils.token_rules import TokenRules, compute_token_reward
# ── Configuration ─────────────────────────────────────────────────────────
@@ -284,7 +283,7 @@ def generate_agenda(issues: list[dict], config: dict) -> dict:
items.append(item)
return {
"generated_at": datetime.now(timezone.utc).isoformat(),
"generated_at": datetime.now(UTC).isoformat(),
"time_budget_minutes": agenda_time,
"item_count": len(items),
"items": items,
@@ -322,7 +321,7 @@ def print_agenda(agenda: dict) -> None:
def fetch_recent_activity(client: GiteaClient, config: dict) -> dict:
"""Fetch recent issues and PRs from the lookback window."""
lookback_hours = config.get("lookback_hours", 24)
since = datetime.now(timezone.utc) - timedelta(hours=lookback_hours)
since = datetime.now(UTC) - timedelta(hours=lookback_hours)
since_str = since.isoformat()
activity = {
@@ -399,7 +398,7 @@ def load_cycle_data() -> dict:
continue
# Get entries from last 24 hours
since = datetime.now(timezone.utc) - timedelta(hours=24)
since = datetime.now(UTC) - timedelta(hours=24)
recent = [
e for e in entries
if e.get("timestamp") and datetime.fromisoformat(e["timestamp"].replace("Z", "+00:00")) >= since
@@ -426,7 +425,7 @@ def load_cycle_data() -> dict:
def generate_day_summary(activity: dict, cycles: dict) -> dict:
"""Generate a day summary from activity data."""
return {
"generated_at": datetime.now(timezone.utc).isoformat(),
"generated_at": datetime.now(UTC).isoformat(),
"lookback_hours": 24,
"issues_touched": len(activity.get("issues_touched", [])),
"issues_closed": len(activity.get("issues_closed", [])),

View File

@@ -25,7 +25,6 @@ import sys
from collections import Counter
from datetime import UTC, datetime, timedelta
from pathlib import Path
from typing import Any
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen

View File

@@ -12,7 +12,6 @@ Refs: #1105
from __future__ import annotations
import json
import logging
import os
import shutil