opensquilla--opensquilla
183 行
5.5 KiB
Python
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"}
|