Spaces:
Running on Zero
Running on Zero
| from lost_found_desk.conversation import build_summary, detect_language, plan_turn | |
| def test_detect_language(): | |
| assert detect_language("我掉了一個黑色水壺") == "zh" | |
| assert detect_language("I lost a black bottle") == "en" | |
| assert detect_language("カバンをなくしました") == "zh" # CJK family | |
| def _user(content): | |
| return {"role": "user", "content": content} | |
| def _assistant(content): | |
| return {"role": "assistant", "content": content} | |
| def test_unparseable_answers_progress_without_repeat(): | |
| """Regression: even answers we cannot machine-parse must advance the flow. | |
| The old English-keyword gate left such claims stuck on the same question | |
| forever. The brain tracks which attributes it already asked about, so it | |
| asks each at most once and then becomes ready — never repeating a question. | |
| """ | |
| conversation = [_assistant("seed")] | |
| collecting = [] | |
| final = None | |
| for msg in ["aaa", "bbb", "ccc", "ddd"]: | |
| plan = plan_turn(conversation, msg) # no inventory -> generic collection | |
| assert plan["assistant_message"] | |
| assert msg in plan["summary"] | |
| if plan["readiness_state"] == "collecting": | |
| collecting.append(plan["assistant_message"]) | |
| conversation += [_user(msg), _assistant(plan["assistant_message"])] | |
| final = plan | |
| assert len(collecting) == len(set(collecting)), "a question was repeated" | |
| assert final["readiness_state"] == "ready_for_staff_review" | |
| def test_chinese_attributes_are_understood(): | |
| """A Chinese description that already gives type+color shouldn't be re-asked | |
| for them — only the remaining distinguishing detail.""" | |
| plan = plan_turn([_assistant("seed")], "我掉了一個黑色的水壺", _TWO_BOTTLES) | |
| assert plan["readiness_state"] == "collecting" | |
| assert plan["target"] == "distinctive" | |
| def test_summary_accumulates_user_words(): | |
| conversation = [_assistant("seed"), _user("a navy hoodie"), _assistant("q")] | |
| assert build_summary(conversation, "with a small logo") == "a navy hoodie with a small logo" | |
| _TWO_BOTTLES = [ | |
| {"item_id": "b1", "status": "unclaimed", "caption": "black water bottle with a silver cap", "found_location": ""}, | |
| {"item_id": "b2", "status": "unclaimed", "caption": "blue water bottle with a dinosaur sticker", "found_location": ""}, | |
| ] | |
| def test_inventory_driven_disambiguation_asks_a_distinguishing_attribute(): | |
| # Two bottles that differ in color; the claimant only gave the type, so the | |
| # follow-up should target a distinguishing attribute, not a fixed script. | |
| plan = plan_turn([_assistant("seed")], "I lost a bottle", _TWO_BOTTLES) | |
| assert plan["readiness_state"] == "collecting" | |
| assert plan["target"] in {"color", "distinctive"} | |
| def test_specific_description_is_ready_immediately(): | |
| plan = plan_turn([_assistant("seed")], "a black water bottle with a silver cap and a sticker", _TWO_BOTTLES) | |
| assert plan["readiness_state"] == "ready_for_staff_review" | |
| def test_chinese_with_inventory_progresses_without_repeat(): | |
| conversation = [_assistant("seed")] | |
| seen = set() | |
| final = None | |
| for msg in ["我掉了一個水壺", "黑色的", "上面有貼紙"]: | |
| plan = plan_turn(conversation, msg, _TWO_BOTTLES) | |
| assert plan["assistant_message"] not in seen | |
| seen.add(plan["assistant_message"]) | |
| conversation += [_user(msg), _assistant(plan["assistant_message"])] | |
| final = plan | |
| assert final["readiness_state"] == "ready_for_staff_review" | |