更新功能
This commit is contained in:
@@ -9,7 +9,7 @@ from types import SimpleNamespace
|
||||
from unittest.mock import patch
|
||||
|
||||
from app.models.contracts import ChatMessage, MessagePart
|
||||
from app.services.agent_service import AgentService, CDSL_TOOL_SCHEMA, RepeatedToolArgumentsError, StrictToolSchemaError, TOOL_SCHEMAS, ToolArgumentsError, engine_capability_manifest, normalize_image_analysis, parse_tool_arguments, response_language_instruction, system_prompt, tools_for_model, user_visible_error_message
|
||||
from app.services.agent_service import AgentService, CDSL_TOOL_SCHEMA, RepeatedToolArgumentsError, StrictToolSchemaError, TOOL_SCHEMAS, ToolArgumentsError, engine_capability_manifest, get_repair_step_key, normalize_image_analysis, parse_tool_arguments, response_language_instruction, system_prompt, tools_for_model, user_visible_error_message
|
||||
from app.services.engine_service import load_engine
|
||||
from app.services.quality import QUALITY_RULE_TYPES
|
||||
from app.services.library import CdslLibrary
|
||||
@@ -79,6 +79,38 @@ class ParseToolArgumentsTests(unittest.TestCase):
|
||||
with self.assertRaisesRegex(ToolArgumentsError, "JSON object"):
|
||||
parse_tool_arguments('["not", "tool arguments"]')
|
||||
|
||||
|
||||
class RepairStepKeyTests(unittest.TestCase):
|
||||
def test_generation_and_patch_share_the_same_feature_step_budget(self) -> None:
|
||||
state = {
|
||||
"phase": "CDSL_REPAIR",
|
||||
"feature_plan": {
|
||||
"plan_id": "plan_1",
|
||||
"nodes": [
|
||||
{"id": "boss", "status": "ready"},
|
||||
{"id": "hole", "status": "waiting_for_selection"},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
self.assertEqual(
|
||||
get_repair_step_key(state, "generate_cdsl_model"),
|
||||
get_repair_step_key(state, "patch_cdsl_model"),
|
||||
)
|
||||
|
||||
def test_completed_nodes_do_not_change_the_active_step_key(self) -> None:
|
||||
state = {
|
||||
"phase": "CDSL_REPAIR",
|
||||
"feature_plan": {
|
||||
"plan_id": "plan_1",
|
||||
"nodes": [
|
||||
{"id": "base", "status": "completed"},
|
||||
{"id": "boss", "status": "ready"},
|
||||
],
|
||||
},
|
||||
}
|
||||
self.assertEqual(get_repair_step_key(state, "generate_cdsl_model"), "plan:plan_1:boss")
|
||||
|
||||
def test_recovers_only_the_known_premature_cdsl_wrapper_close(self) -> None:
|
||||
payload = parse_tool_arguments(
|
||||
'{"cdsl":{"schema":"cad.cdsl.llm.v1"}}, "summary":"fixed envelope"}',
|
||||
@@ -88,6 +120,28 @@ class ParseToolArgumentsTests(unittest.TestCase):
|
||||
self.assertEqual(payload["summary"], "fixed envelope")
|
||||
self.assertEqual(payload["cdsl"], {"schema": "cad.cdsl.llm.v1"})
|
||||
|
||||
def test_recovers_trailing_cdsl_metadata_after_a_complete_envelope(self) -> None:
|
||||
payload = parse_tool_arguments(
|
||||
'{"cdsl":{"schema":"cad.cdsl.llm.v1"},"summary":"fixed envelope",'
|
||||
'"assumptions":["metric"]}, "summary":"repeated envelope",'
|
||||
'"assumptions":["metric"]}',
|
||||
recover_cdsl_wrapper=True,
|
||||
)
|
||||
|
||||
self.assertEqual(payload, {
|
||||
"cdsl": {"schema": "cad.cdsl.llm.v1"},
|
||||
"summary": "fixed envelope",
|
||||
"assumptions": ["metric"],
|
||||
})
|
||||
|
||||
def test_rejects_a_second_cdsl_payload_after_a_complete_envelope(self) -> None:
|
||||
with self.assertRaisesRegex(ToolArgumentsError, "trailing content"):
|
||||
parse_tool_arguments(
|
||||
'{"cdsl":{"schema":"cad.cdsl.llm.v1"},"summary":"original",'
|
||||
'"assumptions":[]}, "cdsl":{"schema":"different"}}',
|
||||
recover_cdsl_wrapper=True,
|
||||
)
|
||||
|
||||
def test_does_not_recover_arbitrary_trailing_tool_content(self) -> None:
|
||||
with self.assertRaisesRegex(ToolArgumentsError, "trailing content"):
|
||||
parse_tool_arguments(
|
||||
@@ -123,6 +177,13 @@ class ParseToolArgumentsTests(unittest.TestCase):
|
||||
rule_type = verification["properties"]["rules"]["items"]["properties"]["type"]
|
||||
self.assertEqual(set(rule_type["enum"]), set(QUALITY_RULE_TYPES))
|
||||
|
||||
def test_verification_schema_requires_feature_for_feature_scoped_rules(self) -> None:
|
||||
generate_tool = next(tool for tool in TOOL_SCHEMAS if tool["function"]["name"] == "generate_cdsl_model")
|
||||
rule = generate_tool["function"]["parameters"]["properties"]["verification"]["properties"]["rules"]["items"]
|
||||
self.assertTrue(any("feature" in branch.get("then", {}).get("required", []) for branch in rule["allOf"]))
|
||||
self.assertIn("overall_width", rule["properties"]["type"]["enum"])
|
||||
self.assertIn("overall_height", rule["properties"]["type"]["enum"])
|
||||
|
||||
def test_strict_tool_schema_covers_generation_arguments(self) -> None:
|
||||
tools = tools_for_model(ProviderModel("strict-model", strict_tool_schema=True))
|
||||
strict_tools = [tool["function"]["name"] for tool in tools if tool["function"].get("strict")]
|
||||
|
||||
Reference in New Issue
Block a user