feat(agents): per-agent inference — momentum, overdue-task, recent-patterns, focus-area (ADR-0014 step 7)

All four agents bumped to v1.1.0.

momentum (#114): infers engagement_trend ('up'|'stable'|'down') by comparing
done-rate in the last 7 days vs the prior 7 days. Agent surfaces the trend
in its snippet ("trending up — build on the momentum").

overdue-task (#115): infers lateness_tolerance_days (0/1/2) from snooze rate.
Agent now filters tasks against the tolerance so low-urgency users aren't
nagged about tasks that are only hours overdue.

recent-patterns (#116): infers window_days (7/14/30) from feedback event
density — sparse users get a wider window so the snippet isn't always empty.

focus-area (#113): no inferred params (project-level feedback linkage needed,
tracked under #78). preferred_areas pref was declared but ignored; agent now
honours it as a tiebreaker and mentions it in the snippet.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-05 11:21:10 +00:00
parent ad6747c242
commit afb0e9b0cb
8 changed files with 383 additions and 26 deletions

View File

@@ -36,10 +36,10 @@ async def test_infer_time_of_day_enough_history():
@pytest.mark.anyio
async def test_infer_agent_with_no_inferred_params():
"""Agents with no inferred_params return an empty dict."""
"""Agents with no inferred_params return an empty dict (focus-area has none)."""
transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="http://test") as client:
resp = await client.post("/agents/overdue-task/infer", json={"user_id": "u1", "feedback_history": []})
resp = await client.post("/agents/focus-area/infer", json={"user_id": "u1", "feedback_history": []})
assert resp.status_code == 200
assert resp.json()["inferred_prefs"] == {}