Commit Graph

20 Commits

Author SHA1 Message Date
João Moura
6b6a39d503 fix(events): Improve coding agents instructions (#7447)
* feat: scaffold project with assistant instruction files

- Updated project creation to include `CLAUDE.md` and `GEMINI.md` that import `AGENTS.md`, ensuring consistent guidance across coding assistants.
- Implemented utility functions to copy assistant instruction files during project setup.
- Enhanced documentation in `AGENTS.md` to emphasize the importance of keeping telemetry enabled for optimal performance.
- Added tests to verify the correct scaffolding of assistant instruction files and their contents.

* fix(cli): neutral observability guidance in scaffolded AGENTS.md

- State the observability rule as the user's decision, never a fix for
  console warnings, speed, or a "clean" configuration
- Rewrite the AMP section as built-in capabilities: no "free",
  "proactively", "sales pitch", or scripted pitches
- Turn the research mandate into a list of sources to consult when
  version details matter
- Retarget the scaffold tests to the new wording

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fix(cli): scaffold assistant files for JSON crews and harden telemetry tests

- create_json_crew, the default `crewai create crew` path, now copies
  AGENTS.md, CLAUDE.md and GEMINI.md; AGENTS.md documents the JSON layout
- span helper no longer depends on OTEL_SDK_DISABLED being popped by an
  earlier test; thread-scope test stops its worker before leaving the mock
- single import style in the shutdown test

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 02:07:57 -03:00
Fang Kaiqi
f5db5a1788 docs: point prompt-template link at its current path (#7101)
Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-02 10:21:40 +05:30
Ran Shemtov
a35fbc864d docs: update channels guide to current copilotkit channels api (#7016)
* docs: update channels guide to current copilotkit channels api

* docs: translate channels and frontend overview guides to ar, ko, pt-BR

---------

Co-authored-by: Lorenze Jay <63378463+lorenzejay@users.noreply.github.com>
2026-08-31 15:47:58 +00:00
chenshiyang
265697b6f8 docs: refresh retired Gemini model ids (#7003)
Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-08-31 10:43:31 -03:00
Lorenze Jay
f90d37b4ac feat(flow): promote conversational flows to stable (#7107)
Move the canonical API into crewai.flow while preserving experimental imports and declarative references through compatibility aliases.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-27 23:06:57 +05:30
Vidit Ostwal
56e0e85a81 [OSS-115] Persist custom conversational replies after fallback append (#7026)
* fix(flows): persist custom conversational replies after fallback append

Custom @listen routes that only return a public string were appended after kickoff, so @persist snapshots missed the assistant turn. Snapshot again from the same persist path once the fallback writes state.messages.

* test(flows): cover @persist restore of custom conversational replies

Add regression coverage for custom @listen returns across fresh Flow instances, no double-append on built-in converse, and a single user/assistant message-added event.

* docs: note that public listen returns persist as assistant replies
2026-08-26 09:41:28 -07:00
Lorenze Jay
a9cb0bdf02 Lorenze/deprecate/answer from history (#7105)
* feat(flows): enhance conversational flow documentation and APIs

- Updated the description to clarify the use of `handle_turn` and structured streaming in multi-turn chat applications.
- Added a warning about the experimental nature of the conversational features.
- Improved the overview section to include structured streaming and refined the explanation of session handling.
- Enhanced the API documentation for `handle_turn`, `stream_turn`, and `chat` methods, emphasizing their roles in conversational flows.
- Clarified the turn lifecycle and the handling of user messages within the flow.
- Updated examples to reflect changes in message handling and session tracing.
- Ensured consistency across language versions in the documentation.

* feat(flow): deprecate answer_from_history route

Guide conversational flows toward the existing converse route while preserving compatibility warnings and schema metadata.

Co-authored-by: Cursor <cursoragent@cursor.com>

* stacklevel=3 raising it higher

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-25 11:01:22 +05:30
João Moura
500ebc7a68 feat(flow): let a declaration name the router's response format (#7063)
* feat(flow): let a declaration name the router's response format

`conversational.router.response_format` was typed `Any` and dropped with a
warning, because `_router_response_format` hands its value straight to
`llm.call(response_format=...)`, which needs a real class. So the router always
used its synthesized fallback: `intent: str` with the route labels only in a
field description.

The field now takes the same `{"python": "module.path.Class"}` shape a crew
agent's `response_format` uses, resolved through the same
`_resolve_model_class`. That brings the project-root containment with it -- a
declaration cannot reach outside the project to import code -- and gives the
router a `Literal[...]` of the real route labels instead of a bare string.

The DSL projection now emits that shape too, so a live class on a Python flow
round-trips as `{"python": ...}` rather than an opaque `{"ref": ...}` that
nothing could reload.

A bare `module:qualname` ref is now a load-time validation error instead of
being silently discarded; the test that pinned the old drop-with-warning
behavior is updated to assert that.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(flow): do not project a response format that cannot be reloaded

`_python_reference` emitted a dotted path for any class, including two that
cannot be imported back: a non-Pydantic class, and one defined inside a
function, whose `__qualname__` carries `<locals>`. The definition then held a
ref that only failed when something tried to resolve it.

Both are dropped at projection time with a warning naming why, so a reload
falls back to the synthesized response format. The live class still drives the
running flow; only the projection omits it.

Found by CodeRabbit on #7063.

* test(flows): assert the response_format omission warnings

The projection tests only checked for None, so removing the warning that tells
an author their response_format was dropped would still pass.

Found by CodeRabbit on #7063.

* fix(flows): only project a response_format ref that imports back

The check rejected <locals> classes but still emitted a path for a nested one.
The loader splits a ref on its last dot, so module.Outer.Route resolves
module.Outer as a module that does not exist - proven: reload raised
JSONProjectError. A create_model() class held only in a local is unreachable
the same way.

Projection now confirms module.qualname resolves back to the class, against the
already-imported module so it never triggers an import.

Found by CodeRabbit on #7063.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-24 13:53:15 -07:00
Lorenze Jay
090633737c feat(flows): enhance conversational flow documentation and APIs (#7104)
- Updated the description to clarify the use of `handle_turn` and structured streaming in multi-turn chat applications.
- Added a warning about the experimental nature of the conversational features.
- Improved the overview section to include structured streaming and refined the explanation of session handling.
- Enhanced the API documentation for `handle_turn`, `stream_turn`, and `chat` methods, emphasizing their roles in conversational flows.
- Clarified the turn lifecycle and the handling of user messages within the flow.
- Updated examples to reflect changes in message handling and session tracing.
- Ensured consistency across language versions in the documentation.
2026-08-24 11:26:31 -07:00
João Moura
4718b190d1 fix(cli): open the conversational TUI for a declarative chat flow (#7060)
* fix(cli): open the conversational TUI for a declarative chat flow

`crewai run` refused a declarative conversational flow and told the user to
drive it from Python. That was wrong: the conversational TUI already exists and
already does this job. `CrewRunApp(conversational=True)` renders a chat pane and
drives `handle_turn` per message (crew_run_tui.py:833-935), and
`kickoff_flow._run_conversational_flow_tui` launches it for a Python
conversational Flow.

A declaration-built flow satisfies everything that TUI needs -- `handle_turn`,
a settable `defer_trace_finalization`, and `finalize_session_traces()` -- so it
now routes there instead of exiting.

A chat loop still needs a terminal. A headless run (`is_interactive()` false,
which folds in CREWAI_DMN) says what it would have needed rather than kicking
off a single turn and presenting that as the whole conversation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(cli): do not send a human-feedback chat flow to the Textual TUI

A declaration can carry both a `conversational:` block and a method with
`human_feedback:` -- verified, both predicates return True on the same flow.
Routing it to the chat TUI hangs: the runtime collects feedback with a blocking
`input()` (flow/runtime/__init__.py:3719) that Textual cannot service, so the
prompt is never shown. The STEPS TUI already declines these for exactly this
reason. Such a flow now falls back to the terminal REPL, which can prompt.

Also updates the guide in en/ar/ko/pt-BR: it still said `crewai run` has no
chat loop and exits, which is now the opposite of what the CLI does.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(cli): reject --inputs on a conversational flow instead of dropping it

The conversational branch returns before `_resolve_flow_inputs`, and the TUI
calls `handle_turn(message)` -- which owns the kickoff inputs, passing
`{"id": session_id}` itself. So any `--inputs` value was silently discarded and
the conversation ran as if it had been applied. It now errors, and says that
resuming a session by id is not wired up yet rather than implying it worked.

Also corrects the Arabic guide: `مُوجّه محجوز` reads as "reserved router", not
the blocking prompt it describes.

Both found by CodeRabbit on #7060.

* fix(cli): document the conversational routing exceptions

Three review follow-ups:

- The Arabic guide read خدمته (masculine) against the feminine
  مُطالبة introduced by the last fix.
- Both docstrings described a routing path that now has exceptions: a
  conversational declaration rejects --inputs and skips state-schema
  resolution, and a human-feedback one uses the terminal REPL.
- The --inputs rejection test accepted SystemExit(0); it now pins code 1.

Found by CodeRabbit on #7060.

* fix(cli): reject --inputs on a chat flow even when it parses empty

parse_inputs_json returns {} both when the option is absent and when the user
passes --inputs "{}", so the falsy check started the TUI for the second case
while the docs said it was unsupported. The conversational path now takes
whether the option was supplied, not what it parsed to.

Documents the restriction in en, ar, ko and pt-BR.

Found by CodeRabbit on #7060.

* test(cli): pin the headless conversational exit status

pytest.raises(SystemExit) also accepts SystemExit(0), so the error path could
regress to a successful exit unnoticed.

Found by CodeRabbit on #7060.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 14:36:40 +05:30
João Moura
4dfd074fae docs(flow): document declarative conversational flows (#7035)
* test(flow): unskip the conversational end-to-end suite

The `conversational_graph_broken` marker parked 21 end-to-end conversational
tests with the reason "the definition-first start migration intentionally
stopped scanning inherited methods, so that graph no longer registers".

That is no longer true: `_iter_flow_methods` walks the MRO for
`__conversational_only__` methods (dsl/_utils.py:406-420), so a
`conversational = True` subclass does register `route_conversation`,
`converse_turn`, `end_conversation` and `answer_from_history_turn` — which
`test_flow_definition.py:391-407` already asserts.

Removing the marker takes the file from 47 passed / 21 skipped to 68 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(flow): make conversational opt-in unmistakable

Opting a Flow into chat took two statements, and forgetting one failed
silently. With `@ConversationConfig(...)` but no `conversational = True`:
`FlowDefinition.conversational` came back `None`, the built-in graph never
registered, and `handle_turn()` returned `None` without appending a message
or raising — while `chat()` reported "only available on conversational flows"
on a class that was literally decorated with a conversational config.

Three changes:

- `ConversationConfig.__call__` now also sets `conversational = True`. Every
  field on the config is consumed only by the conversational graph, so a
  decorated non-conversational Flow could only ever discard it.
- `FlowConversationalDefinition.enabled` defaults to True. The block is absent
  on non-conversational flows, so declaring it is the opt-in; `enabled: false`
  remains an explicit opt-out.
- `handle_turn()` raises like `chat()` and `stream_turn()` already do instead
  of silently returning `None`.

Setting `conversational = True` by hand still works and is still the way to
opt in without a config.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(flow): let a declaration drive conversational mode

`FlowDefinition.conversational` was written by the DSL projection and read by
nothing: every conversational gate resolved through `type(self).flow_definition()`
— the class projection — instead of `self._definition`, the declaration a flow
was actually built from. So `Flow.from_declaration()` on a definition with a
conversational block produced a flow that reported itself non-conversational,
dropped the user message, and never registered its declared routes.

Resolution rules, applied consistently:

- Structure (enabled, methods, route labels, builtin/internal routes) comes
  from `self._definition`, which is the loaded declaration for a declarative
  flow and the class projection otherwise. Both paths now agree.
- Behavior (`conversational_config`) still prefers the class attribute, which
  can hold live objects — a configured LLM, a custom BaseLLM, a response_format
  model class — that the serializable definition degrades to a config dict or a
  `module:qualname` ref. Reading the definition first would silently downgrade
  every decorated Python flow. A declaration-built flow has no class config, so
  `_config_from_definition` supplies one, cached for stable identity.
- A declared `state:` block is never replaced. `_create_default_extension_state`
  is consulted before `_create_definition_state`, so returning `ConversationState`
  there discarded every field the declaration asked for. It now yields to a
  declared state and only supplies the default when nothing else does.

The class-scoped `_is_conversational` / `_conversational_definition`
classmethods are gone; the existing instance-scoped `_is_conversational_enabled`
is the single gate.

A router `response_format` that survived serialization as a ref or schema dict
is dropped with a warning rather than handed to `llm.call()`, which needs a
real class.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(flow): synthesize the built-in conversational methods for declarations

A declaration carrying `conversational: {}` loaded clean and then ran zero
methods and returned `None`, because the four built-in graph handlers are
inherited from `_ConversationalMixin` and a declaration has nothing to inherit
from. Authors had to name `crewai.experimental.conversational_mixin:_Conversational
Mixin.route_conversation` and three siblings by hand.

`Flow._extend_definition` is a new runtime extension hook, called once
`_definition` is resolved and before methods are bound. The conversational
mixin overrides it to fill in `route_conversation`, `converse_turn`,
`end_conversation` and `answer_from_history_turn` when they are missing, using
the same code refs the DSL projection already emits so a declaration and a
class projection of the same flow produce identical method definitions.

Synthesis is deliberately a runtime concern, not a contract one:
`FlowDefinition` stays independent of the authoring layer and of the engine,
as `test_flow_definition_contract_is_dsl_agnostic` requires, and a loaded
declaration still serializes back to exactly what its author wrote.

Route descriptions are now carried by the contract. The DSL projects a handler
docstring's first line into `FlowMethodDefinition.description`, and the router
catalog reads that before falling back to the live docstring. This also fixes
a real defect: for a declarative flow `getattr(type(self), handler_name, None)`
is `None`, and the old code read `None.__doc__` — so the router LLM was told a
route's description was "The type of the None singleton."

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(flow): let an agent or crew handler reply in a conversation (#7034)

`handle_turn` promotes a handler's return value to the assistant message when
the handler did not append one itself, but the check required `isinstance(result,
str)`. Declarative `agent` and `crew` actions return `LiteAgentOutput` and
`CrewOutput`, whose text lives on `.raw` — so the most natural declarative
handler was exactly the one whose reply never reached the transcript.

`_is_public_turn_result` now unwraps `.raw` before deciding, matching
`_stringify_result`, which already did. The routing-artefact guards are applied
to the unwrapped text, so an output echoing a route label or this turn's intent
is still not promoted.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(flow): keep privately recorded agent results out of the transcript

Unwrapping `.raw` in `_is_public_turn_result` made the end-of-turn fallback
promote `LiteAgentOutput` / `CrewOutput` objects that the handler had already
recorded via `append_agent_result` with the default private visibility. That
call does not set `_assistant_reply_appended`, so the fallback republished the
very object the handler asked to keep private — defeating
`visible_agent_outputs`.

Reproduced against `main` for contrast: no leak before the unwrap, leak after.

`append_agent_result` now remembers the object it recorded for the duration of
the turn, and the fallback skips anything already routed that way. The check is
identity-based on purpose: a handler that records scratch work privately and
then returns a user-facing summary still gets that summary promoted, which a
simple "handler already handled it" flag would have broken.

Found by Cursor Bugbot on #7033.

* feat(flow): mark a declarative chat flow conversational on the instance

A declaration enables chat through `conversational.enabled`, without the
`conversational = True` class attribute. Callers outside this package
capability-check that attribute -- the AG-UI serving guide states it as a
requirement -- so it disagreed with `_is_conversational_enabled()` and a
declarative conversational flow looked non-conversational from outside.

`_extend_definition` now sets it on the instance when the definition enables
chat. Instance-only on purpose: the DSL projection reads the attribute off the
*class* to decide whether to emit a conversational block, so setting it there
would make every later subclass look conversational.

Verified on a real declarative flow: `conversational` and `stream_turn` both
now satisfy the documented capability check, while `Flow.conversational` and
any later subclass stay False.

* refactor(flow): derive routing-artefact labels from the effective routes

`_is_public_turn_result` matched a literal set of route labels, duplicating
knowledge that `_effective_builtin_routes()` already owns. A declaration that
adds a builtin route was not covered, so a handler echoing that label could be
promoted into the transcript -- the same class of divergence already fixed for
`route_turn`.

Verified the derived set is byte-identical to the old literal one for a
class-based flow, so this is a pure generalization: `conversation` and
`route_to_flow` stay explicit because neither is a route.

Also replaces a tuple-index lambda in the chat REPL test with a named
`input_fn`; it relied on tuple evaluation order and on the list being mutated
before its length was read.

Both found by CodeRabbit on #7033.

* docs(flow): document declarative conversational flows

The authoring skill told LLM authors "use top-level `conversational` only when
the user asks for a chat flow" while documenting none of its 19 fields — there
was no ModelSpec for either conversational model, so the API reference appendix
skipped them entirely.

- Adds both conversational models to the skill reference, with field
  descriptions, and registers them under the existing `conversational` skip so
  `skills(skips=["conversational"])` still suppresses the whole block.
- Adds authoring rules: do not declare the built-in graph, do not name a
  handler after the route it listens to, do not declare state unless it needs
  extra fields, and give every route handler a description.
- Documents the declarative form in the conversational-flows guide across en,
  ar, ko and pt-BR, including what is supplied automatically, how to run it,
  and what a declaration cannot express (live LLM objects, a response_format
  class, route_turn overrides).
- `crewai run` on a conversational declaration now says it has no chat loop and
  points at handle_turn/chat, instead of quietly running a single turn and
  exiting. It fails closed: a flow that cannot be inspected runs normally.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(flow): render the conversational router section in the skill

Both conversational models shared one `Conversational` section, and the
template renders only the first model of a non-union section. The router's
fields were therefore dropped from the API reference and the generated link to
them pointed at a heading that did not exist.

Also softens the built-in-handler rule: `_extend_definition` keeps an
author-supplied entry and the guide documents that override, so the skill
should say to omit those handlers by default rather than never declare them.

Adds regression tests for both sections rendering, for every field of both
models appearing, and for `skips=["conversational"]` suppressing both.

Both found by CodeRabbit on #7035.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(flow): correct the route-description rule in the authoring skill

The rule said every route handler must define `description`, but
`conversational.router.route_descriptions` is the higher-precedence source --
`_build_route_catalog` checks the overrides before falling back to the method
description. Either one describes a route; the rule now says so, and says what
happens when a route has neither.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: ViditOstwal <viditostwal@gmail.com>
Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-08-19 20:18:18 +05:30
João Moura
4b9b8bcbb9 feat(events): record what kind of exception ended a flow (#6982)
* feat(telemetry): record what kind of exception ended a flow

Flow failures are visible but undiagnosable. Live data shows roughly 17% of
flows ending in outcome=failed, and 72% of AgentExecutor failures completing
in under 200ms - far too fast to be an LLM call - but nothing records what
the failure actually is, so there is no way to tell a real defect from a
user pressing Ctrl-C.

Record the exception's class name as error_type on Flow Completed and Flow
Method Failed. The class name only: str(error) is never read, because it
routinely carries prompts, model output, file paths and credentials. The
isidentifier() check is the allowlist that enforces it - any message text
reaching that argument carries a space or punctuation and is dropped - and
it lives inside Telemetry rather than at the call site so a future caller
cannot bypass it. Method names and flow state remain unrecorded.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ASfWmW3RGy4qAQm6s8U9jH

* docs(frontend): point the frontend guides at their edge paths

The frontend guides added in #6686 exist only under edge - they are not in
any frozen version snapshot - but their 80 internal links use the bare
/en/guides/frontend/... form, which resolves against the released versions
where those pages do not exist. mint broken-links fails on every one of
them, which blocks every open PR, not only the one that added them.

Use the /edge/en/... form the repo already uses for other edge-only pages
(concepts/streaming, learn/execution-boundary-hooks). Anchors are preserved.
No page content changes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ASfWmW3RGy4qAQm6s8U9jH

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-13 16:12:19 +00:00
Ran Shemtov
27083f4131 docs: add Frontend guides (CopilotKit + AG-UI) (#6686)
Some checks failed
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Vulnerability Scan / Detect changes (push) Has been cancelled
Vulnerability Scan / pip-audit (push) Has been cancelled
Check Documentation Broken Links / Check broken links (push) Has been cancelled
Nightly Canary Release / Check for new commits (push) Has been cancelled
Nightly Canary Release / Build nightly packages (push) Has been cancelled
Nightly Canary Release / Publish nightly to PyPI (push) Has been cancelled
* docs: add Frontend guides section (CopilotKit + AG-UI)

Add a Frontend sub-group under Guides documenting how to build user
interfaces for CrewAI Crews and Flows with CopilotKit over the AG-UI
protocol. Pages: overview, generative UI, tool-based generative UI,
agentic generative UI, human-in-the-loop, shared state, frontend
actions, predictive state updates, and channels.

* docs: mirror Frontend guides into v1.15.5 (Latest)

Also register the Frontend sub-group and pages under the default
v1.15.5 version so the section is visible without switching to Edge.

* docs(frontend): address audit — correct APIs and claims

- Use useRenderTool for display-only tool rendering (was useFrontendTool)
- Correct state 'auto-streams' claims: snapshot at step boundaries,
  document copilotkit_emit_state for mid-step progress
- Fix setState usage to spread full state (replace, not merge)
- Add tool description to the frontend-action example
- Rewrite Channels with the real @copilotkit/channels createBot API
  (Slack + Discord adapters); drop unsupported platform claims
- Note self-hosted vs managed CopilotKit paths and pin package versions

* docs(frontend): remove versions callout from overview

* docs(frontend): drop package-generation framing from emit_state note

* docs(frontend): add generative UI spectrum (A2UI, reasoning) + Conversational Flows

Rewrite generative-ui as the controlled/declarative/open-ended spectrum;
add A2UI (declarative), Reasoning (controlled), and a Conversational Flows
page; add a backend-tools section to tool-based; note the three execution
shapes in the overview.

* docs(frontend): address review — edge-only, attribute access, safe defaults

Remove the docs/v1.15.5 mirror (versioned snapshots are cut from edge by
the release tooling; the docs-snapshots CI guard rejects manual docs/v*
writes). Use attribute access on the LiteLLM message in shared-state,
guard setState against undefined agent/recipe, and use
Field(default_factory=list) for the agent-state list.
2026-08-12 10:01:16 -07:00
Vidit Ostwal
8320178697 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.
2026-08-06 00:14:55 +05:30
Vidit Ostwal
fef32f43a0 feat(cli): unify scaffolding under crewai create <resource> (#6821)
* feat(cli): add canonical `crewai create tool` command

Unify tool scaffolding under the create verb and deprecate
`crewai tool create` with a yellow warning while keeping backward
compatibility.

* feat(cli): add canonical `crewai create skill` command

Unify skill scaffolding under the create verb and deprecate
`crewai skill create` with a yellow warning while keeping backward
compatibility.

* feat(cli): add canonical `crewai create template` command

Unify template scaffolding under the create verb and deprecate
`crewai template add` with a yellow warning while keeping backward
compatibility.

* docs: document unified `crewai create` scaffolding commands

Document canonical create forms for tool, skill, and template projects,
note deprecated aliases, and update skills and agents-md guides.

* feat(cli): extend create picker and DMN guidance for all types

Show tool, skill, and template in the interactive create picker and
list every supported type in the CREWAI_DMN usage error.

* fix(cli): allow create tool/skill/template in CREWAI_DMN mode

Only set skip_provider in DMN mode for crew creation, since tool,
skill, and template paths reject that flag as a crew-only option.

* test(cli): patch TemplateCommand at cli lookup site in DMN test

create() resolves TemplateCommand from crewai_cli.cli, not from
remote_template.main directly.
2026-08-05 16:41:27 +00:00
Gui Vieira
3266932f00 [COR-636] Remove migrated AMP documentation (#6730) 2026-07-30 13:14:34 -03:00
Lorenze Jay
8eed457e70 Define stream frame protocol for flows (#6391)
* Define stream frame protocol for flows

* Add direct LLM streaming helpers

* Unify flow streaming frame items

* Update flow streaming integration properties

* Drop stream frame debug runner example

* Address streaming contract review feedback

* Replay cached stream frame projections

* Remove stream frame version field

* Fix streaming contract docs link

* Preserve LLM instance state for stream events

* Address streaming review cleanup
2026-06-30 10:53:48 -07:00
Vinicius Brasil
221dfdb08e Consolidate crewai run and crewai flow kickoff (#6296)
Make `crewai run` the single execution path for crews and flows, with
`crewai flow kickoff` kept as a deprecated compatibility alias.
2026-06-22 20:44:08 -07:00
Vinicius Brasil
9db2d44766 Add typed output schemas for CrewAI tools (#6236)
Some checks failed
Build uv cache / build-cache (3.10) (push) Has been cancelled
Build uv cache / build-cache (3.11) (push) Has been cancelled
Build uv cache / build-cache (3.12) (push) Has been cancelled
Build uv cache / build-cache (3.13) (push) Has been cancelled
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Check Documentation Broken Links / Check broken links (push) Has been cancelled
Vulnerability Scan / pip-audit (push) Has been cancelled
Nightly Canary Release / Check for new commits (push) Has been cancelled
Nightly Canary Release / Build nightly packages (push) Has been cancelled
Nightly Canary Release / Publish nightly to PyPI (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
Currently, tools have a strong input contract through `args_schema`, but no
output contract. This means that anything a tool outputs is converted to
string.

Not only the contract is weak, but the "invisible" conversion to string can
have unexpected effects when the tool returns complex objects like dicts and
arrays.

With this PR, a tool can _optionally_ define an output contract with
`output_schema`. CrewAI validates the raw result and sends the agent JSON.

```python
class ProductResult(BaseModel):
    sku: str
    name: str
    in_stock: bool

class ProductLookupTool(BaseTool):
    name: str = "Product Lookup"
    description: str = "Look up product availability by SKU."

    def _run(self, sku: str) -> ProductResult:
        return ProductResult(sku=sku, name="USB-C dock", in_stock=True)
```

If the result does not match the schema, CrewAI warns and falls back to
`str(raw_result)` instead of failing the run:

```python
@tool("Product Lookup", output_schema=ProductResult)
def product_lookup(sku: str) -> dict[str, object]:
    return {"sku": sku, "name": "USB-C dock", "in_stock": True}

#=> RuntimeWarning: Failed to validate or serialize output from tool 'Bad Product Lookup' using output_schema 'ProductResult'... Falling back to str(raw_result).
```

This is additive and non-breaking. Existing tools do not need to change. Tools
without `output_schema` keep the old string behavior. Invalid typed outputs
warn and fall back to the old formatting path.
2026-06-19 14:33:51 -07:00
Lucas Gomide
a237ebabba feat: adopt directory-based docs versioning with Edge channel (#6202)
* feat: adopt directory-based docs versioning with Edge channel

Switch docs.crewai.com from navigation-only versioning (every version
selector entry rendered the same docs/<lang>/* source files) to
Mintlify's directory-based versioning so each version selector entry
renders its own snapshot. Add an "Edge" channel under docs/edge/<lang>/*
that always reflects main HEAD for unreleased work, eliminating
pre-release leakage onto frozen release labels. External links to
canonical /<lang>/* URLs are preserved via wildcard redirects that
always land on the current default version.

Layout:
- docs/edge/<lang>/*         rolling source (you edit here)
- docs/edge/enterprise-api.*.yaml
- docs/v<X.Y.Z>/<lang>/*     frozen, immutable snapshots
- docs/v<X.Y.Z>/enterprise-api.*.yaml
- docs/images/               shared, append-only
- docs/docs.json             nav + redirects

URLs follow the Mintlify-idiomatic shape: /edge/<lang>/<page> for
Edge, /v<X.Y.Z>/<lang>/<page> for every frozen snapshot. The wildcard
redirects /<lang>/:slug* -> /<default>/<lang>/:slug* keep stale links
working, and every freeze rewrites them (plus all per-section/per-page
redirects) so destinations always resolve to the current default
without depending on a second redirect hop.

Release flow integration (devtools release):
- New module crewai_devtools.docs_versioning.freeze() materialises
  docs/v<X.Y.Z>/ from docs/edge/, rewrites openapi: refs inside the
  snapshot, inserts the version into every language block in
  docs.json, and refreshes all redirect destinations.
- _update_docs_and_create_pr() in cli.py now calls that freeze during
  Phase 2 of devtools release. Edge changelogs are updated first (so
  the snapshot freeze picks them up), then the snapshot is staged
  alongside docs.json, branched as docs/freeze-v<X.Y.Z>, and the PR
  is titled [docs-freeze] docs: snapshot and changelog for v<X.Y.Z>
  — the title prefix the new CI guard reads.
- The PR still gates tag, GitHub release, PyPI publish, and the
  enterprise release as before; no new PRs are added.
- Pre-releases (1.X.YaN, 1.X.YbN, ...) skip the snapshot — they ride
  Edge — and the docs PR title omits the [docs-freeze] prefix.
- docs_check (AI-generated docs scaffolding) writes to
  docs/edge/<lang>/* so newly-generated unreleased docs land in Edge
  and never accidentally touch a frozen snapshot.

Migration scripts (one-shot):
- scripts/docs/freeze_historical_versions.py reconstructs all 16
  historical snapshots (v1.10.0 .. v1.14.7) from git tags via
  git archive | tar, rewriting openapi: MDX refs so each snapshot
  reads its own enterprise-api YAML rather than the live one.
- scripts/docs/prefix_version_paths.py one-shot-migrates docs.json:
  rewrites every page path in 16 versioned blocks to point under
  docs/v<X.Y.Z>/, inserts a new Edge entry per language, tags
  v1.14.7 as Latest (default), prunes pages whose target file
  doesn't exist in the snapshot (e.g. docs/ar/ didn't exist before
  v1.12.0), and writes the wildcard + per-section redirects.
- scripts/docs/freeze_current_edge.py is now a thin CLI wrapper
  around docs_versioning.freeze for manual one-off freezes (e.g.
  retroactively snapshotting a forgotten release).

CI guards (.github/workflows/docs-snapshots.yml):
- Frozen snapshots under docs/v[0-9]*/ are immutable; only PRs whose
  title contains [docs-freeze] (i.e. release-cut PRs generated by
  devtools release or the manual wrapper) may modify them.
- Images under docs/images/ are append-only since snapshots share a
  single image directory. Deleting or renaming an image breaks every
  historical snapshot that still references it.

Restored docs/images/crewai-otel-export.png from PR #3673; it was
deleted in PR #4908 but v1.10.0 / v1.10.1 snapshots still reference
it. Restoring instead of editing the snapshots preserves historical
rendering fidelity and validates the new append-only rule
retroactively.

Tests:
- lib/devtools/tests/test_docs_versioning.py covers the freeze: file
  copy, openapi rewrite, version insertion, default demotion, redirect
  upserts, per-section redirect rewriting, idempotency, and invalid
  inputs.

Verified locally with mintlify broken-links: 0 broken links across
the full site (Edge + 16 frozen versions, 4 locales).

AGENTS.md (repo root) is the contributor guide for the new model;
RELEASING.md is the release-cut runbook; README's Contribution
section links to both.

Co-authored-by: Cursor <cursoragent@cursor.com>

* style: resolve linter issues

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-17 11:56:59 -04:00