Spaces:
Sleeping
Sleeping
Commit History
-
[assess] Agentic guard against junk/jailbreak input; tidy economic UX
Hélder Monteiro +1: CodexPer feedback that a smart agent should refuse to assess garbage rather than fabricate a result — and that this must be MODEL REASONING, not hardcoded prose matching: - Prompt: a precedence GATE checked before any category. If the answers are nonsensical / test strings / code / contradictory / devoid of real info, the agent sets case_type=unclear, leaves grounds+countries empty, and asks for a genuine account. 'No protection ground' now requires a genuine account — junk is unclear, never economic (the bucket the model was wrongly falling through to). - assessment.py: an unclear case yields NO recommendations (don't invent destinations from junk); _synth_reasoning returns a clean 'I couldn't determine your situation' message instead of a protection narrative. - recommendations.py: a 'needs more info' panel (no cards, no roadmap, proceed hidden) when there are no recs; the economic intro is trimmed to one line since the full honest explanation already lives in the assessm…9c6656b -
[fix] Give Ollama a real context window (root cause); deterministic weak-check
Hélder Monteiro +1: CodexRoot cause of the 'assessment acts like a chatbot / refuses' behavior: Ollama loaded the model with its default ~4096-token context, which silently TRUNCATED the assessment prompt (system + facts + injected guideline/country tool results) and dropped the instructions — so the model drifted to a greeting. Fix the cause: - agent/loop.py passes options.num_ctx (env NUM_CTX, default 16384) on every chat. - deploy/modal_app.py loads the model with OLLAMA_CONTEXT_LENGTH=NUM_CTX so the server matches the client (no reload on first request). With 16k context lfm2.5:8b now produces a correct, structured assessment on its own (verified over Modal: refugee · sexual-orientation PSG · high · 3 cards). Per feedback, replace the brittle prose phrase-matching weak-detector with a DETERMINISTIC signal: the answer is weak only when the model produced no structured output (case_type/grounds/countries) or almost no text — no guessing at non-deterministic wording. The interview-grounded fallback then r…cd3c555 -
[fix] Treat chatbot-greeting assessments as weak (use grounded fallback)
Hélder Monteiro +1: Codexlfm2.5:8b sometimes answered the assessment with a conversational greeting that asked the person for info it already had ('Could you tell me your preferred language?… please share … when you're ready'). That isn't a refusal, so it slipped past _is_weak_reasoning and leaked to the screen. Add greeting / request-for-info markers so these are treated as weak and replaced by the deterministic interview-grounded analysis + recommendations. Co-authored-by: Codex <noreply@openai.com>e88a54f -
[fix] Robust assessment + 2-3 recs + documents progress
Hélder Monteiro +1: CodexThree issues found in the live test (small-model quality + UX), not deployment: 1. Assessment could show a refusal ('I cannot determine a case type…'). The rich deterministic fallback only triggered when the narration was <120 chars, so a long non-answer leaked. Add _is_weak_reasoning() (refusal markers + length); when weak, take the interview-derived case_type/grounds/risk and the structured _synth_reasoning instead of the model's non-answer. 2. Recommendations always showed ONE country (we only topped up when the list was empty). Now top up protection cases to 2-3 using the person's own stated destination_preferences (looked up, signatory-only), then strong curated systems; cap at 3. Algeria case now -> Sweden/France/Italy. 3. 'Prepare my documents' looked frozen during the LLM draft. show_documents is now an async generator: reveal the docs screen with a 'Preparing your document package…' status immediately, then render the finished Word+PDF package. C…6614702
-
[fix] Hide doubled 'processing' spinner; never leak @@END / metadata
Hélder Monteiro +1: Codex1) Two 'processing…' overlays appeared in the interview responder because the choice controls are now always mounted-visible, so Gradio painted its generic per-component progress spinner on each. Set show_progress='hidden' on the interview events (Begin + Continue + reveal); the conversation itself signals progress and the assessment has its own bar. 2) The assessment leaked '@@END' and a raw 'Summary of my assessment' list when the small model wrote the metadata as prose instead of the @@ASSESSMENT block. parse_assessment now recognises the metadata in three forms (the @@ASSESSMENT block, a 'Summary of my assessment' section, or a bare run of field: lines), strips all of it plus any stray @@ASSESSMENT/@@END markers from the visible reasoning, and parses fields tolerant of bullets and parenthetical glosses. Co-authored-by: Codex <noreply@openai.com>3c64ee8
-
[agentic] Port pi loop hooks + LLM-drafted editable (Word) documents
Hélder Monteiro +1: CodexAudited /tmp/pi and ported its agentic control architecture into Refuge's Python loop, then used it to make the assessment and documents genuinely agentic (the hackathon point: small-LLM agentic AI). Agent framework (agent/loop.py) — Python port of pi's AgentLoopConfig hooks: - LoopHooks: transform_context, before_tool_call, after_tool_call, should_stop_after_turn, prepare_next_turn; plus tool `terminate` handling. Assessment now uses the hooks: - should_stop_after_turn ends the run once the @@ASSESSMENT block is produced (no rambling); before_tool_call blocks web_search queries containing the person's private narrative (privacy, ARCHITECTURE §Security). Documents are now agentic + editable: - agent/drafting.py: the LLM drafts an in-depth, first-person personal statement from the person's own answers, in their language, with [placeholders] to complete (deterministic fallback if the model is down; nothing fabricated). - doc_generator: exports every document as editable Word…b93c45d -
[T049-T055 + UX] Phase 5 documents + single-model + responder/UX fixes
Hélder Monteiro +1: CodexPhase 5 — Document package: - agent/tools/doc_generator.py + 4 WeasyPrint templates: real PDFs from session data, amber-highlighted pre-fills, blanks (never [NAME]/PLACEHOLDER), logged field sources; zip for "Download all"; head-less preview snippet - app/phases/documents.py: preview + evidence checklist (pre-checked from documents_available) + file list + Download all + Start over - nav: Recommendations "Prepare my documents" -> Documents; Start over -> intake - launch(allowed_paths=[tempdir]) so Gradio can serve the generated PDFs - tests: 8 document tests (real PDF text via pypdf 6.12.2, pinned one-before) Single LLM + UX fixes (from live testing): - one model end-to-end: MODEL_ID=lfm2.5:8b (fast ~2s, tool-calling + good multilingual); removed per-phase model split (no fallback, hackathon rule) - languages limited to those lfm2.5:8b handles well (probe-verified): English, French, Spanish, Portuguese, Arabic, Hindi, Chinese, Japanese, Korean, Russian - responder: free-text…f05e15f -
[T035-T043] Phase 3 — situation assessment (reasoning stream + real tools)
Hélder Monteiro +1: Codex- agent/tools/country_lookup.py: offline lookup from countries.json (enriched if present), flat schema (unhcrPresence, processingTimeMonths, acceptanceRate, primaryLanguage, requiredDocuments, legalAidOrgs, unhcrOffice, tier, warning); not_found instead of fabrication; PENDING stats surfaced as None (T036/SC-026) - agent/tools/web_search.py: real Tavily search via httpx; fails loudly w/o key or on API error (no fake results) (T035/SC-025) - app/prompts/assessment.md: 5-step scaffold (1951 + AU 1969 grounds, transit safety, find programmes, rank 2-3) + @@ASSESSMENT structured block (T038) - app/assessment_parse.py: parse grounds/risk/countries from the block - app/phases/assessment.py: facts sidebar (8 fields), live reasoning stream, progress bar, "Searching: …" tool chips; stream_assessment core runs the model with both tools, then attaches authoritative country_lookup data to ranked recommendations (origin excluded) into session.assessment (T037/T039/T040) - app/app.py…4270181 -
[T030-T034] Phase 2 — intake screen + language selection + theming
Hélder Monteiro +1: Codex- app/phases/intake.py: mockup-faithful intake (#phase-1) — topo backdrop, logo+wordmark+tagline, 8 language pills in native script, amber "Begin in <language>" primary, privacy trust chip. Single-select w/ click-to-deselect. - pure logic: select_language, begin_interview (ValueError w/o language), toggle_selection, begin_label — all unit-tested (T034) - intake -> interview navigation: Begin hides intake, reveals + streams the interview in the chosen language (language-aware bootstrap) - app/app.py: global theme/chrome overrides (hide Gradio footer, body bg, fonts, flatten default component boxes, focus rings); mount intake + hidden interview; removed standalone hero (intake owns the wordmark now) - interview.build(visible=...) so it can start hidden - scripts/validate_design_tokens.py: also scan intake/interview CSS modules Tests: 40 pass (incl real-model integration). Token validator PASS. Co-authored-by: Codex <noreply@openai.com>fa21080 -
[T017-T029] Phase 1 — agent loop + interview core
Hélder Monteiro +1: Codex- agent/loop.py: full turn cycle (already streamed); separate system prompt from persisted history (no accumulation); create_loop() session factory (T019) - app/prompts/interview.md: 4 sub-phase question bank + @@RESPONDER directive (T020) - app/prompt_loader.py: compose system + interview prompts (T021) - app/responder.py: parse @@RESPONDER -> ResponderSpec, lenient fallback - app/phases/interview.py: mockup-faithful progress rail, chat bubbles, thinking indicator, structured responder (choice/country/text), ghost "Save and continue later"; real per-delta streaming; turn_end sets responder mode; agent_end advances state (T022-T025) - app/countries.py: country selector choices from countries.json - app/design_tokens.py: align CSS var names to mockup (--primary/--bg/--r-md/ --s-md) + shadows/maxw from DESIGN §4/§5; app.py hero updated - app/app.py: mount interview, auto-start first question via demo.load Tests (33 pass): responder parse, event contracts (T028), loop isolation…e16f16c -
[T001-T016] Phase 0 — project setup: agent loop, state machine, Gradio skeleton
Hélder Monteiro +1: Codex- requirements.txt + pyproject.toml pinned one release before latest (gradio 6.15.2, weasyprint 68.1, httpx 0.28.0, ollama 0.6.1, litellm 1.87.1, pytest 9.0.2, pytest-asyncio 1.3.0) - agent/events.py: 8 typed AgentEvent dataclasses - agent/loop.py: pure-Python async AgentLoop (stream, tools, steer, abort, error-as-event); agent/tools/base.py AgentTool contract - app/state/session.py: forward-only interview state machine - app/app.py + app/design_tokens.py: Gradio skeleton, DESIGN.md :root tokens - app/prompts/system.md: Refuge case-worker persona - scripts/validate_design_tokens.py: T010 token validator - tests/unit: state machine (7) + loop ping (1) — all green Co-authored-by: Codex <noreply@openai.com>944f1ac