Projeto do Agent Contas ORACLE

This commit is contained in:
2026-08-19 09:35:50 -03:00
commit 950a2bcd33
1366 changed files with 177217 additions and 0 deletions

View File

@@ -0,0 +1,132 @@
from __future__ import annotations
import json
from copy import deepcopy
from pathlib import Path
from typing import Any
import pytest
from agent_framework.workflows import FileWorkflowRepository, WorkflowActionRegistry, WorkflowRuntime
from agent_framework.workflows.models import WorkflowDefinition
ROOT = Path(__file__).resolve().parents[2]
CASES = ROOT / "tests" / "migration" / "data" / "workflow_yaml_cases"
def _load_cases():
return [json.loads(p.read_text(encoding="utf-8")) for p in sorted(CASES.glob("*.json"))]
def _contains_subset(expected: Any, observed: Any) -> bool:
if isinstance(expected, dict):
return isinstance(observed, dict) and all(
key in observed and _contains_subset(value, observed[key]) for key, value in expected.items()
)
if isinstance(expected, list):
return isinstance(observed, list) and len(expected) <= len(observed) and all(
_contains_subset(value, observed[index]) for index, value in enumerate(expected)
)
return expected == observed
class _DefinitionRepository:
def __init__(self, definition):
self.definition = definition
def get_active(self, name):
assert name == self.definition.name
return self.definition
def get_version(self, name, version):
assert (name, version) == (self.definition.name, self.definition.version)
return self.definition
def _normalized_expected_nodes(case):
nodes = list((case.get("expect") or {}).get("trace_nodes") or [])
# Runtime antigo repetia a action imediatamente anterior ao pause. O runtime
# novo deliberadamente não a repete para impedir side effects duplicados.
normalized = []
for node in nodes:
if normalized and normalized[-1] == node:
continue
normalized.append(node)
return normalized
@pytest.mark.asyncio
@pytest.mark.parametrize("case", _load_cases(), ids=lambda c: c["id"])
async def test_original_workflow_case_on_framework_runtime(case):
original = FileWorkflowRepository(ROOT / "workflows").get_version(case["workflow"], int(case["version"]))
raw = original.model_dump(by_alias=True)
registry = WorkflowActionRegistry()
calls = []
# No teste cada node recebe uma action exclusiva. Isso permite reproduzir
# exatamente os outputs configurados no caso JSON, mesmo quando dois nodes
# compartilham a mesma action de produção.
for node in raw["nodes"]:
node_id = node["id"]
real_action = node["action"]
test_action = f"__case__{node_id}"
node["action"] = test_action
async def handler(params, state, *, _node=node_id, _action=real_action):
cfgs = dict(case.get("actions") or {})
configured = cfgs.get(_node) if isinstance(cfgs.get(_node), dict) else cfgs.get(_action)
configured = configured if isinstance(configured, dict) else {}
calls.append({"node_id": _node, "action": _action, "params": deepcopy(params)})
if configured.get("success") is False:
raise RuntimeError(str(configured.get("error") or "falha configurada"))
return deepcopy(configured.get("output") or {"success": True})
registry.register(test_action, handler)
definition = WorkflowDefinition.model_validate(raw)
runtime = WorkflowRuntime(_DefinitionRepository(definition), actions=registry, checkpointer=None, allow_deterministic_fallback=True)
first = await runtime.arun(definition.name, deepcopy(case.get("input") or {}), version=definition.version)
start_expect = case.get("expect_start")
if isinstance(start_expect, dict):
if start_expect.get("status") == "WAITING_INPUT":
assert first.status == "PAUSED"
if "paused_at" in start_expect:
assert first.pause.get("node") == start_expect["paused_at"]
expected_input = first.pause.get("expected_input") or {}
if "expected_input_key" in start_expect:
assert expected_input.get("key") == start_expect["expected_input_key"]
if "allowed_values" in start_expect:
assert expected_input.get("allowed_values") == start_expect["allowed_values"]
final = first
resume = case.get("resume")
if isinstance(resume, dict):
final = await runtime.aresume(definition.name, first.execution_id, deepcopy(resume), version=definition.version)
expect = dict(case.get("expect") or {})
assert final.status == expect.get("status")
if "last_node" in expect:
assert final.state.get("current_node") == expect["last_node"]
# Data do runtime antigo era a união dos outputs. ``vars`` representa essa
# informação no runtime novo e é a fonte para referências $.vars.* do YAML.
flattened = {}
for value in (final.state.get("vars") or {}).values():
if isinstance(value, dict):
flattened.update(value)
if "data_subset" in expect:
assert _contains_subset(expect["data_subset"], flattened)
observed_nodes = [item.get("node") for item in final.trace if item.get("action") != "pause_resume"]
if "trace_nodes" in expect:
active_node_ids = {node.id for node in definition.nodes}
expected_nodes = [node for node in _normalized_expected_nodes(case) if node in active_node_ids]
assert observed_nodes == expected_nodes
for expected in expect.get("calls", []):
found = [c for c in calls if c["node_id"] == expected.get("node_id") and ("action" not in expected or c["action"] == expected["action"])]
assert found, expected
subset = expected.get("params_subset")
if subset is not None:
assert any(_contains_subset(subset, c["params"]) for c in found)