mqtt切换为远程服务器部署,优化简单指令解析时长
This commit is contained in:
@@ -0,0 +1,410 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import threading
|
||||
import unittest
|
||||
from copy import deepcopy
|
||||
|
||||
from cognitive_agent.application.codex_assistant import (
|
||||
CodexAssistantService,
|
||||
_VehicleAuthorization,
|
||||
_VehicleTurnContext,
|
||||
)
|
||||
|
||||
|
||||
UTTERANCE = "空调温度设置到23度,打开闪烁灯"
|
||||
|
||||
|
||||
def compiled_mixed_result() -> dict[str, object]:
|
||||
return {
|
||||
"request_id": "req-assistant-local-mixed",
|
||||
"utterance": UTTERANCE,
|
||||
"status": "processing",
|
||||
"phase": "commands_validated",
|
||||
"provider_used": "local_rules+infrared_local_rules",
|
||||
"execution_mode": "dry_run",
|
||||
"control_transport": "wired_can",
|
||||
"function_configs": {
|
||||
"native_climate": {
|
||||
"spec": {
|
||||
"domain": "climate",
|
||||
"operations": [
|
||||
{
|
||||
"id": "climate-temperature-1",
|
||||
"capability": "climate.set_temperature",
|
||||
"target": {"zone": "driver"},
|
||||
"parameters": {"temperature_c": 23},
|
||||
"parse_source": "local_rule",
|
||||
}
|
||||
],
|
||||
}
|
||||
},
|
||||
"self_extension": {
|
||||
"spec": {
|
||||
"domain": "self_extension",
|
||||
"operations": [
|
||||
{
|
||||
"id": "infrared-1",
|
||||
"capability": "infrared.emit",
|
||||
"target": {"device": "toy-001", "name": "闪灯玩具"},
|
||||
"parameters": {"action": "开启", "slot": 1},
|
||||
"parse_source": "local_rule",
|
||||
}
|
||||
],
|
||||
}
|
||||
},
|
||||
},
|
||||
"command_plans": {
|
||||
"self_extension": {
|
||||
"spec": {
|
||||
"domain": "self_extension",
|
||||
"commands": [
|
||||
{
|
||||
"operation_ref": "unrelated-operation",
|
||||
"message": "Native_0xBAD",
|
||||
"signals": {
|
||||
"debug_command": "must-not-cross-tool-boundary",
|
||||
"frame_id": "0xBAD",
|
||||
"data_hex": "DE AD BE EF",
|
||||
},
|
||||
},
|
||||
{
|
||||
"operation_ref": "infrared-1",
|
||||
"bus": "TCP",
|
||||
"message": "infrared.emit",
|
||||
"signals": {"slot": 1},
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
"native_climate": {
|
||||
"spec": {
|
||||
"domain": "climate",
|
||||
"commands": [
|
||||
{
|
||||
"operation_ref": "climate-temperature-1",
|
||||
"bus": "body_can",
|
||||
"message": "Native_0x1DE",
|
||||
"signals": {
|
||||
"debug_command": "ac temp driver 23",
|
||||
"frame_id": "0x1DE",
|
||||
"data_hex": "00 00 00 00 17 00 00 00",
|
||||
},
|
||||
}
|
||||
],
|
||||
}
|
||||
},
|
||||
},
|
||||
"trace_events": [
|
||||
{"stage": "intent_parse", "duration_ms": 2},
|
||||
{"stage": "context_resolve", "duration_ms": 1},
|
||||
{"stage": "domain_route", "duration_ms": 1},
|
||||
{"stage": "function_generate", "duration_ms": 2},
|
||||
{"stage": "schema_validate", "duration_ms": 1},
|
||||
{"stage": "compile", "duration_ms": 2},
|
||||
{"stage": "execute", "duration_ms": 999},
|
||||
],
|
||||
"raw_can": "must-not-cross-tool-boundary",
|
||||
}
|
||||
|
||||
|
||||
class ValidatedControlProjectionTest(unittest.TestCase):
|
||||
def test_projection_exposes_only_exact_display_commands(self) -> None:
|
||||
projection = CodexAssistantService._validated_control_payload(
|
||||
compiled_mixed_result()
|
||||
)
|
||||
|
||||
self.assertIsNotNone(projection)
|
||||
assert projection is not None
|
||||
commands = projection["validated_control_commands"]
|
||||
assert isinstance(commands, list)
|
||||
self.assertEqual(len(commands), 2)
|
||||
by_capability = {
|
||||
command["operation"]["capability"]: command for command in commands
|
||||
}
|
||||
climate = by_capability["climate.set_temperature"]
|
||||
infrared = by_capability["infrared.emit"]
|
||||
self.assertEqual(climate["actual_command"], "ac temp driver 23")
|
||||
self.assertEqual(
|
||||
climate["frames"],
|
||||
[
|
||||
{
|
||||
"label": "CAN1 帧",
|
||||
"value": "0x1DE · 00 00 00 00 17 00 00 00",
|
||||
}
|
||||
],
|
||||
)
|
||||
self.assertEqual(infrared["actual_command"], "infrared emit 1")
|
||||
self.assertEqual(
|
||||
infrared["frames"],
|
||||
[
|
||||
{
|
||||
"label": "GSCU1B TCP",
|
||||
"value": '{"action":"emit","data":{"no":1},"type":"infrared"}',
|
||||
}
|
||||
],
|
||||
)
|
||||
self.assertEqual(
|
||||
[event["stage"] for event in projection["trace_events"]],
|
||||
[
|
||||
"intent_parse",
|
||||
"context_resolve",
|
||||
"domain_route",
|
||||
"function_generate",
|
||||
"schema_validate",
|
||||
"compile",
|
||||
],
|
||||
)
|
||||
serialized = json.dumps(projection, ensure_ascii=False)
|
||||
self.assertNotIn("command_plans", serialized)
|
||||
self.assertNotIn("data_hex", serialized)
|
||||
self.assertNotIn("raw_can", serialized)
|
||||
self.assertNotIn("must-not-cross-tool-boundary", serialized)
|
||||
|
||||
def test_projection_drops_secrets_and_sensitive_nested_keys(self) -> None:
|
||||
result = compiled_mixed_result()
|
||||
secret = "projection-secret-token"
|
||||
climate_config = result["function_configs"]["native_climate"]
|
||||
climate_config["spec"]["domain"] = f"climate-{secret}"
|
||||
operation = climate_config["spec"]["operations"][0]
|
||||
operation["target"].update(
|
||||
{
|
||||
"api_key": "API-LEAK",
|
||||
"cookie": "COOKIE-LEAK",
|
||||
}
|
||||
)
|
||||
operation["parameters"].update(
|
||||
{
|
||||
"credential": "CRED-LEAK",
|
||||
"access_key": "ACCESS-LEAK",
|
||||
}
|
||||
)
|
||||
operation["parse_source"] = f"local-{secret}"
|
||||
result["command_plans"]["native_climate"]["spec"]["commands"][0][
|
||||
"signals"
|
||||
]["debug_command"] = f"ac temp driver 23 {secret}"
|
||||
|
||||
projection = CodexAssistantService._validated_control_payload(
|
||||
result,
|
||||
secret=secret,
|
||||
)
|
||||
|
||||
self.assertIsNotNone(projection)
|
||||
assert projection is not None
|
||||
serialized = json.dumps(projection, ensure_ascii=False)
|
||||
for forbidden in (
|
||||
secret,
|
||||
"API-LEAK",
|
||||
"COOKIE-LEAK",
|
||||
"CRED-LEAK",
|
||||
"ACCESS-LEAK",
|
||||
"api_key",
|
||||
"credential",
|
||||
"access_key",
|
||||
):
|
||||
self.assertNotIn(forbidden, serialized)
|
||||
climate = next(
|
||||
item
|
||||
for item in projection["validated_control_commands"]
|
||||
if item["operation"]["capability"] == "climate.set_temperature"
|
||||
)
|
||||
self.assertEqual(climate["domain"], "")
|
||||
self.assertNotIn("parse_source", climate["operation"])
|
||||
self.assertEqual(climate["operation"]["target"], {"zone": "driver"})
|
||||
self.assertEqual(
|
||||
climate["operation"]["parameters"],
|
||||
{"temperature_c": 23},
|
||||
)
|
||||
self.assertEqual(climate["actual_command"], "")
|
||||
|
||||
def test_projection_drops_operation_when_identity_contains_secret(self) -> None:
|
||||
result = compiled_mixed_result()
|
||||
secret = "projection-secret-token"
|
||||
operation = result["function_configs"]["native_climate"]["spec"][
|
||||
"operations"
|
||||
][0]
|
||||
operation["id"] = f"climate-{secret}"
|
||||
result["command_plans"]["native_climate"]["spec"]["commands"][0][
|
||||
"operation_ref"
|
||||
] = operation["id"]
|
||||
|
||||
projection = CodexAssistantService._validated_control_payload(
|
||||
result,
|
||||
secret=secret,
|
||||
)
|
||||
|
||||
self.assertIsNotNone(projection)
|
||||
assert projection is not None
|
||||
serialized = json.dumps(projection, ensure_ascii=False)
|
||||
self.assertNotIn(secret, serialized)
|
||||
self.assertEqual(
|
||||
[
|
||||
item["operation"]["capability"]
|
||||
for item in projection["validated_control_commands"]
|
||||
],
|
||||
["infrared.emit"],
|
||||
)
|
||||
|
||||
def test_duplicate_operation_refs_never_cross_configuration_boundaries(self) -> None:
|
||||
result = {
|
||||
"function_configs": {
|
||||
"native_climate": {
|
||||
"spec": {
|
||||
"domain": "climate",
|
||||
"operations": [
|
||||
{
|
||||
"id": "op-1",
|
||||
"capability": "climate.set_temperature",
|
||||
"target": {"zone": "driver"},
|
||||
"parameters": {"temperature_c": 23},
|
||||
}
|
||||
],
|
||||
}
|
||||
},
|
||||
"native_seat": {
|
||||
"spec": {
|
||||
"domain": "seat",
|
||||
"operations": [
|
||||
{
|
||||
"id": "op-1",
|
||||
"capability": "seat.set_heating",
|
||||
"target": {"zone": "passenger"},
|
||||
"parameters": {"level": 2},
|
||||
}
|
||||
],
|
||||
}
|
||||
},
|
||||
},
|
||||
"command_plans": {
|
||||
"native_seat": {
|
||||
"spec": {
|
||||
"domain": "seat",
|
||||
"commands": [
|
||||
{
|
||||
"operation_ref": "op-1",
|
||||
"bus": "seat_can0",
|
||||
"signals": {
|
||||
"debug_command": "seat passenger heat 2"
|
||||
},
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
projection = CodexAssistantService._validated_control_payload(result)
|
||||
|
||||
self.assertIsNotNone(projection)
|
||||
assert projection is not None
|
||||
commands = projection["validated_control_commands"]
|
||||
self.assertEqual(len(commands), 1)
|
||||
self.assertEqual(
|
||||
commands[0]["operation"]["capability"],
|
||||
"seat.set_heating",
|
||||
)
|
||||
self.assertEqual(commands[0]["actual_command"], "seat passenger heat 2")
|
||||
|
||||
def test_compiled_semantic_operation_is_kept_without_debug_command(self) -> None:
|
||||
result = deepcopy(compiled_mixed_result())
|
||||
climate_command = result["command_plans"]["native_climate"]["spec"][
|
||||
"commands"
|
||||
][0]
|
||||
climate_command["signals"].pop("debug_command")
|
||||
|
||||
projection = CodexAssistantService._validated_control_payload(result)
|
||||
|
||||
self.assertIsNotNone(projection)
|
||||
assert projection is not None
|
||||
climate = next(
|
||||
item
|
||||
for item in projection["validated_control_commands"]
|
||||
if item["operation"]["capability"] == "climate.set_temperature"
|
||||
)
|
||||
self.assertEqual(climate["actual_command"], "")
|
||||
self.assertEqual(
|
||||
climate["frames"][0]["value"],
|
||||
"0x1DE · 00 00 00 00 17 00 00 00",
|
||||
)
|
||||
|
||||
def test_direct_stream_emits_projection_before_progress_and_completion(self) -> None:
|
||||
client = type("UnavailableClient", (), {"available": False})()
|
||||
assistant = CodexAssistantService(client)
|
||||
events: list[dict[str, object]] = []
|
||||
|
||||
def execute_control(instruction, progress):
|
||||
self.assertEqual(instruction, UTTERANCE)
|
||||
result = compiled_mixed_result()
|
||||
progress(result)
|
||||
return {**result, "status": "succeeded"}
|
||||
|
||||
result = assistant.stream(
|
||||
UTTERANCE,
|
||||
conversation_id="conv-validated-projection",
|
||||
principal="local-test",
|
||||
history=[],
|
||||
emit=events.append,
|
||||
execute_control=execute_control,
|
||||
control_terms=("空调", "闪烁灯"),
|
||||
quick_control_commands=[UTTERANCE],
|
||||
)
|
||||
|
||||
event_types = [event["type"] for event in events]
|
||||
validated_index = event_types.index("validated_control_commands")
|
||||
self.assertLess(validated_index, event_types.index("action.progress"))
|
||||
self.assertLess(validated_index, event_types.index("action.completed"))
|
||||
self.assertLess(validated_index, event_types.index("answer.completed"))
|
||||
self.assertEqual(result["route"], "vehicle_control")
|
||||
self.assertEqual(result["success"], True)
|
||||
|
||||
safe_result = CodexAssistantService._safe_vehicle_result(
|
||||
compiled_mixed_result()
|
||||
)
|
||||
self.assertNotIn("command_plans", safe_result)
|
||||
self.assertNotIn("validated_control_commands", safe_result)
|
||||
|
||||
def test_agent_tool_path_queues_projection_for_the_browser_thread(self) -> None:
|
||||
client = type("UnavailableClient", (), {"available": False})()
|
||||
assistant = CodexAssistantService(client)
|
||||
request_token = "projection-secret-token"
|
||||
|
||||
def execute_control(instruction, progress):
|
||||
self.assertEqual(instruction, UTTERANCE)
|
||||
result = compiled_mixed_result()
|
||||
progress(result)
|
||||
return {**result, "status": "succeeded"}
|
||||
|
||||
context = _VehicleTurnContext(
|
||||
original_message=UTTERANCE,
|
||||
execute_control=execute_control,
|
||||
authorization=_VehicleAuthorization(
|
||||
instruction=UTTERANCE,
|
||||
reason="explicit_registered_control",
|
||||
),
|
||||
capability_snapshot={},
|
||||
query_capabilities=lambda _snapshot, _query: {},
|
||||
lock=threading.Lock(),
|
||||
)
|
||||
assistant._tool_contexts[request_token] = context
|
||||
|
||||
safe_result = assistant.execute_vehicle_control(request_token, UTTERANCE)
|
||||
|
||||
queued_events = []
|
||||
while not context.events.empty():
|
||||
queued_events.append(context.events.get_nowait())
|
||||
event_types = [event["type"] for event in queued_events]
|
||||
self.assertEqual(event_types[0], "action.started")
|
||||
self.assertLess(
|
||||
event_types.index("validated_control_commands"),
|
||||
event_types.index("action.progress"),
|
||||
)
|
||||
self.assertLess(
|
||||
event_types.index("validated_control_commands"),
|
||||
event_types.index("action.completed"),
|
||||
)
|
||||
self.assertNotIn("command_plans", safe_result)
|
||||
self.assertNotIn(request_token, json.dumps(queued_events, ensure_ascii=False))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user