- Upgrade OpenClaw primary model from deepseek-v4.1-flash to deepseek-v4.1-flash-1017 across all interactive agents, heartbeats, compaction, and cron jobs. - Configure hardened OpenRouter provider routing for 1017 (deepinfra, inference-net, parasail, cloudflare) with strict fp8/bf16 quantization and tool_choice verification. - Retain deepseek-v4.1-flash (0910), z-ai/glm-5.3-flash, and qwen3.8-flash in the automated fallback chain. - Update ADR 0002 with 1017 economics (30% price reduction on prompt/cache, +60% intelligence benchmark increase) and a 7-point provider qualification playbook. - Add operational scripts and tooling for session compaction, subagent vector deduplication, gateway preflight, and triage diagnostics in k8s/openclaw. - Update DuckDB backend engine, git-sync logic, and test suites. - Enhance Mila tracking UI components and add container build configuration. - Sync Terraform infrastructure state for Authentik.
177 lines
5.8 KiB
Python
177 lines
5.8 KiB
Python
import tempfile
|
|
import pytest
|
|
from pathlib import Path
|
|
from fastapi.testclient import TestClient
|
|
|
|
from app.engine import DuckDBEngine
|
|
from app.models import EventCreateRequest, EventStopRequest
|
|
|
|
|
|
def test_add_and_stop_sleep_event(tmp_path: Path):
|
|
# Use isolated temp directory for write tests so we do not pollute wiki git repo
|
|
engine = DuckDBEngine(data_dir=tmp_path)
|
|
|
|
# 1. Add active sleep event (end=None)
|
|
add_req = EventCreateRequest(
|
|
kind="sleep.session",
|
|
subject="mila",
|
|
payload={"type": "nap", "location": "kinderwagen"},
|
|
actor="test-runner",
|
|
note="Mittagsschlaf Test",
|
|
)
|
|
res_add = engine.add_event(add_req)
|
|
assert res_add["status"] == "success"
|
|
event_id = res_add["id"]
|
|
assert event_id is not None
|
|
|
|
# Check that it appears in open sleep
|
|
open_rows = engine.query(f"SELECT * FROM sleep WHERE id = '{event_id}' AND (isOpen = true OR endIso IS NULL)")
|
|
assert len(open_rows) == 1
|
|
|
|
# 2. Stop the active sleep event
|
|
stop_req = EventStopRequest(
|
|
kind="sleep.session",
|
|
subject="mila",
|
|
event_id=event_id,
|
|
actor="test-runner",
|
|
)
|
|
res_stop = engine.stop_event(stop_req)
|
|
assert res_stop["status"] == "success"
|
|
assert res_stop["id"] == event_id
|
|
|
|
# Check that it is now closed
|
|
closed_rows = engine.query(f"SELECT isOpen, endIso FROM sleep WHERE id = '{event_id}'")
|
|
assert len(closed_rows) == 1
|
|
assert closed_rows[0]["isOpen"] is False
|
|
assert closed_rows[0]["endIso"] is not None
|
|
|
|
|
|
def test_add_nutrition_and_diaper_event(tmp_path: Path):
|
|
engine = DuckDBEngine(data_dir=tmp_path)
|
|
|
|
# Add nutrition event
|
|
nut_req = EventCreateRequest(
|
|
kind="nutrition.intake",
|
|
subject="moritz",
|
|
payload={"item": "Apfel", "qty": 150.0, "kcal": 78.0, "protein_g": 0.5},
|
|
meal="snack",
|
|
actor="test-runner",
|
|
)
|
|
res_nut = engine.add_event(nut_req)
|
|
assert res_nut["status"] == "success"
|
|
nut_id = res_nut["id"]
|
|
|
|
nut_rows = engine.query(f"SELECT * FROM nutrition WHERE id = '{nut_id}'")
|
|
assert len(nut_rows) == 1
|
|
|
|
# Add diaper event
|
|
diaper_req = EventCreateRequest(
|
|
kind="diaper.change",
|
|
subject="mila",
|
|
payload={"pee": True, "poo": False},
|
|
actor="test-runner",
|
|
)
|
|
res_diaper = engine.add_event(diaper_req)
|
|
assert res_diaper["status"] == "success"
|
|
diaper_id = res_diaper["id"]
|
|
|
|
diaper_rows = engine.query(f"SELECT * FROM mila WHERE id = '{diaper_id}'")
|
|
assert len(diaper_rows) == 1
|
|
|
|
|
|
def test_duplicate_open_sleep_rejected(tmp_path: Path):
|
|
engine = DuckDBEngine(data_dir=tmp_path)
|
|
|
|
# 1. Start first open sleep session
|
|
req1 = EventCreateRequest(
|
|
kind="sleep.session",
|
|
subject="mila",
|
|
payload={"type": "nap", "location": "bett"},
|
|
actor="parent",
|
|
)
|
|
res1 = engine.add_event(req1)
|
|
assert res1["status"] == "success"
|
|
|
|
# 2. Attempt to start second open sleep session without stopping the first
|
|
req2 = EventCreateRequest(
|
|
kind="sleep.session",
|
|
subject="mila",
|
|
payload={"type": "nap", "location": "kinderwagen"},
|
|
actor="parent",
|
|
)
|
|
with pytest.raises(ValueError, match="already active for subject 'mila'"):
|
|
engine.add_event(req2)
|
|
|
|
|
|
def test_duplicate_open_sleep_api_endpoint(client: TestClient):
|
|
# 1. Start first session via API
|
|
res1 = client.post("/duckdb-api/v1/events", json={
|
|
"kind": "sleep.session",
|
|
"subject": "test_baby",
|
|
"payload": {"type": "nap"},
|
|
})
|
|
assert res1.status_code == 200
|
|
|
|
# 2. Start second session via API -> must return 400 Bad Request
|
|
res2 = client.post("/duckdb-api/v1/events", json={
|
|
"kind": "sleep.session",
|
|
"subject": "test_baby",
|
|
"payload": {"type": "nap"},
|
|
})
|
|
assert res2.status_code == 400
|
|
assert "already active for subject 'test_baby'" in res2.json()["detail"]
|
|
|
|
# 3. Clean up by stopping
|
|
stop_res = client.post("/duckdb-api/v1/events/stop", json={
|
|
"kind": "sleep.session",
|
|
"subject": "test_baby",
|
|
})
|
|
assert stop_res.status_code == 200
|
|
|
|
|
|
def test_agent_utc_wallclock_guard_and_mila_recipe_defaults(tmp_path: Path):
|
|
engine = DuckDBEngine(data_dir=tmp_path)
|
|
|
|
# 1. Agent passes +00:00 on local wall-clock times (e.g. 08:30 to 10:20)
|
|
nap_req = EventCreateRequest(
|
|
kind="sleep.session",
|
|
subject="mila",
|
|
actor="agent:mila_tracker",
|
|
start="2026-10-17T08:30:00+00:00",
|
|
end="2026-10-17T10:20:00+00:00",
|
|
payload={"type": "nap", "location": "bett"},
|
|
)
|
|
res_nap = engine.add_event(nap_req)
|
|
assert res_nap["status"] == "success"
|
|
assert res_nap["record"]["startIso"] == "2026-10-17T08:30:00+02:00"
|
|
assert res_nap["record"]["endIso"] == "2026-10-17T10:20:00+02:00"
|
|
assert res_nap["record"]["sleepTimeSeconds"] == 6600
|
|
|
|
# 2. Solid food without amount_g gets standard recipe defaults
|
|
brei_req = EventCreateRequest(
|
|
kind="feeding.solid",
|
|
subject="mila",
|
|
actor="agent:mila_tracker",
|
|
start="2026-10-17T12:20:00+00:00",
|
|
meal="lunch",
|
|
payload={"item": "mittagsbrei"},
|
|
)
|
|
res_brei = engine.add_event(brei_req)
|
|
assert res_brei["record"]["start"] == "2026-10-17T12:20:00+02:00"
|
|
assert res_brei["record"]["payload"]["amount_g"] == 190
|
|
assert res_brei["record"]["payload"]["kcal"] == 135
|
|
|
|
abend_req = EventCreateRequest(
|
|
kind="feeding.solid",
|
|
subject="mila",
|
|
actor="agent:mila_tracker",
|
|
start="2026-10-17T16:40:00+00:00",
|
|
meal="dinner",
|
|
payload={"item": "abendbrei"},
|
|
)
|
|
res_abend = engine.add_event(abend_req)
|
|
assert res_abend["record"]["start"] == "2026-10-17T16:40:00+02:00"
|
|
assert res_abend["record"]["payload"]["amount_g"] == 200
|
|
assert res_abend["record"]["payload"]["kcal"] == 110
|
|
|