mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-08-10 16:32:28 +00:00
fix(flow): clarify conversational route/handler name collision errors (#6825)
* fix(flow): clarify route/handler name collision validation errors
When @listen(...) includes the handler's own name, FlowDefinition validation
fails. This change improves the error text and how it surfaces for Python
Flow classes.
What changed
- _self_listen_error in flow_definition.py: two message variants (conversational
vs default), both include the listen condition
- build_flow_definition in dsl/_utils.py: wraps FlowDefinition ValidationError
with the Python Flow class name
- Tests for declarative and DSL-built flows; docs follow in a separate commit
When each error surfaces
1. Conversational message — FlowDefinition validation when
conversational.enabled is true and listen references the handler name.
Example: @listen("create_video") on def create_video in a conversational flow.
Surfaces via:
- FlowDefinition.from_declaration(dict/yaml) → pydantic ValidationError for
FlowDefinition (Value error, methods.create_video.listen listen condition...)
- MyFlow.flow_definition() / MyFlow() → ValueError Invalid flow definition
for MyFlow: ... (wrapped by pydantic as ValidationError for MyFlow on
instantiation)
2. Default (non-conversational) message — same trigger check when the flow is
not conversational. Example: @listen("publish") on def publish.
Surfaces via the same paths as (1).
3. Class-name wrapper — only on the Python DSL path when build_flow_definition
catches FlowDefinition ValidationError. Prepends Invalid flow definition for
{ClassName}: to the underlying message from (1) or (2). Does not apply to
from_declaration without a Flow class.
* docs(flow): explain conversational handler naming vs route labels
Document why @listen route labels must differ from handler method names and
recommend the handle_* naming pattern.
* docs(cli): warn against matching @listen labels to handler names
Add AGENTS.md guidance for crew and flow scaffolding so coding assistants
do not name handlers the same as their @listen route or event labels.
* docs(cli): clarify @listen self-reference fails at validation
Document that matching @listen labels to handler names raises a validation
error at flow instantiation, and that the runtime loop only occurs if
validation is bypassed.
This commit is contained in:
@@ -627,6 +627,26 @@ class MyFlow(Flow):
|
||||
| `@listen(method)` | Triggers when specified method completes. Receives output as argument |
|
||||
| `@router(method)` | Conditional branching. Returns string labels that trigger `@listen("label")` |
|
||||
|
||||
### `@listen` labels vs handler names
|
||||
|
||||
The string in `@listen("...")` is an **event or route label**, not the Python method name. Router return values, route labels, and method completion events share one trigger namespace.
|
||||
|
||||
**Never** use the same name for the `@listen` label and the handler method:
|
||||
|
||||
```python
|
||||
# ❌ Wrong — raises a validation error when the flow is instantiated
|
||||
@listen("create_video")
|
||||
def create_video(self):
|
||||
...
|
||||
|
||||
# ✅ Correct — distinct handler name (handle_* prefix is a common pattern)
|
||||
@listen("create_video")
|
||||
def handle_create_video(self):
|
||||
...
|
||||
```
|
||||
|
||||
If validation were bypassed, matching names would also cause the handler to re-trigger itself in a loop at runtime. This applies to all flows. It is especially common in **conversational flows** (`conversational = True`), where `@listen("...")` is a router intent name — do not name the handler after the route it serves.
|
||||
|
||||
### Structured State
|
||||
```python
|
||||
from pydantic import BaseModel
|
||||
@@ -1148,3 +1168,4 @@ crewai run # Execute
|
||||
- Using `process=Process.hierarchical` without setting `manager_llm` or `manager_agent`
|
||||
- Circular delegation: set `allow_delegation=False` on specialist agents
|
||||
- Not installing tools package: `uv add crewai-tools`
|
||||
- **Matching `@listen("label")` to the handler method name** — raises a validation error at flow instantiation; would re-trigger in an infinite loop at runtime only if validation is bypassed. Use a different method name (e.g. `handle_create_video` for `@listen("create_video")`)
|
||||
|
||||
@@ -39,8 +39,8 @@ Pick the simplest action that does the job.
|
||||
- `state` is the initial shared data shape. Action results do not automatically merge into `state`.
|
||||
- Read method results with `outputs.method_name` after that method can run.
|
||||
- `listen` targets a method name or a router-emitted event name.
|
||||
- Methods must not listen to their own method name.
|
||||
- Method names and emitted event names share one namespace. Avoid reusing the same string for both unless the user explicitly wants that.
|
||||
- Methods must not listen to their own method name — including when the `listen` value is a route label that matches the method name (e.g. `listen: create_video` on method `create_video`).
|
||||
- Method names and emitted event names share one namespace. Do not reuse the same string for a method's `listen` target and its method name.
|
||||
- Use `router: true` plus `emit` when one method chooses between named branches.
|
||||
- A router action must return exactly one emitted event string. It must not return JSON, a list, or an explanation.
|
||||
- Use `start: true` for the single entrypoint.
|
||||
@@ -107,8 +107,8 @@ Dynamic value rules:
|
||||
- Do not make `do` a list.
|
||||
- Do not use CEL `+` to build text in action mappings. Keep the text literal and insert each dynamic value with `${...}`.
|
||||
- Do not reference `outputs.some_method` before `some_method` can run.
|
||||
- Do not set a method's `listen` to its own method name.
|
||||
- Do not use the same string for an emitted event and a method name unless the user asks for it.
|
||||
- Do not set a method's `listen` to its own method name (including matching route labels such as `listen: create_video` on method `create_video`).
|
||||
- Do not use the same string for a method's `listen` target and its method name.
|
||||
- Do not use `emit` without `router: true`.
|
||||
- Do not rely on crew action-level `inputs` alone to ground agent behavior. Inputs that do not match placeholders are effectively unused by the prompt.
|
||||
- Do not ask agents to infer missing facts when accuracy matters. Tell them to mark missing dates, amounts, offers, logs, or constraints as unknown.
|
||||
|
||||
Reference in New Issue
Block a user