Skip to content

Commit 57b39b1

Browse files
committed
fix(job_agent): keep multi-word tags when parsing LLM tag:score output
1 parent e419f77 commit 57b39b1

2 files changed

Lines changed: 65 additions & 1 deletion

File tree

job_agent.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,10 @@
180180
"技术": ["工程能力", "系统设计"],
181181
}
182182

183-
_TAG_SCORE_RE = re.compile(r"([^::\s]+?)\s*[::]\s*([1-5])(?=\s|$)")
183+
# Allow spaces inside a tag so a multi-word skill like "Machine Learning" is
184+
# captured whole, but stop at a newline / comma so we don't run across the
185+
# boundary between two tags. The captured tag is .strip()-ed by the caller.
186+
_TAG_SCORE_RE = re.compile(r"([^::\n,,]+?)\s*[::]\s*([1-5])(?=\s|$)")
184187

185188

186189
def parse_llm_response(reply: str, valid_tags: Set[str]) -> List[Tuple[str, int]]:

tests/test_job_agent.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from job_agent import (
2+
deduplicate,
3+
format_skill_string,
4+
normalize_text,
5+
parse_llm_response,
6+
)
7+
8+
_VALID = {"Python", "Machine Learning", "Data Analysis", "SQL"}
9+
10+
11+
def test_parse_keeps_multi_word_tags():
12+
# A multi-word skill like "Machine Learning" must be captured whole, not
13+
# truncated to its last word (which wouldn't be in the tag set).
14+
parsed = parse_llm_response(
15+
"Python:5\nMachine Learning:4\nData Analysis:3", _VALID
16+
)
17+
assert parsed == [("Python", 5), ("Machine Learning", 4), ("Data Analysis", 3)]
18+
19+
20+
def test_parse_handles_multiple_tags_on_one_line():
21+
parsed = parse_llm_response("Python:5 Machine Learning:4", _VALID)
22+
assert parsed == [("Python", 5), ("Machine Learning", 4)]
23+
24+
25+
def test_parse_accepts_fullwidth_colon():
26+
parsed = parse_llm_response("SQL:2", _VALID)
27+
assert parsed == [("SQL", 2)]
28+
29+
30+
def test_parse_drops_unknown_and_out_of_range():
31+
# Unknown tags and scores outside 1-5 are ignored.
32+
parsed = parse_llm_response("Unknown:5\nPython:9\nPython:4", _VALID)
33+
assert parsed == [("Python", 4)]
34+
35+
36+
def test_parse_dedupes_keeping_first():
37+
parsed = parse_llm_response("Python:5\nPython:2", _VALID)
38+
assert parsed == [("Python", 5)]
39+
40+
41+
def test_parse_strips_markdown_emphasis():
42+
parsed = parse_llm_response("**Python**:5", _VALID)
43+
assert parsed == [("Python", 5)]
44+
45+
46+
def test_parse_empty_returns_empty():
47+
assert parse_llm_response("", _VALID) == []
48+
49+
50+
def test_normalize_text_strips_whitespace_and_lowercases():
51+
assert normalize_text(" Hello World ") == "helloworld"
52+
assert normalize_text(None) == ""
53+
assert normalize_text(123) == "123"
54+
55+
56+
def test_deduplicate_preserves_order_and_skips_empty():
57+
assert deduplicate(["a", "b", "a", "", "c", "b"]) == ["a", "b", "c"]
58+
59+
60+
def test_format_skill_string_matches_csv_shape():
61+
assert format_skill_string([("Python", 5), ("SQL", 3)]) == "Python , 5 , AI | SQL , 3 , AI"

0 commit comments

Comments
 (0)