项目文件夹

文件
2026-07-13 13:12:33 +08:00

183 行
5.5 KiB
Python

from __future__ import annotations
import json
import pytest
from opensquilla.skills.meta.clarify_autofill import (
autofill_required_clarify_fields,
)
from opensquilla.skills.meta.types import ClarifyField, ClarifyStepConfig
@pytest.mark.asyncio
async def test_autofill_fills_missing_required_fields_with_llm() -> None:
schema = ClarifyStepConfig(
mode="form",
fields=(
ClarifyField(name="age", type="int", required=True, min=6, max=12),
ClarifyField(
name="budget",
type="enum",
required=True,
choices=("50 元以内", "100 元以内", "200 元以内"),
),
ClarifyField(name="topic", type="string", required=False),
),
)
async def fake_chat(system: str, user: str) -> str:
assert "Return only one JSON object" in system
assert "age" in user
return json.dumps({"age": 9, "budget": "100 元以内"}, ensure_ascii=False)
filled, completed = await autofill_required_clarify_fields(
schema=schema,
filled_fields={"topic": "磁力迷宫"},
user_message="给 9 岁孩子做科学项目,预算 100 元以内。",
clarify_reply="",
llm_chat=fake_chat,
)
assert completed == {"age": 9, "budget": "100 元以内"}
assert filled == {"topic": "磁力迷宫", "age": 9, "budget": "100 元以内"}
@pytest.mark.asyncio
async def test_autofill_can_infer_optional_fields_for_empty_form_submission() -> None:
schema = ClarifyStepConfig(
mode="form",
fields=(
ClarifyField(name="topic", type="string", required=True),
ClarifyField(
name="age_band",
type="enum",
required=True,
choices=("PRE_K", "EARLY_GRADE", "TWEEN", "TEEN"),
),
ClarifyField(
name="deadline_days",
type="int",
required=False,
min=0,
max=365,
default=14,
),
ClarifyField(
name="language",
type="enum",
required=False,
choices=("en", "zh", "mixed"),
default="mixed",
),
),
)
async def fake_chat(_system: str, user: str) -> str:
payload = json.loads(user)
target_names = {
field["name"] for field in payload["fields_to_infer"]
}
assert target_names == {
"topic", "age_band", "deadline_days", "language",
}
return json.dumps(
{
"topic": "磁力迷宫",
"age_band": "EARLY_GRADE",
"deadline_days": 7,
"language": "zh",
},
ensure_ascii=False,
)
filled, completed = await autofill_required_clarify_fields(
schema=schema,
filled_fields={"deadline_days": 14, "language": "mixed"},
user_message="给 8 岁孩子做一个磁力迷宫项目。",
clarify_reply="",
llm_chat=fake_chat,
infer_optional_fields=True,
)
assert completed == {
"topic": "磁力迷宫",
"age_band": "EARLY_GRADE",
"deadline_days": 7,
"language": "zh",
}
assert filled == completed
@pytest.mark.asyncio
async def test_autofill_replaces_uninformative_required_answers() -> None:
schema = ClarifyStepConfig(
mode="form",
fields=(
ClarifyField(name="audience", type="string", required=True),
ClarifyField(name="budget", type="string", required=True),
),
)
async def fake_chat(_system: str, _user: str) -> str:
return '{"budget": "100 元以内"}'
filled, completed = await autofill_required_clarify_fields(
schema=schema,
filled_fields={"audience": "老师", "budget": "都可以"},
user_message="给小学生做一个科学项目。",
clarify_reply="budget: 都可以",
llm_chat=fake_chat,
)
assert completed == {"budget": "100 元以内"}
assert filled == {"audience": "老师", "budget": "100 元以内"}
@pytest.mark.asyncio
async def test_autofill_uses_safe_fallback_without_llm() -> None:
schema = ClarifyStepConfig(
mode="form",
fields=(
ClarifyField(
name="budget",
type="enum",
required=True,
choices=("50 元以内", "100 元以内"),
),
ClarifyField(name="age", type="int", required=True, min=6, max=12),
),
)
filled, completed = await autofill_required_clarify_fields(
schema=schema,
filled_fields={},
user_message="",
clarify_reply="",
llm_chat=None,
)
assert completed == {"budget": "50 元以内", "age": 6}
assert filled == {"budget": "50 元以内", "age": 6}
@pytest.mark.asyncio
async def test_autofill_string_fallback_follows_english_user_message() -> None:
schema = ClarifyStepConfig(
mode="form",
fields=(
ClarifyField(name="audience", type="string", required=True),
),
)
filled, completed = await autofill_required_clarify_fields(
schema=schema,
filled_fields={},
user_message="Please create a concise launch plan.",
clarify_reply="",
llm_chat=None,
)
assert completed == {"audience": "Automatically inferred from context"}
assert filled == {"audience": "Automatically inferred from context"}