fix(v3.7.0): resolve issue #1429 #1490
@@ -1033,6 +1033,16 @@ iteration` and data corruption under concurrent plan execution. All public
|
||||
response format from the OpenCode API `/session/status` endpoint instead of an array.
|
||||
Workers now dispatch and verify correctly, preventing incorrect session deletion.
|
||||
|
||||
- **Actor compiler ignores `actor_ref` field on SUBGRAPH nodes** (#1429): Fixed the
|
||||
actor compiler (`src/cleveragents/actor/compiler.py`) to read `actor_ref` from the
|
||||
top-level `NodeDefinition.actor_ref` field instead of `node.config.get("actor_ref")`.
|
||||
Before this fix, `CompiledActor.metadata.subgraph_refs` was always empty and
|
||||
`NodeConfig.subgraph` on every SUBGRAPH node was always `None`, silently breaking all
|
||||
hierarchical/nested actor graph compositions. Added Behave regression tests covering
|
||||
subgraph compilation with `actor_ref` fields and Robot Framework integration tests
|
||||
verifying that `subgraph_refs` is correctly populated after compilation.
|
||||
|
||||
|
||||
---
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -54,3 +54,4 @@ Below are some of the specific details of various contributions.
|
||||
dict, so per-node LSP bindings specified via `lsp_binding:` YAML key are no longer silently
|
||||
dropped. Includes Behave BDD and Robot Framework regression tests.
|
||||
* HAL 9000 has contributed the config-actor combined-format support fix (PR #11232 / issue #11189): added ``_detect_nested_config_actor()``, ``_flatten_config_actor()``, and handling in ``ActorConfiguration.from_blob()`` to transparently flatten the nested ``config.actor`` block from both compact-string and nested-dict forms so v3 detection, schema validation, and canonicalisation see flat data — eliminating the ``"provider is required"`` crash.
|
||||
* HAL 9000 has contributed the actor compiler `actor_ref` field fix (issue #1429): corrected `_map_node()` and `compile_actor()` in `src/cleveragents/actor/compiler.py` to read `actor_ref` from the top-level `NodeDefinition.actor_ref` field instead of `node.config.get("actor_ref")`, resolving silent failures on all SUBGRAPH nodes where `subgraph_refs` was always empty and `NodeConfig.subgraph` was always `None`.
|
||||
|
||||
@@ -142,7 +142,8 @@ class SubgraphResolutionSuite:
|
||||
type=NodeType.SUBGRAPH,
|
||||
name="Sub",
|
||||
description="Subgraph ref",
|
||||
config={"actor_ref": "bench/inner"},
|
||||
config={},
|
||||
actor_ref="bench/inner",
|
||||
),
|
||||
]
|
||||
outer_edges = [EdgeDefinition(from_node="main", to_node="sub")]
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
Feature: Actor compiler reads actor_ref from NodeDefinition field
|
||||
|
|
||||
As a CleverAgents developer
|
||||
I want the actor compiler to read actor_ref from the NodeDefinition.actor_ref field
|
||||
So that SUBGRAPH nodes correctly populate NodeConfig.subgraph and metadata.subgraph_refs
|
||||
|
||||
Background:
|
||||
Given the actor compiler is available
|
||||
|
||||
# Issue #1429: _map_node() and compile_actor() were reading
|
||||
# node.config.get("actor_ref") instead of node.actor_ref, causing SUBGRAPH
|
||||
# nodes to silently lose their actor references during compilation.
|
||||
|
||||
@tdd_issue @tdd_issue_1429
|
||||
Scenario: Compiled SUBGRAPH node has subgraph field populated from actor_ref
|
||||
Given actor "test/outer-1429-a" has a subgraph node with actor_ref "test/inner-1429-a"
|
||||
And actor "test/inner-1429-a" has no subgraph nodes
|
||||
And a registry containing both actors
|
||||
When I compile actor "test/outer-1429-a" with the registry resolver
|
||||
Then the actor compilation should succeed
|
||||
And the compiled node "sub" should have subgraph set to "test/inner-1429-a"
|
||||
|
||||
@tdd_issue @tdd_issue_1429
|
||||
Scenario: Compiled actor metadata subgraph_refs populated from actor_ref field
|
||||
Given actor "test/outer-1429-b" has a subgraph node with actor_ref "test/inner-1429-b"
|
||||
And actor "test/inner-1429-b" has no subgraph nodes
|
||||
And a registry containing both actors
|
||||
When I compile actor "test/outer-1429-b" with the registry resolver
|
||||
Then the actor compilation should succeed
|
||||
And the actor subgraph_refs should map "sub" to "test/inner-1429-b"
|
||||
|
||||
@tdd_issue @tdd_issue_1429
|
||||
Scenario: Both NodeConfig.subgraph and subgraph_refs populated for SUBGRAPH node
|
||||
Given actor "test/outer-1429-c" has a subgraph node with actor_ref "local/code-reviewer"
|
||||
And actor "local/code-reviewer" has no subgraph nodes
|
||||
And a registry containing both actors
|
||||
When I compile actor "test/outer-1429-c" with the registry resolver
|
||||
Then the actor compilation should succeed
|
||||
And the compiled node "sub" should have subgraph set to "local/code-reviewer"
|
||||
And the actor subgraph_refs should map "sub" to "local/code-reviewer"
|
||||
@@ -0,0 +1,157 @@
|
||||
"""Robot Framework helper for tdd_actor_compiler_actor_ref_1429 tests.
|
||||
|
||||
Regression tests for issue #1429: the actor compiler must read actor_ref
|
||||
from NodeDefinition.actor_ref (a typed Pydantic field), not from
|
||||
node.config.get("actor_ref") (a raw dict lookup).
|
||||
|
||||
Two aspects are tested:
|
||||
subgraph-field -- _map_node() sets NodeConfig.subgraph from node.actor_ref
|
||||
subgraph-refs -- compile_actor() populates metadata.subgraph_refs from
|
||||
node_def.actor_ref
|
||||
|
||||
Usage:
|
||||
python robot/helper_tdd_actor_compiler_actor_ref_1429.py subgraph-field
|
||||
python robot/helper_tdd_actor_compiler_actor_ref_1429.py subgraph-refs
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_SRC = str(Path(__file__).resolve().parents[1] / "src")
|
||||
if _SRC not in sys.path:
|
||||
sys.path.insert(0, _SRC)
|
||||
|
||||
from cleveragents.actor.compiler import compile_actor # noqa: E402
|
||||
from cleveragents.actor.schema import ( # noqa: E402
|
||||
ActorConfigSchema,
|
||||
ActorType,
|
||||
EdgeDefinition,
|
||||
NodeDefinition,
|
||||
NodeType,
|
||||
RouteDefinition,
|
||||
)
|
||||
|
||||
_ACTOR_REF = "local/code-reviewer"
|
||||
|
||||
|
||||
def _make_outer_actor() -> ActorConfigSchema:
|
||||
"""GRAPH actor with one AGENT node and one SUBGRAPH node referencing _ACTOR_REF."""
|
||||
nodes = [
|
||||
NodeDefinition(
|
||||
id="start",
|
||||
type=NodeType.AGENT,
|
||||
name="Start",
|
||||
description="Start node",
|
||||
config={"agent": "default"},
|
||||
),
|
||||
NodeDefinition(
|
||||
id="sub",
|
||||
type=NodeType.SUBGRAPH,
|
||||
name="Sub",
|
||||
description="Subgraph node",
|
||||
config={},
|
||||
actor_ref=_ACTOR_REF,
|
||||
),
|
||||
]
|
||||
route = RouteDefinition(
|
||||
nodes=nodes,
|
||||
edges=[EdgeDefinition(from_node="start", to_node="sub")],
|
||||
entry_node="start",
|
||||
exit_nodes=["sub"],
|
||||
)
|
||||
return ActorConfigSchema(
|
||||
name="test/outer-1429",
|
||||
type=ActorType.GRAPH,
|
||||
description="Outer actor for #1429 regression test",
|
||||
provider="openai",
|
||||
model="gpt-4",
|
||||
route=route,
|
||||
)
|
||||
|
||||
|
||||
def _make_inner_actor() -> ActorConfigSchema:
|
||||
"""Simple leaf GRAPH actor with no subgraph nodes."""
|
||||
nodes = [
|
||||
NodeDefinition(
|
||||
id="leaf",
|
||||
type=NodeType.AGENT,
|
||||
name="Leaf",
|
||||
description="Leaf node",
|
||||
config={"agent": "default"},
|
||||
)
|
||||
]
|
||||
route = RouteDefinition(
|
||||
nodes=nodes,
|
||||
edges=[],
|
||||
entry_node="leaf",
|
||||
exit_nodes=["leaf"],
|
||||
)
|
||||
return ActorConfigSchema(
|
||||
name=_ACTOR_REF,
|
||||
type=ActorType.GRAPH,
|
||||
description="Inner actor for #1429 regression test",
|
||||
provider="openai",
|
||||
model="gpt-4",
|
||||
route=route,
|
||||
)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if len(sys.argv) < 2:
|
||||
print(
|
||||
"Usage: helper_tdd_actor_compiler_actor_ref_1429.py"
|
||||
" <subgraph-field|subgraph-refs>"
|
||||
)
|
||||
return 1
|
||||
|
||||
command = sys.argv[1]
|
||||
outer = _make_outer_actor()
|
||||
inner = _make_inner_actor()
|
||||
registry = {outer.name: outer, inner.name: inner}
|
||||
|
||||
if command == "subgraph-field":
|
||||
# Tests _map_node(): NodeConfig.subgraph must be set from node.actor_ref
|
||||
try:
|
||||
compiled = compile_actor(outer, actor_resolver=registry.get)
|
||||
node_cfg = compiled.nodes.get("sub")
|
||||
if node_cfg is None:
|
||||
print("tdd-1429-subgraph-field-fail: 'sub' not in compiled.nodes")
|
||||
return 1
|
||||
if node_cfg.subgraph != _ACTOR_REF:
|
||||
print(
|
||||
f"tdd-1429-subgraph-field-fail: "
|
||||
f"expected subgraph={_ACTOR_REF!r}, got {node_cfg.subgraph!r}"
|
||||
)
|
||||
return 1
|
||||
print(f"tdd-1429-subgraph-field-ok: subgraph={node_cfg.subgraph!r}")
|
||||
return 0
|
||||
except Exception as exc:
|
||||
print(f"tdd-1429-subgraph-field-error: {exc}")
|
||||
return 1
|
||||
|
||||
if command == "subgraph-refs":
|
||||
# Tests compile_actor(): metadata.subgraph_refs must be populated
|
||||
# from node_def.actor_ref
|
||||
try:
|
||||
compiled = compile_actor(outer, actor_resolver=registry.get)
|
||||
refs = compiled.metadata.subgraph_refs
|
||||
if refs.get("sub") != _ACTOR_REF:
|
||||
print(
|
||||
f"tdd-1429-subgraph-refs-fail: "
|
||||
f"expected subgraph_refs['sub']={_ACTOR_REF!r}, got {refs!r}"
|
||||
)
|
||||
return 1
|
||||
print(f"tdd-1429-subgraph-refs-ok: subgraph_refs={refs!r}")
|
||||
return 0
|
||||
except Exception as exc:
|
||||
print(f"tdd-1429-subgraph-refs-error: {exc}")
|
||||
return 1
|
||||
|
||||
print(f"Unknown command: {command}")
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,39 @@
|
||||
*** Settings ***
|
||||
|
HAL9001
commented
✅ NEW — Robot Framework integration test added. The 3 test cases cover the key scenarios with correct Note: Automated by CleverAgents Bot ✅ **NEW — Robot Framework integration test added.** The 3 test cases cover the key scenarios with correct `tdd_issue` and `tdd_issue_1429` tags. The separate Python helper module approach follows established patterns.
Note: `CI / integration_tests` is currently **FAILING** — investigate which tests are failing and fix before requesting re-review.
---
Automated by CleverAgents Bot
Supervisor: PR Review | Agent: pr-review-worker
|
||||
Documentation TDD regression tests for issue #1429: actor compiler reads
|
||||
... actor_ref from NodeDefinition.actor_ref field, not from the
|
||||
... raw node.config dict.
|
||||
...
|
||||
... Two compiler functions are covered:
|
||||
... _map_node() -- sets NodeConfig.subgraph
|
||||
... compile_actor() -- populates metadata.subgraph_refs
|
||||
Resource ${CURDIR}/common.resource
|
||||
Suite Setup Setup Test Environment
|
||||
Suite Teardown Cleanup Test Environment
|
||||
|
||||
*** Variables ***
|
||||
${HELPER} ${CURDIR}/helper_tdd_actor_compiler_actor_ref_1429.py
|
||||
|
||||
*** Test Cases ***
|
||||
NodeConfig subgraph Set From actor_ref Field In _map_node
|
||||
[Documentation] Verify _map_node() reads actor_ref from NodeDefinition.actor_ref
|
||||
... so that NodeConfig.subgraph is populated for SUBGRAPH nodes.
|
||||
... Before the fix for #1429 this always returned None because the compiler
|
||||
... used config.get("actor_ref") on a dict that never contained the key.
|
||||
[Tags] slow
|
||||
${result}= Run Process ${PYTHON} ${HELPER} subgraph-field cwd=${WORKSPACE}
|
||||
Log ${result.stdout}
|
||||
Log ${result.stderr}
|
||||
Should Be Equal As Integers ${result.rc} 0
|
||||
Should Contain ${result.stdout} tdd-1429-subgraph-field-ok
|
||||
|
||||
Metadata subgraph_refs Populated From actor_ref Field In compile_actor
|
||||
[Documentation] Verify compile_actor() reads actor_ref from NodeDefinition.actor_ref
|
||||
... so that metadata.subgraph_refs maps SUBGRAPH node IDs to referenced actor names.
|
||||
... Before the fix for #1429 subgraph_refs was always empty because the compiler
|
||||
... used node_def.config.get("actor_ref", "") on a dict that never contained the key.
|
||||
[Tags] slow
|
||||
${result}= Run Process ${PYTHON} ${HELPER} subgraph-refs cwd=${WORKSPACE}
|
||||
Log ${result.stdout}
|
||||
Log ${result.stderr}
|
||||
Should Be Equal As Integers ${result.rc} 0
|
||||
Should Contain ${result.stdout} tdd-1429-subgraph-refs-ok
|
||||
Reference in New Issue
Block a user
✅ NEW — Good test coverage. This feature file covers the key test cases with proper TDD tags (
@tdd_issue,@tdd_issue_1429). The scenarios are well-named and readable as living documentation per CONTRIBUTING.md Gherkin quality standards.However, note that the
CI / unit_testsgate is currently FAILING — please investigate which scenario(s) are failing and fix them before requesting re-review.Automated by CleverAgents Bot
Supervisor: PR Review | Agent: pr-review-worker