chore: checkpoint local wip for issue 892
This commit is contained in:
@@ -1,6 +1,12 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""Tiny auth gate for nginx auth_request. Sets a cookie after successful basic auth."""
|
"""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", "")
|
SECRET = os.environ.get("AUTH_GATE_SECRET", "")
|
||||||
USER = os.environ.get("AUTH_GATE_USER", "")
|
USER = os.environ.get("AUTH_GATE_USER", "")
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
|
|
||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@@ -8,6 +7,7 @@ sys.path.insert(0, str(Path(__file__).parent / "src"))
|
|||||||
|
|
||||||
from timmy.memory_system import memory_store
|
from timmy.memory_system import memory_store
|
||||||
|
|
||||||
|
|
||||||
def index_research_documents():
|
def index_research_documents():
|
||||||
research_dir = Path("docs/research")
|
research_dir = Path("docs/research")
|
||||||
if not research_dir.is_dir():
|
if not research_dir.is_dir():
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
from logging.config import fileConfig
|
from logging.config import fileConfig
|
||||||
|
|
||||||
from sqlalchemy import engine_from_config
|
|
||||||
from sqlalchemy import pool
|
|
||||||
|
|
||||||
from alembic import context
|
from alembic import context
|
||||||
|
from sqlalchemy import engine_from_config, pool
|
||||||
|
|
||||||
# this is the Alembic Config object, which provides
|
# this is the Alembic Config object, which provides
|
||||||
# access to the values within the .ini file in use.
|
# 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
|
# from myapp import mymodel
|
||||||
# target_metadata = mymodel.Base.metadata
|
# target_metadata = mymodel.Base.metadata
|
||||||
from src.dashboard.models.database import Base
|
from src.dashboard.models.database import Base
|
||||||
from src.dashboard.models.calm import Task, JournalEntry
|
|
||||||
target_metadata = Base.metadata
|
target_metadata = Base.metadata
|
||||||
|
|
||||||
# other values from the config, defined by the needs of env.py,
|
# other values from the config, defined by the needs of env.py,
|
||||||
|
|||||||
@@ -5,17 +5,16 @@ Revises:
|
|||||||
Create Date: 2026-03-02 10:57:55.537090
|
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
|
import sqlalchemy as sa
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
revision: str = '0093c15b4bbf'
|
revision: str = '0093c15b4bbf'
|
||||||
down_revision: Union[str, Sequence[str], None] = None
|
down_revision: str | Sequence[str] | None = None
|
||||||
branch_labels: Union[str, Sequence[str], None] = None
|
branch_labels: str | Sequence[str] | None = None
|
||||||
depends_on: Union[str, Sequence[str], None] = None
|
depends_on: str | Sequence[str] | None = None
|
||||||
|
|
||||||
|
|
||||||
def upgrade() -> None:
|
def upgrade() -> None:
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ Usage:
|
|||||||
python scripts/add_pytest_markers.py
|
python scripts/add_pytest_markers.py
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import re
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
@@ -93,7 +92,7 @@ def main():
|
|||||||
print(f"⏭️ {rel_path:<50} (already marked)")
|
print(f"⏭️ {rel_path:<50} (already marked)")
|
||||||
|
|
||||||
print(f"\n📊 Total files marked: {marked_count}")
|
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__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
def fix_l402_proxy():
|
def fix_l402_proxy():
|
||||||
path = "src/timmy_serve/l402_proxy.py"
|
path = "src/timmy_serve/l402_proxy.py"
|
||||||
with open(path, "r") as f:
|
with open(path) as f:
|
||||||
content = f.read()
|
content = f.read()
|
||||||
|
|
||||||
# 1. Add hmac_secret to Macaroon dataclass
|
# 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():
|
def fix_xss():
|
||||||
# Fix chat_message.html
|
# Fix chat_message.html
|
||||||
path = "src/dashboard/templates/partials/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 = f.read()
|
||||||
content = content.replace("{{ user_message }}", "{{ user_message | e }}")
|
content = content.replace("{{ user_message }}", "{{ user_message | e }}")
|
||||||
content = content.replace("{{ response }}", "{{ response | e }}")
|
content = content.replace("{{ response }}", "{{ response | e }}")
|
||||||
@@ -142,7 +141,7 @@ def fix_xss():
|
|||||||
|
|
||||||
# Fix history.html
|
# Fix history.html
|
||||||
path = "src/dashboard/templates/partials/history.html"
|
path = "src/dashboard/templates/partials/history.html"
|
||||||
with open(path, "r") as f:
|
with open(path) as f:
|
||||||
content = f.read()
|
content = f.read()
|
||||||
content = content.replace("{{ msg.content }}", "{{ msg.content | e }}")
|
content = content.replace("{{ msg.content }}", "{{ msg.content | e }}")
|
||||||
with open(path, "w") as f:
|
with open(path, "w") as f:
|
||||||
@@ -150,7 +149,7 @@ def fix_xss():
|
|||||||
|
|
||||||
# Fix briefing.html
|
# Fix briefing.html
|
||||||
path = "src/dashboard/templates/briefing.html"
|
path = "src/dashboard/templates/briefing.html"
|
||||||
with open(path, "r") as f:
|
with open(path) as f:
|
||||||
content = f.read()
|
content = f.read()
|
||||||
content = content.replace("{{ briefing.summary }}", "{{ briefing.summary | e }}")
|
content = content.replace("{{ briefing.summary }}", "{{ briefing.summary | e }}")
|
||||||
with open(path, "w") as f:
|
with open(path, "w") as f:
|
||||||
@@ -158,7 +157,7 @@ def fix_xss():
|
|||||||
|
|
||||||
# Fix approval_card_single.html
|
# Fix approval_card_single.html
|
||||||
path = "src/dashboard/templates/partials/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 = f.read()
|
||||||
content = content.replace("{{ item.title }}", "{{ item.title | e }}")
|
content = content.replace("{{ item.title }}", "{{ item.title | e }}")
|
||||||
content = content.replace("{{ item.description }}", "{{ item.description | e }}")
|
content = content.replace("{{ item.description }}", "{{ item.description | e }}")
|
||||||
@@ -168,7 +167,7 @@ def fix_xss():
|
|||||||
|
|
||||||
# Fix marketplace.html
|
# Fix marketplace.html
|
||||||
path = "src/dashboard/templates/marketplace.html"
|
path = "src/dashboard/templates/marketplace.html"
|
||||||
with open(path, "r") as f:
|
with open(path) as f:
|
||||||
content = f.read()
|
content = f.read()
|
||||||
content = content.replace("{{ agent.name }}", "{{ agent.name | e }}")
|
content = content.replace("{{ agent.name }}", "{{ agent.name | e }}")
|
||||||
content = content.replace("{{ agent.role }}", "{{ agent.role | e }}")
|
content = content.replace("{{ agent.role }}", "{{ agent.role | e }}")
|
||||||
|
|||||||
@@ -8,8 +8,7 @@ from existing history so the LOOPSTAT panel isn't empty.
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import subprocess
|
from datetime import UTC, datetime
|
||||||
from datetime import datetime, timezone
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from urllib.request import Request, urlopen
|
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"])
|
stats["avg_duration"] = round(stats["total_duration"] / stats["count"])
|
||||||
|
|
||||||
summary = {
|
summary = {
|
||||||
"updated_at": datetime.now(timezone.utc).isoformat(),
|
"updated_at": datetime.now(UTC).isoformat(),
|
||||||
"window": len(recent),
|
"window": len(recent),
|
||||||
"total_cycles": len(entries),
|
"total_cycles": len(entries),
|
||||||
"success_rate": round(len(successes) / len(recent), 2) if recent else 0,
|
"success_rate": round(len(successes) / len(recent), 2) if recent else 0,
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import importlib.util
|
|||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from datetime import datetime, timezone
|
from datetime import UTC, datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import requests
|
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'))}")
|
lines.append(f"- **Result:** {bres.get('detail', bres.get('error', 'n/a'))}")
|
||||||
snippet = bres.get("code_snippet", "")
|
snippet = bres.get("code_snippet", "")
|
||||||
if snippet:
|
if snippet:
|
||||||
lines.append(f"- **Generated code snippet:**")
|
lines.append("- **Generated code snippet:**")
|
||||||
lines.append(" ```python")
|
lines.append(" ```python")
|
||||||
for ln in snippet.splitlines()[:8]:
|
for ln in snippet.splitlines()[:8]:
|
||||||
lines.append(f" {ln}")
|
lines.append(f" {ln}")
|
||||||
@@ -287,7 +287,7 @@ def parse_args() -> argparse.Namespace:
|
|||||||
|
|
||||||
def main() -> int:
|
def main() -> int:
|
||||||
args = parse_args()
|
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"Model Benchmark Suite — {run_date}")
|
||||||
print(f"Testing {len(args.models)} model(s): {', '.join(args.models)}")
|
print(f"Testing {len(args.models)} model(s): {', '.join(args.models)}")
|
||||||
|
|||||||
@@ -46,8 +46,7 @@ import argparse
|
|||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
from datetime import UTC, datetime
|
||||||
from datetime import datetime, timezone
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
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.
|
When the date rolls over, the counter resets to 1.
|
||||||
"""
|
"""
|
||||||
if now is None:
|
if now is None:
|
||||||
now = datetime.now(timezone.utc)
|
now = datetime.now(UTC)
|
||||||
|
|
||||||
iso_cal = now.isocalendar() # (year, week, weekday)
|
iso_cal = now.isocalendar() # (year, week, weekday)
|
||||||
week = iso_cal[1]
|
week = iso_cal[1]
|
||||||
@@ -221,7 +220,7 @@ def update_summary() -> None:
|
|||||||
for k, v in sorted(by_weekday.items())}
|
for k, v in sorted(by_weekday.items())}
|
||||||
|
|
||||||
summary = {
|
summary = {
|
||||||
"updated_at": datetime.now(timezone.utc).isoformat(),
|
"updated_at": datetime.now(UTC).isoformat(),
|
||||||
"current_epoch": current_epoch,
|
"current_epoch": current_epoch,
|
||||||
"window": len(recent),
|
"window": len(recent),
|
||||||
"measured_cycles": len(measured),
|
"measured_cycles": len(measured),
|
||||||
@@ -293,7 +292,7 @@ def main() -> None:
|
|||||||
truly_success = args.success and args.main_green
|
truly_success = args.success and args.main_green
|
||||||
|
|
||||||
# Generate epoch turnover tag
|
# Generate epoch turnover tag
|
||||||
now = datetime.now(timezone.utc)
|
now = datetime.now(UTC)
|
||||||
epoch_tag, epoch_parts = _epoch_tag(now)
|
epoch_tag, epoch_parts = _epoch_tag(now)
|
||||||
|
|
||||||
entry = {
|
entry = {
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ Usage: python scripts/dev_server.py [--port PORT]
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import datetime
|
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
import subprocess
|
import subprocess
|
||||||
@@ -81,8 +80,8 @@ def _ollama_url() -> str:
|
|||||||
|
|
||||||
def _smoke_ollama(url: str) -> str:
|
def _smoke_ollama(url: str) -> str:
|
||||||
"""Quick connectivity check against Ollama."""
|
"""Quick connectivity check against Ollama."""
|
||||||
import urllib.request
|
|
||||||
import urllib.error
|
import urllib.error
|
||||||
|
import urllib.request
|
||||||
|
|
||||||
try:
|
try:
|
||||||
req = urllib.request.Request(url, method="GET")
|
req = urllib.request.Request(url, method="GET")
|
||||||
@@ -101,14 +100,14 @@ def _print_banner(port: int) -> None:
|
|||||||
hr = "─" * 62
|
hr = "─" * 62
|
||||||
print(flush=True)
|
print(flush=True)
|
||||||
print(f" {hr}")
|
print(f" {hr}")
|
||||||
print(f" ┃ Timmy Time — Development Server")
|
print(" ┃ Timmy Time — Development Server")
|
||||||
print(f" {hr}")
|
print(f" {hr}")
|
||||||
print()
|
print()
|
||||||
print(f" Dashboard: http://localhost:{port}")
|
print(f" Dashboard: http://localhost:{port}")
|
||||||
print(f" API docs: http://localhost:{port}/docs")
|
print(f" API docs: http://localhost:{port}/docs")
|
||||||
print(f" Health: http://localhost:{port}/health")
|
print(f" Health: http://localhost:{port}/health")
|
||||||
print()
|
print()
|
||||||
print(f" ── Status ──────────────────────────────────────────────")
|
print(" ── Status ──────────────────────────────────────────────")
|
||||||
print(f" Backend: {ollama_url} [{ollama_status}]")
|
print(f" Backend: {ollama_url} [{ollama_status}]")
|
||||||
print(f" Version: {version}")
|
print(f" Version: {version}")
|
||||||
print(f" Git commit: {git}")
|
print(f" Git commit: {git}")
|
||||||
|
|||||||
@@ -319,9 +319,9 @@ def main(argv: list[str] | None = None) -> int:
|
|||||||
print(f"Exported {count} training examples to: {args.output}")
|
print(f"Exported {count} training examples to: {args.output}")
|
||||||
print()
|
print()
|
||||||
print("Next steps:")
|
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" 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:
|
else:
|
||||||
print("No training examples exported.")
|
print("No training examples exported.")
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
@@ -18,9 +18,8 @@ Called by: deep_triage.sh (before the LLM triage), timmy-loop.sh (every 50 cycle
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import sys
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from datetime import datetime, timezone, timedelta
|
from datetime import UTC, datetime, timedelta
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||||
@@ -52,7 +51,7 @@ def parse_ts(ts_str: str) -> datetime | None:
|
|||||||
try:
|
try:
|
||||||
dt = datetime.fromisoformat(ts_str.replace("Z", "+00:00"))
|
dt = datetime.fromisoformat(ts_str.replace("Z", "+00:00"))
|
||||||
if dt.tzinfo is None:
|
if dt.tzinfo is None:
|
||||||
dt = dt.replace(tzinfo=timezone.utc)
|
dt = dt.replace(tzinfo=UTC)
|
||||||
return dt
|
return dt
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
return None
|
return None
|
||||||
@@ -60,7 +59,7 @@ def parse_ts(ts_str: str) -> datetime | None:
|
|||||||
|
|
||||||
def window(entries: list[dict], days: int) -> list[dict]:
|
def window(entries: list[dict], days: int) -> list[dict]:
|
||||||
"""Filter entries to the last N days."""
|
"""Filter entries to the last N days."""
|
||||||
cutoff = datetime.now(timezone.utc) - timedelta(days=days)
|
cutoff = datetime.now(UTC) - timedelta(days=days)
|
||||||
result = []
|
result = []
|
||||||
for e in entries:
|
for e in entries:
|
||||||
ts = parse_ts(e.get("timestamp", ""))
|
ts = parse_ts(e.get("timestamp", ""))
|
||||||
@@ -344,7 +343,7 @@ def main() -> None:
|
|||||||
recommendations = generate_recommendations(trends, types, repeats, outliers, triage_eff)
|
recommendations = generate_recommendations(trends, types, repeats, outliers, triage_eff)
|
||||||
|
|
||||||
insights = {
|
insights = {
|
||||||
"generated_at": datetime.now(timezone.utc).isoformat(),
|
"generated_at": datetime.now(UTC).isoformat(),
|
||||||
"total_cycles_analyzed": len(cycles),
|
"total_cycles_analyzed": len(cycles),
|
||||||
"trends": trends,
|
"trends": trends,
|
||||||
"by_type": types,
|
"by_type": types,
|
||||||
@@ -371,7 +370,7 @@ def main() -> None:
|
|||||||
header += f" · current epoch: {latest_epoch}"
|
header += f" · current epoch: {latest_epoch}"
|
||||||
print(header)
|
print(header)
|
||||||
|
|
||||||
print(f"\n TRENDS (7d vs previous 7d):")
|
print("\n TRENDS (7d vs previous 7d):")
|
||||||
r7 = trends["recent_7d"]
|
r7 = trends["recent_7d"]
|
||||||
p7 = trends["previous_7d"]
|
p7 = trends["previous_7d"]
|
||||||
print(f" Cycles: {r7['count']:>3d} (was {p7['count']})")
|
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" PRs merged: {r7['prs_merged']:>3d} (was {p7['prs_merged']})")
|
||||||
print(f" Lines net: {r7['lines_net']:>+5d}")
|
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"]):
|
for t, info in sorted(types.items(), key=lambda x: -x[1]["count"]):
|
||||||
print(f" {t:12s} n={info['count']:>2d} "
|
print(f" {t:12s} n={info['count']:>2d} "
|
||||||
f"ok={info['success_rate']*100:>3.0f}% "
|
f"ok={info['success_rate']*100:>3.0f}% "
|
||||||
f"avg={info['avg_duration']//60}m{info['avg_duration']%60:02d}s")
|
f"avg={info['avg_duration']//60}m{info['avg_duration']%60:02d}s")
|
||||||
|
|
||||||
if repeats:
|
if repeats:
|
||||||
print(f"\n REPEAT FAILURES:")
|
print("\n REPEAT FAILURES:")
|
||||||
for rf in repeats[:3]:
|
for rf in repeats[:3]:
|
||||||
print(f" #{rf['issue']} failed {rf['failure_count']}x")
|
print(f" #{rf['issue']} failed {rf['failure_count']}x")
|
||||||
|
|
||||||
|
|||||||
@@ -360,7 +360,7 @@ def main(argv: list[str] | None = None) -> int:
|
|||||||
return rc
|
return rc
|
||||||
|
|
||||||
# Default: train
|
# Default: train
|
||||||
print(f"Starting LoRA fine-tuning")
|
print("Starting LoRA fine-tuning")
|
||||||
print(f" Model: {model_path}")
|
print(f" Model: {model_path}")
|
||||||
print(f" Data: {args.data}")
|
print(f" Data: {args.data}")
|
||||||
print(f" Adapter path: {args.adapter_path}")
|
print(f" Adapter path: {args.adapter_path}")
|
||||||
|
|||||||
@@ -9,11 +9,10 @@ This script runs before commits to catch issues early:
|
|||||||
- Syntax errors in test files
|
- Syntax errors in test files
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
|
||||||
import subprocess
|
|
||||||
from pathlib import Path
|
|
||||||
import ast
|
import ast
|
||||||
import re
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
def check_imports():
|
def check_imports():
|
||||||
@@ -70,7 +69,7 @@ def check_test_syntax():
|
|||||||
|
|
||||||
for test_file in tests_dir.rglob("test_*.py"):
|
for test_file in tests_dir.rglob("test_*.py"):
|
||||||
try:
|
try:
|
||||||
with open(test_file, "r") as f:
|
with open(test_file) as f:
|
||||||
ast.parse(f.read())
|
ast.parse(f.read())
|
||||||
print(f"✓ {test_file.relative_to(tests_dir.parent)} has valid syntax")
|
print(f"✓ {test_file.relative_to(tests_dir.parent)} has valid syntax")
|
||||||
except SyntaxError as e:
|
except SyntaxError as e:
|
||||||
@@ -86,7 +85,7 @@ def check_platform_specific_tests():
|
|||||||
# Check for hardcoded /Users/ paths in tests
|
# Check for hardcoded /Users/ paths in tests
|
||||||
tests_dir = Path("tests").resolve()
|
tests_dir = Path("tests").resolve()
|
||||||
for test_file in tests_dir.rglob("test_*.py"):
|
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()
|
content = f.read()
|
||||||
if 'startswith("/Users/")' in content:
|
if 'startswith("/Users/")' in content:
|
||||||
issues.append(
|
issues.append(
|
||||||
@@ -110,7 +109,7 @@ def check_docker_availability():
|
|||||||
|
|
||||||
if docker_test_files:
|
if docker_test_files:
|
||||||
for test_file in 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()
|
content = f.read()
|
||||||
has_skipif = "@pytest.mark.skipif" in content or "pytestmark = pytest.mark.skipif" in content
|
has_skipif = "@pytest.mark.skipif" in content or "pytestmark = pytest.mark.skipif" in content
|
||||||
if not has_skipif and "docker" in content.lower():
|
if not has_skipif and "docker" in content.lower():
|
||||||
|
|||||||
@@ -83,8 +83,8 @@ def test_tcp_connection(host: str, port: int, timeout: float) -> tuple[bool, soc
|
|||||||
return True, sock
|
return True, sock
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
print(f" ✗ Connection failed: {exc}")
|
print(f" ✗ Connection failed: {exc}")
|
||||||
print(f" Checklist:")
|
print(" Checklist:")
|
||||||
print(f" - Is Bannerlord running with GABS mod enabled?")
|
print(" - Is Bannerlord running with GABS mod enabled?")
|
||||||
print(f" - Is port {port} open in Windows Firewall?")
|
print(f" - Is port {port} open in Windows Firewall?")
|
||||||
print(f" - Is the VM IP correct? (got: {host})")
|
print(f" - Is the VM IP correct? (got: {host})")
|
||||||
return False, None
|
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:
|
def test_ping(sock: socket.socket) -> bool:
|
||||||
"""PASS: JSON-RPC ping returns a 2.0 response."""
|
"""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:
|
try:
|
||||||
t0 = time.monotonic()
|
t0 = time.monotonic()
|
||||||
resp = _rpc(sock, "ping", req_id=1)
|
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:
|
def test_game_state(sock: socket.socket) -> bool:
|
||||||
"""PASS: get_game_state returns a result (game must be in a campaign)."""
|
"""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:
|
try:
|
||||||
t0 = time.monotonic()
|
t0 = time.monotonic()
|
||||||
resp = _rpc(sock, "get_game_state", req_id=2)
|
resp = _rpc(sock, "get_game_state", req_id=2)
|
||||||
@@ -120,7 +120,7 @@ def test_game_state(sock: socket.socket) -> bool:
|
|||||||
if code == -32601:
|
if code == -32601:
|
||||||
# Method not found — GABS version may not expose this method
|
# Method not found — GABS version may not expose this method
|
||||||
print(f" ~ Method not available ({elapsed_ms:.1f} ms): {msg}")
|
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
|
return True
|
||||||
print(f" ✗ RPC error ({elapsed_ms:.1f} ms) [{code}]: {msg}")
|
print(f" ✗ RPC error ({elapsed_ms:.1f} ms) [{code}]: {msg}")
|
||||||
return False
|
return False
|
||||||
@@ -191,7 +191,7 @@ def main() -> int:
|
|||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
print(f"GABS Connectivity Test Suite")
|
print("GABS Connectivity Test Suite")
|
||||||
print(f"Target: {args.host}:{args.port}")
|
print(f"Target: {args.host}:{args.port}")
|
||||||
print(f"Timeout: {args.timeout}s")
|
print(f"Timeout: {args.timeout}s")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ def test_model_available(model: str) -> bool:
|
|||||||
|
|
||||||
def test_basic_response(model: str) -> bool:
|
def test_basic_response(model: str) -> bool:
|
||||||
"""PASS: model responds coherently to a simple prompt."""
|
"""PASS: model responds coherently to a simple prompt."""
|
||||||
print(f"\n[2/5] Basic response test")
|
print("\n[2/5] Basic response test")
|
||||||
messages = [
|
messages = [
|
||||||
{"role": "user", "content": "Reply with exactly: HERMES_OK"},
|
{"role": "user", "content": "Reply with exactly: HERMES_OK"},
|
||||||
]
|
]
|
||||||
@@ -188,7 +188,7 @@ def test_memory_usage() -> bool:
|
|||||||
|
|
||||||
def test_tool_calling(model: str) -> bool:
|
def test_tool_calling(model: str) -> bool:
|
||||||
"""PASS: model produces a tool_calls response (not raw text) for a tool-use prompt."""
|
"""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 = [
|
messages = [
|
||||||
{
|
{
|
||||||
"role": "user",
|
"role": "user",
|
||||||
@@ -236,7 +236,7 @@ def test_tool_calling(model: str) -> bool:
|
|||||||
|
|
||||||
def test_timmy_persona(model: str) -> bool:
|
def test_timmy_persona(model: str) -> bool:
|
||||||
"""PASS: model accepts a Timmy persona system prompt and responds in-character."""
|
"""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 = [
|
messages = [
|
||||||
{
|
{
|
||||||
"role": "system",
|
"role": "system",
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import argparse
|
|||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import json
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
from datetime import datetime, timezone
|
from datetime import UTC, datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
# ── Config ──────────────────────────────────────────────────────────────
|
# ── Config ──────────────────────────────────────────────────────────────
|
||||||
@@ -277,7 +277,7 @@ def update_quarantine(scored: list[dict]) -> list[dict]:
|
|||||||
"""Auto-quarantine issues that have failed >= 2 times. Returns filtered list."""
|
"""Auto-quarantine issues that have failed >= 2 times. Returns filtered list."""
|
||||||
failures = load_cycle_failures()
|
failures = load_cycle_failures()
|
||||||
quarantine = load_quarantine()
|
quarantine = load_quarantine()
|
||||||
now = datetime.now(timezone.utc).isoformat()
|
now = datetime.now(UTC).isoformat()
|
||||||
|
|
||||||
filtered = []
|
filtered = []
|
||||||
for item in scored:
|
for item in scored:
|
||||||
@@ -366,7 +366,7 @@ def run_triage() -> list[dict]:
|
|||||||
backup_data = QUEUE_BACKUP_FILE.read_text()
|
backup_data = QUEUE_BACKUP_FILE.read_text()
|
||||||
json.loads(backup_data) # Validate backup
|
json.loads(backup_data) # Validate backup
|
||||||
QUEUE_FILE.write_text(backup_data)
|
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:
|
except (json.JSONDecodeError, OSError) as restore_exc:
|
||||||
print(f"[triage] ERROR: Backup restore failed: {restore_exc}", file=sys.stderr)
|
print(f"[triage] ERROR: Backup restore failed: {restore_exc}", file=sys.stderr)
|
||||||
# Write empty list as last resort
|
# Write empty list as last resort
|
||||||
@@ -377,7 +377,7 @@ def run_triage() -> list[dict]:
|
|||||||
|
|
||||||
# Write retro entry
|
# Write retro entry
|
||||||
retro_entry = {
|
retro_entry = {
|
||||||
"timestamp": datetime.now(timezone.utc).isoformat(),
|
"timestamp": datetime.now(UTC).isoformat(),
|
||||||
"total_open": len(all_issues),
|
"total_open": len(all_issues),
|
||||||
"scored": len(scored),
|
"scored": len(scored),
|
||||||
"ready": len(ready),
|
"ready": len(ready),
|
||||||
|
|||||||
@@ -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.daily_run import router as daily_run_router
|
||||||
from dashboard.routes.db_explorer import router as db_explorer_router
|
from dashboard.routes.db_explorer import router as db_explorer_router
|
||||||
from dashboard.routes.discord import router as discord_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.experiments import router as experiments_router
|
||||||
from dashboard.routes.grok import router as grok_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.health import router as health_router
|
||||||
from dashboard.routes.hermes import router as hermes_router
|
from dashboard.routes.hermes import router as hermes_router
|
||||||
from dashboard.routes.loop_qa import router as loop_qa_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.nexus import router as nexus_router
|
||||||
from dashboard.routes.quests import router as quests_router
|
from dashboard.routes.quests import router as quests_router
|
||||||
from dashboard.routes.scorecards import router as scorecards_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_metrics import router as sovereignty_metrics_router
|
||||||
from dashboard.routes.sovereignty_ws import router as sovereignty_ws_router
|
from dashboard.routes.sovereignty_ws import router as sovereignty_ws_router
|
||||||
from dashboard.routes.spark import router as spark_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.tasks import router as tasks_router
|
||||||
from dashboard.routes.telegram import router as telegram_router
|
from dashboard.routes.telegram import router as telegram_router
|
||||||
from dashboard.routes.thinking import router as thinking_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.three_strike import router as three_strike_router
|
||||||
from dashboard.routes.tools import router as tools_router
|
from dashboard.routes.tools import router as tools_router
|
||||||
from dashboard.routes.tower import router as tower_router
|
from dashboard.routes.tower import router as tower_router
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ Refs: #1009
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ from infrastructure.models.registry import (
|
|||||||
model_registry,
|
model_registry,
|
||||||
)
|
)
|
||||||
from infrastructure.models.router import (
|
from infrastructure.models.router import (
|
||||||
TierLabel,
|
|
||||||
TieredModelRouter,
|
TieredModelRouter,
|
||||||
|
TierLabel,
|
||||||
classify_tier,
|
classify_tier,
|
||||||
get_tiered_router,
|
get_tiered_router,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ References:
|
|||||||
- Issue #882 — Model Tiering Router: Local 8B / Hermes 70B / Cloud API Cascade
|
- Issue #882 — Model Tiering Router: Local 8B / Hermes 70B / Cloud API Cascade
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import asyncio
|
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
|||||||
@@ -20,13 +20,11 @@ Usage::
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import uuid
|
import uuid
|
||||||
from collections.abc import Generator
|
from collections.abc import Generator
|
||||||
from contextlib import closing, contextmanager
|
from contextlib import closing, contextmanager
|
||||||
from datetime import UTC, datetime
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import base64
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
from datetime import UTC, datetime
|
from datetime import UTC, datetime
|
||||||
from pathlib import Path
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|||||||
@@ -22,21 +22,20 @@ import sqlite3
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
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.
|
# 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"
|
# 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
|
# 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.
|
# 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.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__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import logging
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from config import settings
|
from config import settings
|
||||||
|
|
||||||
from timmy.thinking.seeds import _META_OBSERVATION_PHRASES, _SENSITIVE_PATTERNS
|
from timmy.thinking.seeds import _META_OBSERVATION_PHRASES, _SENSITIVE_PATTERNS
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ import random
|
|||||||
from datetime import UTC, datetime
|
from datetime import UTC, datetime
|
||||||
|
|
||||||
from timmy.thinking.seeds import (
|
from timmy.thinking.seeds import (
|
||||||
SEED_TYPES,
|
|
||||||
_CREATIVE_SEEDS,
|
_CREATIVE_SEEDS,
|
||||||
_EXISTENTIAL_SEEDS,
|
_EXISTENTIAL_SEEDS,
|
||||||
_OBSERVATION_SEEDS,
|
_OBSERVATION_SEEDS,
|
||||||
_SOVEREIGNTY_SEEDS,
|
_SOVEREIGNTY_SEEDS,
|
||||||
|
SEED_TYPES,
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""System snapshot and memory context mixin for the thinking engine."""
|
"""System snapshot and memory context mixin for the thinking engine."""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from datetime import UTC, datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from timmy.memory_system import HOT_MEMORY_PATH, SOUL_PATH
|
from timmy.memory_system import HOT_MEMORY_PATH, SOUL_PATH
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ from difflib import SequenceMatcher
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from config import settings
|
from config import settings
|
||||||
|
from timmy.thinking._db import _DEFAULT_DB, Thought, _get_conn, _row_to_thought
|
||||||
from timmy.thinking._db import Thought, _DEFAULT_DB, _get_conn, _row_to_thought
|
|
||||||
from timmy.thinking._distillation import _DistillationMixin
|
from timmy.thinking._distillation import _DistillationMixin
|
||||||
from timmy.thinking._issue_filing import _IssueFilingMixin
|
from timmy.thinking._issue_filing import _IssueFilingMixin
|
||||||
from timmy.thinking._seeds_mixin import _SeedsMixin
|
from timmy.thinking._seeds_mixin import _SeedsMixin
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ from infrastructure.router.cascade import (
|
|||||||
ProviderStatus,
|
ProviderStatus,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Helpers
|
# Helpers
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -10,13 +10,13 @@ Covers:
|
|||||||
- "Plan the optimal path to become Hortator" → LOCAL_HEAVY
|
- "Plan the optimal path to become Hortator" → LOCAL_HEAVY
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from unittest.mock import AsyncMock, MagicMock, patch
|
from unittest.mock import AsyncMock, MagicMock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from infrastructure.models.router import (
|
from infrastructure.models.router import (
|
||||||
TierLabel,
|
|
||||||
TieredModelRouter,
|
TieredModelRouter,
|
||||||
|
TierLabel,
|
||||||
_is_low_quality,
|
_is_low_quality,
|
||||||
classify_tier,
|
classify_tier,
|
||||||
get_tiered_router,
|
get_tiered_router,
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ from __future__ import annotations
|
|||||||
from datetime import UTC, datetime, timedelta
|
from datetime import UTC, datetime, timedelta
|
||||||
from unittest.mock import AsyncMock, MagicMock, patch
|
from unittest.mock import AsyncMock, MagicMock, patch
|
||||||
|
|
||||||
import httpx
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from timmy.backlog_triage import (
|
from timmy.backlog_triage import (
|
||||||
@@ -28,7 +27,6 @@ from timmy.backlog_triage import (
|
|||||||
score_issue,
|
score_issue,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Helpers
|
# Helpers
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ from unittest.mock import AsyncMock, MagicMock, patch
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# exceeds_local_capacity
|
# exceeds_local_capacity
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ from timmy.quest_system import (
|
|||||||
update_quest_progress,
|
update_quest_progress,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Helpers
|
# Helpers
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ if "serpapi" not in sys.modules:
|
|||||||
|
|
||||||
from timmy.research_tools import get_llm_client, google_web_search # noqa: E402
|
from timmy.research_tools import get_llm_client, google_web_search # noqa: E402
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# google_web_search
|
# google_web_search
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ Refs: #957 (Session Sovereignty Report Generator)
|
|||||||
import base64
|
import base64
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
from datetime import UTC, datetime
|
from datetime import UTC
|
||||||
from pathlib import Path
|
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@@ -18,14 +17,12 @@ from timmy.sovereignty.session_report import (
|
|||||||
_format_duration,
|
_format_duration,
|
||||||
_gather_session_data,
|
_gather_session_data,
|
||||||
_gather_sovereignty_data,
|
_gather_sovereignty_data,
|
||||||
_render_markdown,
|
|
||||||
commit_report,
|
commit_report,
|
||||||
generate_and_commit_report,
|
generate_and_commit_report,
|
||||||
generate_report,
|
generate_report,
|
||||||
mark_session_start,
|
mark_session_start,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# _format_duration
|
# _format_duration
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -7,11 +7,8 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from timmy.tools.search import _extract_crawl_content, scrape_url, web_search
|
from timmy.tools.search import _extract_crawl_content, scrape_url, web_search
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Helpers
|
# Helpers
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -12,9 +12,7 @@ import argparse
|
|||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
# Add timmy_automations to path for imports
|
# Add timmy_automations to path for imports
|
||||||
_TA_PATH = Path(__file__).resolve().parent.parent.parent / "timmy_automations" / "daily_run"
|
_TA_PATH = Path(__file__).resolve().parent.parent.parent / "timmy_automations" / "daily_run"
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ falls back to the Ollama backend without crashing.
|
|||||||
Refs #1284
|
Refs #1284
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|||||||
@@ -11,11 +11,9 @@ from unittest.mock import MagicMock, patch
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from infrastructure.energy.monitor import (
|
from infrastructure.energy.monitor import (
|
||||||
|
_DEFAULT_MODEL_SIZE_GB,
|
||||||
EnergyBudgetMonitor,
|
EnergyBudgetMonitor,
|
||||||
InferenceSample,
|
InferenceSample,
|
||||||
_DEFAULT_MODEL_SIZE_GB,
|
|
||||||
_EFFICIENCY_SCORE_CEILING,
|
|
||||||
_WATTS_PER_GB_HEURISTIC,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
"""Unit tests for infrastructure.self_correction."""
|
"""Unit tests for infrastructure.self_correction."""
|
||||||
|
|
||||||
import os
|
|
||||||
import tempfile
|
|
||||||
from pathlib import Path
|
|
||||||
from unittest.mock import patch
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -13,10 +13,9 @@ Usage:
|
|||||||
import argparse
|
import argparse
|
||||||
import dataclasses
|
import dataclasses
|
||||||
import json
|
import json
|
||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from datetime import datetime, timezone
|
from datetime import UTC, datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -28,12 +27,14 @@ except ImportError:
|
|||||||
# Add parent dir to path so levels can be imported
|
# Add parent dir to path so levels can be imported
|
||||||
sys.path.insert(0, str(Path(__file__).parent))
|
sys.path.insert(0, str(Path(__file__).parent))
|
||||||
|
|
||||||
from levels import level_0_coin_flip
|
from levels import (
|
||||||
from levels import level_1_tic_tac_toe
|
level_0_coin_flip,
|
||||||
from levels import level_2_resource_mgmt
|
level_1_tic_tac_toe,
|
||||||
from levels import level_3_battle_tactics
|
level_2_resource_mgmt,
|
||||||
from levels import level_4_trade_route
|
level_3_battle_tactics,
|
||||||
from levels import level_5_mini_campaign
|
level_4_trade_route,
|
||||||
|
level_5_mini_campaign,
|
||||||
|
)
|
||||||
|
|
||||||
ALL_LEVELS = [
|
ALL_LEVELS = [
|
||||||
level_0_coin_flip,
|
level_0_coin_flip,
|
||||||
@@ -86,7 +87,7 @@ def run_benchmark(
|
|||||||
levels_to_run = list(range(len(ALL_LEVELS)))
|
levels_to_run = list(range(len(ALL_LEVELS)))
|
||||||
|
|
||||||
print(f"\n{'=' * 60}")
|
print(f"\n{'=' * 60}")
|
||||||
print(f" Timmy Cognitive Benchmark — Project Bannerlord M0")
|
print(" Timmy Cognitive Benchmark — Project Bannerlord M0")
|
||||||
print(f"{'=' * 60}")
|
print(f"{'=' * 60}")
|
||||||
print(f" Model: {model}")
|
print(f" Model: {model}")
|
||||||
print(f" Levels: {levels_to_run}")
|
print(f" Levels: {levels_to_run}")
|
||||||
@@ -100,7 +101,7 @@ def run_benchmark(
|
|||||||
"model": model,
|
"model": model,
|
||||||
"skipped": True,
|
"skipped": True,
|
||||||
"reason": f"Model '{model}' not available",
|
"reason": f"Model '{model}' not available",
|
||||||
"timestamp": datetime.now(timezone.utc).isoformat(),
|
"timestamp": datetime.now(UTC).isoformat(),
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
print(f" ERROR: Model '{model}' not found in Ollama.", file=sys.stderr)
|
print(f" ERROR: Model '{model}' not found in Ollama.", file=sys.stderr)
|
||||||
@@ -110,7 +111,7 @@ def run_benchmark(
|
|||||||
|
|
||||||
results = {
|
results = {
|
||||||
"model": model,
|
"model": model,
|
||||||
"timestamp": datetime.now(timezone.utc).isoformat(),
|
"timestamp": datetime.now(UTC).isoformat(),
|
||||||
"skipped": False,
|
"skipped": False,
|
||||||
"levels": {},
|
"levels": {},
|
||||||
"summary": {},
|
"summary": {},
|
||||||
|
|||||||
@@ -21,11 +21,10 @@ import json
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from datetime import datetime, timezone
|
from datetime import UTC, datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
|
||||||
from urllib.request import Request, urlopen
|
|
||||||
from urllib.error import HTTPError, URLError
|
from urllib.error import HTTPError, URLError
|
||||||
|
from urllib.request import Request, urlopen
|
||||||
|
|
||||||
# ── Configuration ─────────────────────────────────────────────────────────
|
# ── Configuration ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -260,7 +259,7 @@ def score_issue_for_path(issue: dict) -> int:
|
|||||||
if updated_at:
|
if updated_at:
|
||||||
try:
|
try:
|
||||||
updated = datetime.fromisoformat(updated_at.replace("Z", "+00:00"))
|
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:
|
if days_old < 7:
|
||||||
score += 2
|
score += 2
|
||||||
elif days_old < 30:
|
elif days_old < 30:
|
||||||
@@ -388,7 +387,7 @@ def build_golden_path(
|
|||||||
4. One more micro-fix or docs (closure)
|
4. One more micro-fix or docs (closure)
|
||||||
"""
|
"""
|
||||||
path = GoldenPath(
|
path = GoldenPath(
|
||||||
generated_at=datetime.now(timezone.utc).isoformat(),
|
generated_at=datetime.now(UTC).isoformat(),
|
||||||
target_minutes=target_minutes,
|
target_minutes=target_minutes,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -478,7 +477,7 @@ def generate_golden_path(
|
|||||||
if not client.is_available():
|
if not client.is_available():
|
||||||
# Return empty path with error indication
|
# Return empty path with error indication
|
||||||
return GoldenPath(
|
return GoldenPath(
|
||||||
generated_at=datetime.now(timezone.utc).isoformat(),
|
generated_at=datetime.now(UTC).isoformat(),
|
||||||
target_minutes=target_minutes,
|
target_minutes=target_minutes,
|
||||||
items=[],
|
items=[],
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -17,11 +17,11 @@ import json
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import UTC, datetime, timedelta
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from urllib.request import Request, urlopen
|
|
||||||
from urllib.error import HTTPError, URLError
|
from urllib.error import HTTPError, URLError
|
||||||
|
from urllib.request import Request, urlopen
|
||||||
|
|
||||||
# ── Configuration ─────────────────────────────────────────────────────────
|
# ── Configuration ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -327,7 +327,7 @@ def check_critical_issues(client: GiteaClient, config: dict) -> IssueSignal:
|
|||||||
issues=all_critical[:10], # Limit stored issues
|
issues=all_critical[:10], # Limit stored issues
|
||||||
)
|
)
|
||||||
|
|
||||||
except (HTTPError, URLError) as exc:
|
except (HTTPError, URLError):
|
||||||
return IssueSignal(
|
return IssueSignal(
|
||||||
count=0,
|
count=0,
|
||||||
p0_count=0,
|
p0_count=0,
|
||||||
@@ -419,7 +419,7 @@ def check_token_economy(config: dict) -> TokenEconomySignal:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# Read last 24 hours of transactions
|
# 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_mint = 0
|
||||||
recent_burn = 0
|
recent_burn = 0
|
||||||
@@ -511,7 +511,7 @@ def generate_snapshot(config: dict, token: str | None) -> HealthSnapshot:
|
|||||||
overall = calculate_overall_status(ci, issues, flakiness)
|
overall = calculate_overall_status(ci, issues, flakiness)
|
||||||
|
|
||||||
return HealthSnapshot(
|
return HealthSnapshot(
|
||||||
timestamp=datetime.now(timezone.utc).isoformat(),
|
timestamp=datetime.now(UTC).isoformat(),
|
||||||
overall_status=overall,
|
overall_status=overall,
|
||||||
ci=ci,
|
ci=ci,
|
||||||
issues=issues,
|
issues=issues,
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ import argparse
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import UTC, datetime, timedelta
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from urllib.request import Request, urlopen
|
|
||||||
from urllib.error import HTTPError, URLError
|
from urllib.error import HTTPError, URLError
|
||||||
|
from urllib.request import Request, urlopen
|
||||||
|
|
||||||
# ── Token Economy Integration ──────────────────────────────────────────────
|
# ── Token Economy Integration ──────────────────────────────────────────────
|
||||||
# Import token rules helpers for tracking Daily Run rewards
|
# Import token rules helpers for tracking Daily Run rewards
|
||||||
@@ -31,12 +31,11 @@ from urllib.error import HTTPError, URLError
|
|||||||
sys.path.insert(
|
sys.path.insert(
|
||||||
0, str(Path(__file__).resolve().parent.parent)
|
0, str(Path(__file__).resolve().parent.parent)
|
||||||
)
|
)
|
||||||
from utils.token_rules import TokenRules, compute_token_reward
|
|
||||||
|
|
||||||
# Health snapshot lives in the same package
|
# Health snapshot lives in the same package
|
||||||
from health_snapshot import generate_snapshot as _generate_health_snapshot
|
from health_snapshot import generate_snapshot as _generate_health_snapshot
|
||||||
from health_snapshot import get_token as _hs_get_token
|
from health_snapshot import get_token as _hs_get_token
|
||||||
from health_snapshot import load_config as _hs_load_config
|
from health_snapshot import load_config as _hs_load_config
|
||||||
|
from utils.token_rules import TokenRules, compute_token_reward
|
||||||
|
|
||||||
# ── Configuration ─────────────────────────────────────────────────────────
|
# ── Configuration ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -284,7 +283,7 @@ def generate_agenda(issues: list[dict], config: dict) -> dict:
|
|||||||
items.append(item)
|
items.append(item)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"generated_at": datetime.now(timezone.utc).isoformat(),
|
"generated_at": datetime.now(UTC).isoformat(),
|
||||||
"time_budget_minutes": agenda_time,
|
"time_budget_minutes": agenda_time,
|
||||||
"item_count": len(items),
|
"item_count": len(items),
|
||||||
"items": items,
|
"items": items,
|
||||||
@@ -322,7 +321,7 @@ def print_agenda(agenda: dict) -> None:
|
|||||||
def fetch_recent_activity(client: GiteaClient, config: dict) -> dict:
|
def fetch_recent_activity(client: GiteaClient, config: dict) -> dict:
|
||||||
"""Fetch recent issues and PRs from the lookback window."""
|
"""Fetch recent issues and PRs from the lookback window."""
|
||||||
lookback_hours = config.get("lookback_hours", 24)
|
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()
|
since_str = since.isoformat()
|
||||||
|
|
||||||
activity = {
|
activity = {
|
||||||
@@ -399,7 +398,7 @@ def load_cycle_data() -> dict:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# Get entries from last 24 hours
|
# Get entries from last 24 hours
|
||||||
since = datetime.now(timezone.utc) - timedelta(hours=24)
|
since = datetime.now(UTC) - timedelta(hours=24)
|
||||||
recent = [
|
recent = [
|
||||||
e for e in entries
|
e for e in entries
|
||||||
if e.get("timestamp") and datetime.fromisoformat(e["timestamp"].replace("Z", "+00:00")) >= since
|
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:
|
def generate_day_summary(activity: dict, cycles: dict) -> dict:
|
||||||
"""Generate a day summary from activity data."""
|
"""Generate a day summary from activity data."""
|
||||||
return {
|
return {
|
||||||
"generated_at": datetime.now(timezone.utc).isoformat(),
|
"generated_at": datetime.now(UTC).isoformat(),
|
||||||
"lookback_hours": 24,
|
"lookback_hours": 24,
|
||||||
"issues_touched": len(activity.get("issues_touched", [])),
|
"issues_touched": len(activity.get("issues_touched", [])),
|
||||||
"issues_closed": len(activity.get("issues_closed", [])),
|
"issues_closed": len(activity.get("issues_closed", [])),
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import sys
|
|||||||
from collections import Counter
|
from collections import Counter
|
||||||
from datetime import UTC, datetime, timedelta
|
from datetime import UTC, datetime, timedelta
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
|
||||||
from urllib.error import HTTPError, URLError
|
from urllib.error import HTTPError, URLError
|
||||||
from urllib.request import Request, urlopen
|
from urllib.request import Request, urlopen
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ Refs: #1105
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
|||||||
Reference in New Issue
Block a user