- Add _language_instruction() to deep_agent.py, reads language from core memory
- Append language directive to all 4 run_* functions (task/project/checkpoint/note)
- Minor fixes: alembic env, route imports, test cleanup
Before: branch 3 of oauth_callback attempted to INSERT a user with a
duplicate email → DB constraint violation → 500.
After: if email_verified=False and the email already exists, raise 409
with a message directing the user to sign in with their password.
Also adds test_callback_unverified_email_conflict_returns_409.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
6 tests covering the authorize and callback endpoints:
- authorize returns URL + state, 503 when unconfigured
- callback: state mismatch → 401, new user creation, existing OAuth
link re-login (same user sub), email-match auto-linking to password user
Provider methods (exchange_code, get_userinfo) are mocked via AsyncMock
so tests run without hitting Google APIs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GET /auth/oauth/{provider}/web-callback receives the Google redirect and
bounces immediately to adiuvai://oauth/callback deep link. Google Cloud
Console only accepts http/https redirect URIs — adiuvai:// is not valid.
Default OAUTH_REDIRECT_URI now points to localhost:8000 for dev; override
with the API domain env var in production.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Step 1 of Google login integration: Alembic migration for oauth_accounts +
avatar_url on users, OAuthAccount model with User relationship, UserProfile
schema extended with avatar_url, get_current_user updated to include avatar_url.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Keep only 4.1 (first reply contains question) as automated eval.
Multi-turn cases (4.2–4.5) are non-deterministic and tested manually
with results tracked in Langfuse.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Langfuse V3 does not accept user_id/session_id on observation-level calls.
Moved to metadata dict in agent_runner, deep_agent, and agent_setup.
refactor(tests): fixture-based pattern for agent_runner_v2 eval tests
- cases.yaml + data/ fixtures under tests/fixtures/agent_runner_v2/
- pytest_generate_tests parametrizes test_eval_runner from YAML
- _resolve_projects() handles symbolic names and inline dicts
- _evaluate_case() centralizes all assertion logic
- --runner-dir CLI option for custom fixture folders
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
lf.trace() and lf.score(trace_id=...) are V2 API removed in V3.
V3 pattern:
lf.start_as_current_observation(name=...) as context manager → obs
obs.score(name=..., value=...)
contextlib.nullcontext() when lf is None so structure stays the same
Updated tests 2.1–2.7 in test_agent_runner_v2.py accordingly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Langfuse uses {{variable}} syntax in its prompt management UI, while the
hardcoded fallbacks use {variable} (Python str.format). The previous code
always called .format() which silently failed/errored when a real Langfuse
prompt was fetched.
- langfuse_client.py: add compile_prompt(template, prompt_obj, **vars)
→ uses prompt_obj.compile(**vars) when Langfuse is available
→ falls back to template.format(**vars) when using the hardcoded fallback
- agent_runner.py: replace .format() with compile_prompt() for
unified_processing (V2 local) and batch_cloud_processing (cloud agent)
- agent_setup.py: replace .format() with compile_prompt() for journey_system
deep_agent.py prompts have no variables, so no change needed there.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
I test del preprocessor sono deterministici — nessun LLM coinvolto,
nessuno score da tracciare.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
file: serve sia come path da leggere che come nome passato a detect_content_type.
Non c'è motivo di averli separati.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- conftest.py: registra --preprocess-dir via pytest_addoption
- test_preprocessors.py: usa pytest_generate_tests per leggere i casi
a collection time con accesso a config; _content e _fixtures_dir
accettano path dinamico
Usage: pytest tests/test_preprocessors.py --preprocess-dir /my/folder
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
YAML: rimosse op/description/score_name/assertions block — ora detect/process
come chiave diretta, assertions piatte sullo stesso livello del caso.
Runner: eliminato _run_assertions engine, assertions inline in test_preprocess.
Riduzione da ~170 a ~75 righe totali tra YAML + test.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Scoring is only meaningful for LLM-backed steps. Preprocess tests are
deterministic Python, so scores add no value. Kept only for detect tests.
- test_preprocess: drop _lf_score call, simplify _run_assertions return type
- cases.yaml: remove score_name from all op=preprocess entries
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New app/core/langfuse_client.py: lazy singleton client, get_prompt_or_fallback()
helper (returns raw template + prompt obj for linking), extract_usage() for token
counts. No-ops when LANGFUSE_* env vars are not set.
- deep_agent.py: home-agent and floating-agent runs wrapped in spans; each ainvoke
wrapped in a generation with model/input/output/usage; prompts fetched from
Langfuse (adiuva-home-agent, adiuva-floating-agent, adiuva-floating-classifier)
with hardcoded fallback.
- agent_runner.py: step1-classifier and step2-processor LLM calls traced; batch
agent _run_agent_with_tools spans + generations; cloud-processor included.
Prompts: adiuva-step1-classifier, adiuva-step2-processor, adiuva-cloud-processor.
- agent_setup.py: journey-setup span + generation per ainvoke; prompt_obj stored
on JourneySession and reused across turns. Prompt: journey_system.
- settings.py: LANGFUSE_SECRET_KEY, LANGFUSE_PUBLIC_KEY, LANGFUSE_HOST added.
- .env.example: Langfuse section with EU/US/self-hosted host comments.
- requirements.txt: langfuse>=2.0.0.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root causes fixed:
1. PROJECT_TOOLS removed from Step 2 tool set — project assignment is now
exclusively handled by the runner in code, never by the LLM.
2. When Step 1 returns "new", runner calls execute_on_client insert/projects
directly (before Step 2), gets the created id, and passes it as context.
3. Newly created projects are appended to the local `projects` list so that
subsequent files in the same run can match to them via Step 1 — prevents
one project per file when multiple files share the same topic.
Also add tests/test_classify_file.py with pytest cases for _classify_file
and a CLI runner: python -m tests.test_classify_file <file> [project...]
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add explicit MUST NOT instruction: never ask about projects, projectId,
or how to link records; project assignment is handled by the agent runner
- Remove projectId from template field list; remove projects from entity types
- Remove stale isApproved=0 reference (already removed from the data model)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>