Commit Graph

13 Commits

Author SHA1 Message Date
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
Gui Vieira
3266932f00 [COR-636] Remove migrated AMP documentation (#6730) 2026-07-30 13:14:34 -03: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
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