CoreRasurae 67972f0dc4
CI / lint (pull_request) Successful in 52s
CI / typecheck (pull_request) Successful in 1m42s
CI / security (pull_request) Successful in 1m28s
CI / quality (pull_request) Successful in 1m59s
CI / build (pull_request) Successful in 1m35s
CI / integration_tests (pull_request) Successful in 4m42s
CI / unit_tests (pull_request) Successful in 6m27s
CI / coverage (pull_request) Successful in 5m0s
CI / status-check (pull_request) Successful in 12s
CI / lint (push) Successful in 1m55s
CI / typecheck (push) Successful in 2m30s
CI / quality (push) Successful in 1m52s
CI / build (push) Successful in 1m41s
CI / security (push) Successful in 2m21s
CI / integration_tests (push) Successful in 3m38s
CI / unit_tests (push) Successful in 6m1s
CI / benchmark (pull_request) Failing after 23m37s
CI / coverage (push) Successful in 5m51s
CI / status-check (push) Successful in 7s
CI / benchmark (push) Failing after 20m20s
fix(graph): reject edges targeting unknown nodes during validation
A graph route edge whose source or target named a node absent from
nodes was accepted silently instead of raising ConfigurationError,
violating the load-time validation required by the Actor
Configuration Standard §11 preamble, §11.3.4 (graph edge source/
target must reference existing nodes), and §6.11.5 (edge validation).
The actor would execute every node up to a dangling target and exit
silently with partial output; a dangling source can never be
traversed at runtime, so it instead let the graph complete normally
while silently ignoring the structurally invalid edge.

The cleveractors.validation package already implements this check for
spec-level configs (agents + routes at the top level, _routes.py
_validate_graph_route), but create_executor()/Executor.execute() — the
router-facing API this project's TDD regression test and Robot
integration tests exercise — never calls into cleveractors.validation
at all. That package's actor-level path (_actor.py
_validate_graph_actor) also never checked edge endpoints. Rather than
wiring the full validate_dict()/validate_actor_config() dispatcher
into Executor.__init__ (which would additionally start enforcing
llm/tool/multi_actor structural checks never exercised via
create_executor() before, an unrelated behavior change/regression
risk), the fix adds a narrowly-scoped _validate_graph_edge_endpoints()
helper in runtime_dispatch.py, called from both _execute_graph() and
_execute_graph_stream() immediately after pg_nodes/pg_edges are built
from either the legacy route={} or v2.0 routes={main:{}} config shape
— and before the agent-creation loop, so a malformed graph never
instantiates an agent or processes a message (§12.1 lifecycle
ordering). start/end/START/END are always accepted as valid endpoints
regardless of whether they appear in the declared nodes mapping, since
PureLangGraph._initialize_nodes() auto-injects them and
_analyze_graph() normalizes the uppercase spellings (§6.2.1, §6.4).
The cleveractors.validation package's existing (unwired) spec-level
edge check is left as-is per its own scope — extending it further is
unrelated to this actor-level runtime bug and is preserved rather than
removed.

Removes @tdd_expected_fail from the two issue #91 regression scenarios
now that the fix makes them pass unconditionally (leaving @tdd_issue/
@tdd_issue_91 as permanent regression guards), and adds four new
scenarios: an edge targeting the auto-injected END node, an edge
sourced from the auto-injected START node, a fully valid graph, and
(per hurui200320's PR review) a streaming-path counterpart of the
dangling-target scenario — all per issue #89's acceptance criteria.
Adds three Robot integration test cases to
email_graph_negative_tests.robot (reusing the existing EmailGraphLib
rather than a new library) covering the same dangling-target,
dangling-source, and END-normalization behavior end-to-end through
create_executor().

Addresses the sole (Minor) finding from hurui200320's review of this
PR: _validate_graph_edge_endpoints() is called from both
_execute_graph() and _execute_graph_stream(), but the original tests
only drove the non-streaming execute() path, leaving
_execute_graph_stream()'s distinct billing-integrity wrapper (the
try/except around config normalization that populates
executor.last_result with a <no_llm> placeholder before re-raising
ConfigurationError) unverified. The new scenario drives
Executor.execute_stream() to exhaustion against the same
dangling-edge-target config, asserting the ConfigurationError
propagates before any token is yielded and that executor.last_result
is populated with the billing-integrity placeholder.

ISSUES CLOSED: #89
Refs: #91, #92
2026-08-04 20:15:28 +01:00
2026-05-26 21:45:54 +01:00
2026-05-26 21:45:54 +01:00
2026-05-26 21:45:54 +01:00
2026-05-26 21:45:54 +01:00

CleverActors

CleverActors is the reactive agent framework used by CleverAgents and CleverRouter.

It provides a Python library that lets a host application:

  • Parse CleverAgents v2 YAML configuration files (with Jinja2 templates and ${ENV_VAR} interpolation).
  • Validate configuration against the built-in schema validator.
  • Create reactive agent networks with RxPy streams, LangGraph graphs, or hybrid pipelines of both.
  • Run single-shot prompts, interactive CLI sessions, or stream-based processing via the ReactiveCleverAgentsApp orchestrator.

Install

pip install "cleveractors @ git+https://git.cleverthis.com/cleverlibre/cleveractors@master"

Quick start

from cleveractors import ReactiveCleverAgentsApp

app = ReactiveCleverAgentsApp(config_files=["config.yaml"])
result = await app.run_single_shot("Hello, agents!")
print(result)

Using agents directly

from cleveractors import Agent
from cleveractors.agents.llm import LLMAgent

agent = LLMAgent(
    name="assistant",
    config={"provider": "openai", "model": "gpt-4o", "system_prompt": "Be helpful."},
)
response = await agent.process_message("What is 2+2?")
print(response)

LangGraph workflows

from cleveractors.langgraph import LangGraph, Node, NodeType, GraphState

graph = LangGraph(name="my_workflow", config={})
graph.add_node(Node(name="start", node_type=NodeType.AGENT, agent="assistant"))
graph.add_node(Node(name="end", node_type=NodeType.END))
graph.add_edge("start", "end")
result = await graph.execute({"message": "Hello"})

Reactive stream routing

from cleveractors.reactive.stream_router import ReactiveStreamRouter, StreamType

router = ReactiveStreamRouter()
stream = router.create_stream({"name": "pipeline", "type": StreamType.HOT})
router.send_message("pipeline", "Process this message")

Package structure

Module Purpose
cleveractors Top-level exports: Agent, ContextManager, ReactiveCleverAgentsApp, CleverAgentsException
cleveractors.agents Agent implementations: LLMAgent, ToolAgent, CompositeAgent, ChainAgent, AgentFactory
cleveractors.core Core framework: ReactiveCleverAgentsApp, ConfigurationManager, ProgressBarManager, exceptions
cleveractors.langgraph LangGraph integration: LangGraph, PureLangGraph, Node, GraphState, StateManager, RxPyLangGraphBridge
cleveractors.reactive RxPy streams: ReactiveStreamRouter, StreamMessage, RouteConfig, ReactiveConfigParser
cleveractors.templates Jinja2+YAML template system: BaseTemplate, TemplateRegistry, AgentTemplate, GraphTemplate, StreamTemplate

Key exports

from cleveractors import Agent, ContextManager, ReactiveCleverAgentsApp, CleverAgentsException
from cleveractors.core.exceptions import ConfigurationError, TemplateError, RoutingError, ExecutionError
from cleveractors.core.config import ConfigurationManager
from cleveractors.agents.factory import AgentFactory
from cleveractors.langgraph import LangGraph, Node, NodeType, GraphState, StateManager
from cleveractors.langgraph.pure_graph import PureLangGraph, create_pure_langgraph
from cleveractors.reactive.stream_router import ReactiveStreamRouter, StreamType, StreamMessage
from cleveractors.templates import BaseTemplate, TemplateType, TemplateParameter, TemplateRegistry

License

MIT — see LICENSE.

See also CleverAgents Operations Code (CONTRIBUTING) for commit, PR, and testing conventions.

S
Description
CleverActors — pure Python library for declarative actor definitions: YAML schema, Jinja2 preprocessing, validation, and LangGraph compilation. Extracted from cleveragents-core.
Readme 5.7 MiB
Languages
Python 81.2%
Gherkin 16.4%
RobotFramework 2.1%
Shell 0.3%