mirror of
https://github.com/hoshikawa2/agent_platform_oci.git
synced 2026-09-07 18:23:46 +00:00
123 lines
4.4 KiB
Python
123 lines
4.4 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
from types import SimpleNamespace
|
|
|
|
import pytest
|
|
|
|
from agent_framework.runtime.agent_runtime import AgentRuntimeMixin
|
|
from agent_framework.runtime.transaction_parameters import extract_transaction_parameters
|
|
|
|
|
|
class _Router:
|
|
def __init__(self, tool, rules=None):
|
|
self.registry = SimpleNamespace(get_tool=lambda name: tool if name == "tx_tool" else None)
|
|
self._rules = rules or {}
|
|
|
|
def parameter_extract_rules(self, tool_name):
|
|
return dict(self._rules)
|
|
|
|
|
|
class _Runtime(AgentRuntimeMixin):
|
|
def __init__(self, tool, rules=None):
|
|
self.tool_router = _Router(tool, rules)
|
|
|
|
|
|
class _CaptureLLM:
|
|
def __init__(self):
|
|
self.prompt = ""
|
|
|
|
async def ainvoke(self, messages, **kwargs):
|
|
self.prompt = messages[-1]["content"]
|
|
return json.dumps({"subject": "TIM CTRL Redes Sociais 8.0", "valor": None}, ensure_ascii=False)
|
|
|
|
|
|
def test_legacy_args_schema_remains_unchanged_without_description():
|
|
tool = SimpleNamespace(args_schema={"subject": "string", "valor": "number"}, requires=["subject", "valor"])
|
|
runtime = _Runtime(tool)
|
|
|
|
schema = runtime._transaction_parameter_schema("tx_tool", {"requires": ["subject", "valor"]})
|
|
|
|
assert schema == {"subject": "string", "valor": "number"}
|
|
|
|
|
|
def test_legacy_args_schema_is_enriched_from_mcp_mapping_description():
|
|
tool = SimpleNamespace(args_schema={"subject": "string", "valor": "number"}, requires=["subject", "valor"])
|
|
runtime = _Runtime(
|
|
tool,
|
|
{
|
|
"subject": {
|
|
"from": "message",
|
|
"strategy": "llm",
|
|
"description": "Nome do serviço, produto, item ou cobrança objeto da contestação.",
|
|
},
|
|
"valor": {
|
|
"from": "message",
|
|
"strategy": "llm",
|
|
"description": "Valor monetário explicitamente informado pelo cliente.",
|
|
},
|
|
},
|
|
)
|
|
|
|
schema = runtime._transaction_parameter_schema("tx_tool", {"requires": ["subject", "valor"]})
|
|
|
|
assert schema["subject"] == {
|
|
"type": "string",
|
|
"description": "Nome do serviço, produto, item ou cobrança objeto da contestação.",
|
|
}
|
|
assert schema["valor"] == {
|
|
"type": "number",
|
|
"description": "Valor monetário explicitamente informado pelo cliente.",
|
|
}
|
|
|
|
|
|
def test_enriched_args_schema_has_precedence_over_mcp_mapping_description():
|
|
tool = SimpleNamespace(
|
|
args_schema={
|
|
"subject": {"type": "string", "description": "Descrição definida no args_schema."},
|
|
"valor": {"type": "number"},
|
|
},
|
|
requires=["subject", "valor"],
|
|
)
|
|
runtime = _Runtime(
|
|
tool,
|
|
{
|
|
"subject": {"description": "Fallback que não deve sobrescrever."},
|
|
"valor": {"description": "Descrição de fallback para valor."},
|
|
},
|
|
)
|
|
|
|
schema = runtime._transaction_parameter_schema("tx_tool", {"requires": ["subject", "valor"]})
|
|
|
|
assert schema["subject"]["description"] == "Descrição definida no args_schema."
|
|
assert schema["valor"] == {"type": "number", "description": "Descrição de fallback para valor."}
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_extractor_prompt_uses_optional_semantic_descriptions_and_keeps_null_rule():
|
|
llm = _CaptureLLM()
|
|
extracted = await extract_transaction_parameters(
|
|
llm,
|
|
text="nao contratei TIM CTRL Redes Sociais 8.0",
|
|
tool_name="contestar_cobranca",
|
|
missing_parameters=["subject", "valor"],
|
|
known_arguments={},
|
|
parameter_schema={
|
|
"subject": {
|
|
"type": "string",
|
|
"description": "Nome do serviço, produto, item ou cobrança objeto da contestação.",
|
|
},
|
|
"valor": {
|
|
"type": "number",
|
|
"description": "Valor monetário explicitamente informado pelo cliente.",
|
|
},
|
|
},
|
|
tool_description="Executa contestação de cobrança.",
|
|
)
|
|
|
|
assert extracted == {"subject": "TIM CTRL Redes Sociais 8.0"}
|
|
assert "principalmente a descrição semântica quando disponível" in llm.prompt
|
|
assert "A ausência de tipo ou descrição NÃO impede a extração" in llm.prompt
|
|
assert "Em caso de dúvida razoável sobre a correspondência ou o valor, prefira null" in llm.prompt
|
|
assert "Nome do serviço, produto, item ou cobrança objeto da contestação." in llm.prompt
|