Commit Graph

849 Commits

Author SHA1 Message Date
João Moura
32a9d2ae7b feat(tracing): collect human feedback and pause events in the trace (#7499)
* feat(tracing): collect human feedback and pause events in the trace

The trace listener subscribed to method and conversation events but not to
the review-gate events or the pause events, so a `@human_feedback` gate
reached the trace only as method_execution_started/finished. A trace could
not say that a run stopped for review, what the reviewer was shown, or what
they answered.

Subscribe to HumanFeedbackRequestedEvent, HumanFeedbackReceivedEvent,
MethodExecutionPausedEvent and FlowPausedEvent through `_handle_action_event`,
as the conversation events are, with the event's own type as the trace type.
Each is a whole-event payload via the default serialization path; no change
to `_build_event_data` or `complex_events`.

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

* fix(tracing): register the gate and pause handlers through _on, keeping the execution-uuid gate

The four new handlers, and the conversation handler this branch had switched by
mistake, registered with event_bus.on and so ran while a kickoff owned an execution
uuid — the case where the OTEL session records these events and the legacy collector
must stay idle. Restored to self._on like every other handler; a test binds an
execution uuid and asserts none of the five are collected into a legacy batch.
Docstrings on the handlers (review bot coverage note).

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

* test(tracing): under a tracing kickoff the session records the gate and pause events and the legacy batch stays empty

Two real flows under an in-memory tracing session (the lifecycle tests' pattern): a
@human_feedback gate answered at the console records human_feedback_requested and
human_feedback_received as spans; an async provider that parks the flow records
method_execution_paused and flow_paused. In both the legacy collector, gated by _on,
collects none of the four. Review bot: the uuid-gated test alone would have passed
with the session registrations missing.

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

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-16 16:41:09 +00:00
wangtao
c0af9badb8 fix(skills): accept CRLF in inline skill definitions (#7504)
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
Co-authored-by: wangtaotaotao95 <328929485+wangtaotaotao95@users.noreply.github.com>
Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-16 19:35:35 +05:30
Ray
b4fd395d8d fix(rag): load text file URLs through the safe fetcher (#7506) 2026-09-16 13:51:05 +00:00
Sharoon Sharif
2c24b95eae fix(memory): close sqlite connections in kickoff task outputs storage (#7493)
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
Mark stale issues and pull requests / stale (push) Has been cancelled
* fix(memory): close sqlite connections in kickoff task outputs storage

`with sqlite3.connect(...) as conn` only commits or rolls back; it never
closes the connection, which then survives in a reference cycle until a
cyclic GC pass. Every Crew kept an open handle on
latest_kickoff_task_outputs.db, so on Windows the file stayed locked and
any later delete, rename or temp-dir cleanup failed with PermissionError
(WinError 32). Wrap each connection in contextlib.closing, keeping the
existing commit/rollback semantics, and add regression tests.

* test(memory): cover rollback and close on a failed write

---------

Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-16 07:47:39 +00:00
João Moura
d2190c2a7d fix(agents): carry from_cache on the native tool path's ToolUsageFinishedEvent (#7501)
`_execute_single_native_tool_call` reads the tools handler's cache and
skips the tool body on a hit, but emitted its ToolUsageFinishedEvent
without `from_cache`, so the bus — and every trace built from it — saw a
replayed native function call as a live one. The text-protocol path
(ToolUsage.on_tool_use_finished) already carried the flag. One kwarg.

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-16 12:47:31 +05:30
João Moura
c1beddf1a6 feat(llm): add llm_overlay contextvar to route agent roles to models (#7500)
A per-run caller sometimes needs specific agents on a different model
without editing the code that builds them. `crewai.llm_overlay` adds a
process-context `role -> model` overlay:

    with llm_overlay({"Researcher": "openai/gpt-4o"}):
        crew.kickoff()

The overlay is read in the only two places an agent resolves its model from
its role: `Agent.post_init_setup` and `LiteAgent.setup_llm`. When the role is
a key, `create_llm` receives the mapped model instead of the declared `llm`;
otherwise, and outside the block, nothing changes. `create_llm` itself stays
role-blind.

The overlay is a ContextVar, so it follows the calling context and is always
reset on exit. It does not cross plain threads; callers threading agents must
propagate the context with `contextvars.copy_context().run(...)`. The module
docstring says so and a test pins the behaviour.

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-16 12:41:47 +05:30
Swapnil Yadav
a59cf26f56 fix(files): raise ValueError instead of bare raise in get_uploader (#7283)
* fix(files): return None instead of bare raise in get_uploader

get_uploader is documented to return None for an unsupported provider, and
every caller branches on `if uploader is None`. Two fallthrough paths ran a
bare `raise` with no active exception, so an unknown provider and a Bedrock
provider without a configured S3 bucket raised
"RuntimeError: No active exception to reraise" instead of returning None.

Return None in both paths and widen the return types to `... | None`. The
Bedrock "not configured" guard now treats a falsy bucket_name (None or "") as
unconfigured, not only an absent one. The except ImportError re-raises are
unaffected.

Fixes #7282

* fix(files): raise ValueError from get_uploader for unknown/unconfigured providers

Per review, raise a ValueError with a concrete reason instead of returning
None. Returning None let the resolver silently fall back to inline and hid the
misconfiguration from the user, so the docstring no longer promises None and
the return types drop `| None`. The Bedrock guard also treats a falsy
bucket_name (None or "") as unconfigured. The ImportError re-raises are
unchanged.

cleanup skips providers it cannot build an uploader for, so it routes
get_uploader through a local helper that treats the ValueError as
"unavailable" and continues the pass.

* refactor(files): surface get_uploader errors through the resolver

Follow-up to review. get_uploader now raises ValueError, so _get_uploader no
longer promises FileUploader | None: it returns the uploader and lets the error
propagate through resolve() to the caller instead of swallowing it and falling
back to inline. Drop the now-dead `if uploader is None` checks at the two
upload call sites.

Also make the unknown-provider ValueError list the supported providers, and add
a happy-path test that a configured provider returns its uploader.

* fix(files): surface uploader lookup errors in async batch resolution

aresolve_files gathers with return_exceptions=True, which was silently dropping
files when _get_uploader raised (a missing provider SDK, or an unknown or
unconfigured provider). A batch shares one provider, so such a lookup failure
applies to every file: re-raise ValueError and ImportError to surface it,
matching the sync resolve_files path. Genuine per-file upload errors are still
logged and skipped.

* fix(files): only re-raise uploader config errors in async batch resolution

The earlier fix re-raised any ValueError or ImportError from
asyncio.gather(return_exceptions=True), so one unrelated per-file error
(for example a stream that raises ValueError when read) aborted the whole
batch instead of the intended log-and-skip.

_get_uploader now translates the lookup failure into a dedicated
UploaderConfigurationError, and aresolve_files re-raises only that, since
it applies to every file for the provider. Ordinary per-file failures stay
best-effort. Adds regression tests for the wrap, a provider-setup error
surfacing from the batch, and an unrelated per-file error skipped while
the rest resolve.

* style(files): apply ruff import sort and formatting to resolver tests

---------

Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-16 06:41:25 +00:00
João Moura
1c64c84cd8 feat(tracing): carry task_prompt and output in agent_execution payloads (#7498)
`agent_execution_started` and `agent_execution_completed` are in
`complex_events`, so `_build_event_data` hand-builds their payloads. Those
payloads shipped only agent_role/goal/backstory and dropped two required bus
fields: `AgentExecutionStartedEvent.task_prompt` and
`AgentExecutionCompletedEvent.output`. A trace therefore said which agent ran
but not what it was asked or what it answered.

Add `task_prompt` to the started payload and `output` to the completed one,
whole and untruncated. No new event types, no TraceEvent change.

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-16 11:56:33 +05:30
Rohit Kanithi
9473098af5 fix(flow): support non-primitive types in SQLiteFlowPersistence (#7358) (#7376)
* fix(flow): support non-primitive types in SQLiteFlowPersistence (#7358)

* test(flow): add docstrings to test classes and step methods

* fix(flow): serialize Decimal and Path as strings in SQLite persistence

* fix(flow): dump BaseModel with mode=python to allow fallback serialization on Any fields

* fix(flow): prioritize model_dump mode=json with fallback to mode=python

* ci: re-trigger test suite

---------

Co-authored-by: Rohit Kanithi <rohitkanithi@users.noreply.github.com>
Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-16 06:01:07 +00:00
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
Lorenze Jay
993a96c4e0 feat(tracing): port trace events sessions to OSS (#7464)
Some checks failed
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 / Detect changes (push) Has been cancelled
Vulnerability Scan / pip-audit (push) Has been cancelled
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
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
* feat(tracing): port enterprise event sessions to OSS

* fix(tracing): address review findings and verify concurrent exports

* fix(tracing): keep redactor ownership in enterprise integrations

* test(tracing): isolate intentional failures from cleanup assertions
2026-09-15 13:09:40 -07:00
Sharoon Sharif
756d8d33c8 fix(cli): read json checkpoints as utf-8 (#7491)
JsonProvider writes checkpoints with encoding="utf-8" and the runtime
serialises non-ASCII text verbatim, but the checkpoint CLI still opened
them with the platform default encoding. On Windows (cp1252) `crewai
checkpoint info` raised UnicodeDecodeError and `list` showed a 0-byte
entry for any checkpoint containing non-ASCII text. Open the files as
UTF-8 and add regression tests for the three readers.
2026-09-15 16:52:54 +00:00
Sharoon Sharif
0e2fa7ec24 fix(cli): overwrite stale poetry.lock backup on windows (#7463)
Some checks failed
CodeQL Advanced / Analyze (python) (push) Has been cancelled
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
Vulnerability Scan / Detect changes (push) Has been cancelled
Vulnerability Scan / pip-audit (push) Has been cancelled
* fix(cli): overwrite stale poetry.lock backup on windows

os.rename raises FileExistsError on Windows when poetry-old.lock already
exists from a previous run, so a second `crewai update` crashed there
while POSIX silently replaced the file. Use os.replace, which overwrites
on every platform, and add a regression test.

* test(cli): add docstrings to update_crew tests

---------

Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-15 15:37:03 +00:00
哈基米
b66f3f215a fix(azure): key streamed tool calls by wire index (#7487)
Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-15 20:57:04 +05:30
絜矩
7b79662372 fix(gemini): preserve fileData content parts (#7479)
* fix(gemini): preserve fileData content parts

* test(gemini): cover media-only fileData messages
2026-09-15 14:52:07 +00:00
Roli Bosch
c6ff78650e fix(memory): honor read_only on update() and recall() access times (#7369)
`Memory.read_only` was enforced only on `remember()` and `remember_many()`.
Two other paths still mutated the backing store:

- `update()` re-embedded the supplied content and wrote the record back.
- `recall()` refreshed `last_accessed` through `touch_records()`, so simply
  reading a read-only memory left a persistent trace.

Both now respect the flag, so a read-only Memory leaves stored records
unchanged. `update()` returns the existing record untouched rather than
raising, matching the silent no-op behaviour of `remember()`. Explicit
deletion through `forget()`/`reset()` is deliberately unaffected.


Claude-Session: https://claude.ai/code/session_01HkDjVYVzHFEj5re9B8JH9p

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-15 11:20:49 +00:00
João Moura
66ef97c73e fix(llms): send reasoning_effort to every openai reasoning model (#7187)
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
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
* fix(llms): send reasoning_effort to every openai reasoning model

The completions path gated the parameter behind
is_o1_model = "o1" in model.lower(), a literal substring test. gpt-5, o3 and
o4-mini contain no "o1", so an explicitly configured effort was dropped and the
model thought at the server default. The request still succeeded, so nothing
surfaced -- one measured extraction ran 6.2s with the setting applied against
149.7s with it dropped.

The gate could not be widened: is_o1_model also drives
supports_function_calling, supports_stop_words and the system->user message
rewrite, so marking gpt-5 as an o1 model would report that it cannot call
tools. The parameter is forwarded unconditionally instead, matching the
responses path, and a model that genuinely does not support it says so in a 400
that is retried once without the key.

Also adds "minimal" to LLM.reasoning_effort, which gpt-5 accepts and the
Literal omitted, so the cheapest setting was unreachable on the typed surface.

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

* refactor(llms): gate reasoning_effort on model shape, not every model

Forwarding to every model made a non-reasoning model pay a rejected request
and a retry on every call. `_supports_reasoning_effort` matches on shape
instead -- the o-series, and GPT generation 5 onwards -- so gpt-4o and gpt-4.1
never send the parameter at all.

Matched by shape rather than by a list of names so a new member of an existing
family works without a release here; gpt-6 and o5 already classify correctly.
The unsupported-parameter retry stays as a safety net for the case the shape
match is wrong for a future family, where it costs nothing when the match is
right.

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

* fix(llms): honour reasoning_effort on compatible servers and fine-tunes

Review follow-ups. A fine-tune (ft:<base>:...) is judged by its base model.
On an OpenAI-compatible server -- anything whose effective base URL is not
api.openai.com, whether set explicitly, via env, or by a provider subclass --
the model name is the server's namespace and says nothing about support, so an
explicit setting is sent as configured; a 400 naming the parameter, in whatever
words the server uses, is recovered by retrying without it, unless it reads as
a complaint about the value. A model that rejected the parameter is remembered
per (endpoint, model) for the process so the rejected call is paid once, and
the drop is logged as a warning since a configured setting is not being
applied. The Literal also gains "xhigh", the remaining value the SDK accepts.

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

* fix(llms): recover reasoning_effort only on evidence the parameter is unknown

Two review follow-ups. The endpoint check now uses the same base URL precedence
as the client itself, so a `client_params` override selects the server. And a
rejection is recovered only when the message says the field is not one the
server knows -- OpenAI's two shapes plus the common compatible-server wordings
("unknown field", "Extra inputs are not permitted") -- rather than any 400 that
lacks a value-sounding word. A pydantic enum complaint such as "Input should be
'low', 'medium' or 'high'" names the parameter but is about its value, and
surfaces instead of being dropped.

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

* fix(llms): remember a reasoning_effort rejection only after the retry succeeds

Two review points on the reasoning_effort fallback. The rejection was recorded
before the retry ran, so a retry that died for an unrelated reason (a dropped
connection, say) silently stopped sending the configured effort for the rest of
the process even though a call without it had never succeeded; the (endpoint,
model) is now remembered only once the retry returns. And _effective_base_url
accepted only a str override in client_params while the SDK, and
_get_client_params, accept httpx.URL too, so a compatible deployment configured
with a URL object was detected as OpenAI and its rejection keyed under the wrong
endpoint; both forms are normalised to the string the client calls.

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-14 19:14:39 +00:00
theater
a225c1b373 fix(cli): don't crash the run TUI when streamed output contains a literal [...] (#7435)
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
* fix(cli): reject non-serializable literal_eval results in TUI JSON formatting

_try_parse_structured() accepted any dict/list coming out of
ast.literal_eval(), including values json.dumps() cannot encode such as
[Ellipsis] from a literal [...]. _format_json_in_text() then raised
TypeError: Object of type ellipsis is not JSON serializable, which
propagated through _tick and cancelled the whole crew run.

Validate the parsed object with json.dumps() inside
_try_parse_structured() so only JSON-serializable dict/list values are
returned; anything else falls back to the original text. Fixes #7434.

* fix(cli): contain RecursionError in the TUI JSON formatting boundary

A streamed structure nested deeper than the JSON backend can walk could
raise RecursionError out of _try_parse_structured (from json.loads) or
out of the render-path dumps, escaping _tick and losing the TUI update.

Catch RecursionError when loading, and validate literal_eval results
with the exact kwargs the render path uses, so any structure the render
cannot encode is rejected at the boundary and the raw text renders
instead.

---------

Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-14 20:41:33 +05:30
Shivangi
a328710007 fix: reject replay when stored tasks differ (#7155)
* fix: reject replay when stored tasks differ

* fix: validate replay task descriptions

* fix: reject ambiguous replay task identities

* fix: persist stable replay task keys

* test: align legacy replay fixture

---------

Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-14 15:52:31 +05:30
Modusensus
7e80d94921 fix: use sys.platform guards so mypy passes on Windows (#7401)
mypy does not narrow on `platform.system()`, so Windows-based contributors
get 8 spurious attr-defined/unused-ignore errors from the termios and
resource imports. Switch to `sys.platform` comparisons, which mypy
understands natively, and drop the now-unneeded type-ignore comments.

Fixes #7400

Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-14 14:38:50 +05:30
João Moura
9393a47f31 fix(agents): request the forced final answer as a user turn (#7450)
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
Mark stale issues and pull requests / stale (push) Has been cancelled
* fix(agents): request the forced final answer as a user turn

When an agent reaches max_iter, handle_max_iterations_exceeded appended
the "give your best final answer" instruction as an assistant message and
relied on assistant prefill to make the model continue it. Current Claude
models (Opus 5, Sonnet 5, Fable 5.x, the 4.6+ family) reject a request
that ends on an assistant turn with a 400, after the whole iteration
budget has already been spent.

The instruction is now appended as a user turn, which every provider
accepts. The handler's formatted_answer parameter is dropped: every
caller had already appended that text as the last assistant message, so
prefixing it again only duplicated history.

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

* fix(agents): stop the lite agent loop after the forced final answer

LiteAgent._invoke_loop fell through after handle_max_iterations_exceeded
and issued a regular LLM call on the same history, discarding the forced
answer. Break out of the loop the way CrewAgentExecutor already does, and
assert a single LLM call in the test.

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

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-14 11:52:08 +05:30
Melanie Hart Buehler
21678f8ac6 docs(rag): add xpu to embedding device options (#6808)
* docs(rag): add xpu to embedding device options

* address copilot review

* docs(rag): sync Korean and Portuguese RagTool pages

---------

Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-14 05:51:43 +00:00
Vidit Ostwal
93ad4d67c4 feat: validate platform integrations during crew setup (#7385)
* feat: validate platform integrations during crew setup

* fix: clarify platform integration validation

* refactor: split platform authentication workflow

* feat: list connected platform integrations
2026-09-11 12:20:33 -07:00
Vidit Ostwal
d20845f0a3 feat: add platform tools to JSON crew wizard (#7384)
* feat: support platform tools in JSON crews

* style: clarify platform integration labels

* fix: avoid repeating tool picker title

* fix(platform): surface JSON tool discovery errors
2026-09-11 12:13:55 -07:00
Vidit Ostwal
e1f3c4bdd4 feat: expose CrewAI Platform application catalog (#7383)
* feat: expose platform application catalog

* refactor: centralize platform application catalog

* fix: preserve platform application typing

* chore: remove unused platform app export
2026-09-11 21:02:00 +05:30
Vidit Ostwal
d5c7bac505 chore: update OpenRouter tool specifications (#7387) 2026-09-11 12:16:05 -03:00
Vidit Ostwal
004f7b58d5 test(bedrock): isolate session credential test (#7388) 2026-09-11 14:23:03 +00:00
Vidit Ostwal
c5759ce854 test(bedrock): verify environment credentials (#7375)
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
* test(bedrock): verify environment credentials

* test(bedrock): isolate credential environment test
2026-09-10 23:07:50 -07:00
monkscode
5704ea08eb fix(agents): keep null in the task output schema embedded in the prompt (#6775)
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
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
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
Check Documentation Broken Links / Check broken links (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
* fix(agents): keep null in the task output schema embedded in the prompt

build_task_prompt_with_schema embeds the task output schema into the prompt
via generate_model_description, whose strip_null_types defaults to True.
Combined with ensure_all_properties_required, an Optional[str] = None field
reaches the model as a required, non-nullable string, contradicting the
provider-side response schema generated from the same model.

That sanitizer targets OpenAI strict function-calling schemas. This call site
produces prompt prose, where those constraints do not apply.

Pass strip_null_types=False, matching the existing call for tool schemas in
utilities/agent_utils.py.

Fixes #6774

* test(agents): cover the output_json branch of the prompt schema

build_task_prompt_with_schema embeds a schema on both the output_json and
the output_pydantic branch, and this PR changes both. The regression test
only built a Task with output_pydantic, so the output_json branch shipped
unpinned.

Parameterize over both output attributes. Checked on this branch with the
fix reverted: both cases fail on the missing anyOf, and both pass with it.

Also compare the anyOf members as a set, so member order is not part of the
test contract.

---------

Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-10 13:46:16 +05:30
Gamal Osama
c860613c7a feat(embeddings): add openrouter as a supported embedding provider (#7127)
* feat(embeddings): add openrouter provider type definitions

* feat(embeddings): implement OpenRouterProvider

* feat(embeddings): export openrouter provider package symbols

* feat(embeddings): register openrouter in allowed embedding providers

* feat(embeddings): register openrouter provider and overloads in factory

* feat(tools): add openrouter embedding service support

* test(embeddings): add comprehensive openrouter provider and factory tests

* test(embeddings): add openrouter build test in embedding factory

* test(embeddings): add openrouter model key alias and env tests

* test(tools): add openrouter tests for embedding service

* docs: add openrouter embedder configuration example

* docs(ar): sync openrouter embedder translation

* docs(ko): sync openrouter embedder translation

* docs(pt-BR): sync openrouter embedder translation

* feat(embeddings): allow model alias and None fields in OpenRouterProviderConfig

* fix(tools): resolve EMBEDDINGS_OPENROUTER_API_KEY before OPENROUTER_API_KEY

* test(tools): add regression tests for openrouter env var precedence and fallback

* feat(embeddings): drop organization_id and resolve api_key via OPENROUTER_API_KEY only

* fix(tools): use OPENROUTER_API_KEY in embedding service and update tests

* docs: switch openrouter knowledge example to model_name and document OPENROUTER_API_KEY

* fix(tools): default openrouter model to namespaced openai/text-embedding-3-small

---------

Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-10 12:24:15 +05:30
Rohit Kanithi
4bfdb0df67 fix(tools): align DOCXSearchTool with standard RAG fixed schema pattern (#7356) (#7357)
Co-authored-by: Rohit Kanithi <rohitkanithi@users.noreply.github.com>
Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-10 11:16:08 +05:30
Lorenze Jay
d469e9fb2b feat: bump versions to 1.15.21 (#7362) 2026-09-09 22:29:18 +00:00
João Moura
d729cade6b fix(openai): surface gateway errors reported inside an HTTP 200 (#7342)
* fix(openai): surface gateway errors reported inside an HTTP 200

OpenAI-compatible gateways commit `200 OK` as soon as the upstream provider
accepts a request, so a later provider failure arrives in the body as an
`error` object with no `choices`. That reached the SDK's parse helper and
surfaced as `TypeError: 'NoneType' object is not iterable`, naming neither the
provider, the status, nor the fact that a timeout happened.

The four non-streaming paths now inspect the raw body before parsing and raise
the exception the upstream code maps to, so a masked 504 is catchable exactly
like an honest one. Streaming already had this guard inside the SDK.

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

* test(openai): teach the tool-cache fake about with_raw_response

The provider now reads the raw body before parsing, so a client double that
only implements `create` no longer satisfies it. Same shape as the fixes to the
reasoning-effort retry and Snowflake doubles.

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

* test(tracing): reset the TraceCollectionListener singleton between tests

TraceCollectionListener caches a TraceBatchManager on the class and
`_initialized` short-circuits `__init__`, so batch state survives for the whole
xdist worker. `test_nested_agent_executor_flow_does_not_finalize_parent_batch`
left `trace_batch_id="debug-trace-batch"` behind, which moved every later trace
POST from /tracing/ephemeral/batches to /tracing/batches/<id>/events. The
recorded cassette then stopped matching, the agent retried, and the second call
found the cassette consumed -- surfacing as ConnectionError in an unrelated
test hundreds of tests later.

Reproduced deterministically by running the leaking test followed by
tests/tracing/test_trace_enable_disable.py::test_trace_calls_when_enabled_via_env;
fails on a68b5e903 too, so this predates the gateway fix it was blocking.

An autouse fixture now clears the cached instance after each test. Two canaries
pin the invariant and fail without the fixture.

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

* test(tracing): drop the unwritable _listeners_setup canary

Both review bots flagged that the canary read `_listeners_setup` off the class,
where it is always False, so it could never fail. Correct, and the suggested fix
does not work either: `BaseEventListener.__init__` calls `setup_listeners`
(base_event_listener.py:16), which sets the flag on the instance
(trace_listener.py:229), so reading it back through `TraceCollectionListener()`
is always True. Neither read observes a leak, so the canary is deleted rather
than replaced, with the reasoning recorded so it is not re-added.

The same finding showed the fixture was resetting two class attributes that are
never assigned at class level. Only dropping `_instance` is load-bearing, so the
fixture is now one line.

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

* docs(tracing): correct why the _listeners_setup canary is unwritable

setup_listeners returns early when tracing is off and no override applies
(trace_listener.py:213-220), assigning the flag at :229 only when it actually
registers. Construction therefore does not always set it, as the previous note
claimed: with tracing disabled the flag never even reaches the instance dict.

The instance read reports ambient tracing state rather than isolation, which is
a better reason not to assert on it than the one recorded before.

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

* fix(tests): clear trace batch state in place instead of dropping the singleton

Dropping `TraceCollectionListener._instance` made the next construction re-run
`setup_listeners`, re-registering its handlers on the event bus. That broke
tests/telemetry/test_task_failure_instrumentation.py, which requires exactly one
handler per event: the re-registered `on_task_failed` made two. Verified against
a53ecc17f, where the same sequence passes -- the regression was mine.

The leak that needed fixing was batch state, not registration, so the fixture
now clears the manager's batch fields in place. Handler cleanup already belongs
to `cleanup_event_handlers`, and `first_time_handler` keeps its reference to the
same manager object.

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

* fix(tests): clear tracing context vars so the listener can re-register

Bugbot flagged that keeping the singleton leaves `_listeners_setup` set, so after
`cleanup_event_handlers` wipes the bus `setup_listeners` returns early
(trace_listener.py:208) and tracing silently registers nothing for the rest of
the worker. Confirmed: after a tracing-enabled run, re-running setup restores 0
of 119 handler entries.

Dropping the singleton fixes that but previously broke
test_task_failure_instrumentation. The real cause was a third leak: the
`_tracing_enabled` context var stayed set, so the replacement listener still
believed tracing was on and re-registered `on_task_failed` next to telemetry's.
Clearing the context vars is what makes replacing the listener safe, so the
fixture now does both, and a canary pins it (fails with `assert True is False`
without the drop).

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 15:12:57 -07:00
Vidit Ostwal
4ed4aba6cd fix(cli): keep deploy push on the AMP create source (#7345)
Push was choosing ZIP vs git from a local origin remote, so adding origin later rebuilt the last ZIP with no files. Prefer AMP zip_deployment from status, and fall back to the old origin heuristic when that field is missing.
2026-09-10 00:23:40 +05:30
Vidit Ostwal
57df7f5202 test(bedrock): restore provider module after import test (#7355)
Co-authored-by: Lorenze Jay <63378463+lorenzejay@users.noreply.github.com>
2026-09-09 23:46:37 +05:30
Daniel Barreto
b92e80be53 chore(tools): make the vision_tool more dynamic (#7350)
* chore(tools): make the vision_tool more dynamic

* tackle review comments

* chore: update tool specifications

* refactor(tools): simplify vision tool model selection

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: ViditOstwal <viditostwal@gmail.com>
Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-09 22:18:53 +05:30
Lorenze Jay
b0fd0a9fa3 feat(telemetry): track checkpoint runtime and CLI usage (#7348)
* feat(cli): track checkpoint command and TUI usage

* feat(telemetry): track runtime checkpoint operations

* fix(telemetry): count prune usage after argument validation

* style(cli): format checkpoint prune command

---------

Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-09 22:13:11 +05:30
Liangshanbobo
929a173575 test(agents): cover native result as answer (#7334) (#7336)
* test(agents): cover native result as answer (#7334)

* test(agents): document result as answer coverage

---------

Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-09 13:32:27 +05:30
George Pickett
9feaf5ecab docs(tools): fix parallel search reference link (#7344)
Co-authored-by: George Pickett <297992784+georgeatparallel@users.noreply.github.com>
Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-09 13:21:59 +05:30
Vidit Ostwal
a68b5e903c chore(ci): label FTC-closed PRs as needs-issue (#7249) 2026-09-09 00:32:53 +05:30
YOON KIWOONG
5d9b77ba10 GitContribute issue #7287 (#7288)
Signed-off-by: kiwoong <rldnddbs@naver.com>
Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-08 22:22:03 +05:30
oxy-giedrius
34199c21b7 chore(oxylabs): allow the 3.x oxylabs SDK (#7331)
`oxylabs` was pinned to exactly 2.0.0, so consumers could not take 3.0.0, out
since March. 3.x keeps the `RealtimeClient` surface these tools use, and all
four tools plus their failure paths were verified against the live API on both
2.0.0 and 3.0.0.

The lockfile keeps oxylabs at 2.0.0, so this permits the upgrade rather than
forcing it.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 07:22:23 +00:00
oxy-giedrius
fe62d04cdb fix(oxylabs): report scrape failures instead of raising IndexError (#7044)
* fix(oxylabs): report scrape failures instead of raising IndexError

The oxylabs SDK logs HTTP errors and returns an empty response rather than
raising, so the unchecked `response.results[0]` in every Oxylabs tool turned a
rejected request into `IndexError: list index out of range`. Invalid credentials
-- the most likely first-run mistake -- gave no indication of the cause. A
result carrying a non-2xx `status_code` had the same problem one level down: the
job ran, the page did not come back, and the tool returned its empty content as
though the scrape had succeeded, handing the agent "[]".

Both are now reported as a `ToolFailure` naming what went wrong, so the agent
gets something it can act on and the framework records the call as failed:

    401 Unauthorized
    400 Bad Request - Parameter `parsing_instructions` can be used just with
    `parse` parameter set to `true`.

Because the SDK keeps the cause only in its own log, the failing call is run
with a handler attached to the `oxylabs` logger and the status, the API's
explanation and timeouts are read back off it. `code` and `retryable` are set
from the status, so 429 and 5xx are marked worth retrying. Nothing about the
caller's logging configuration is changed; an application that has silenced the
SDK still gets the generic failure.

Content that is neither a string nor a dict is also serialized properly:
`parsing_instructions` commonly yields a list, and the previous `str()`
fallback produced a Python repr with single quotes instead of JSON.

The client construction and response handling these four tools duplicated
verbatim now live in a shared `OxylabsBaseTool`, following the existing
`SerpApiBaseTool` pattern, so the handling above exists in one place. The
generated tool specs change only by the new `locale` field, confirming the
tools' public surface is otherwise untouched.

Also add the `locale` option to the Google Search config, which the docs
already documented but the config model silently dropped, and correct two
copy-paste errors in the docs across all four locales.

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

* fix(oxylabs): keep concurrent scrape diagnoses apart

The error capture attached a fresh handler to the shared `oxylabs` logger for
each scrape, so two scrapes in flight at once each saw both errors. `_diagnose`
reads the first HTTP status it finds, so a timeout could be reported as the
other request's 400 -- `retryable=False` on a failure that was worth retrying.

One handler now serves every scrape and routes each record to the capture of
the call that caused it via a `ContextVar`, which isolates threads and asyncio
tasks alike. Serializing the captures would have fixed the cross-talk too, but
at the cost of running every scrape one at a time. The handler stays attached
once installed: it is inert outside a capture, and detaching it would race with
concurrent scrapes.

The regression test forces the interleaving -- one capture is held open while
the other call logs -- and fails against the previous implementation.

Also drive `config` through the public constructor in the tests instead of
assigning `__dict__["config"]`, so they would catch `__init__` dropping a
supplied config.

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 12:42:48 +05:30
αI
7e18abd108 fix(llm): route all DashScope models through native provider (#7234)
DashScope's OpenAI-compatible endpoint serves DeepSeek/Kimi/GLM/etc.,
not only Qwen. Stop restricting the native match to the qwen* prefix so
DASHSCOPE_BASE_URL applies consistently. Fixes #7233.

Co-authored-by: Alphaxiaoteng <230277249+Alphaxiaoteng@users.noreply.github.com>
Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-08 06:08:40 +00:00
Rolly Calma
09997bfd6f fix(state): persist json checkpoints as utf-8 (#7257)
* fix(state): persist json checkpoints as utf-8

* test: import pathlib Path in checkpoint tests

---------

Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-08 06:02:41 +00:00
陈志谦
98c067c22a fix(brightdata): drop stray $ in f-string search URLs (#7326)
get_search_url interpolated ${query} inside an f-string, producing
URLs like https://www.bing.com/search?q=$test. The URL is passed
straight to the SERP request, so every search carried the malformed
query string.

Fixes #7325
2026-09-08 04:55:52 +00:00
Bright Oparaji
1b855b4ff9 docs(events): remove stale params from handle_llm_stream_chunk docstring (#7313)
The Args block for ConsoleFormatter.handle_llm_stream_chunk listed
'chunk' and 'crew_tree' parameters that no longer exist on the method.
The signature was refactored to (accumulated_text, call_type) but the
docstring was not updated. Callers in event_listener.py pass only the
two real params.

Refs #7312.
2026-09-07 19:10:44 +05:30
Bright Oparaji
1f3e6113d7 docs(streaming): fix streaming output docstring examples (#7286)
* docs(streaming): fix streaming output docstring examples

CrewStreamingOutput's example called crew.kickoff() without setting
stream=True on the Crew, so the snippet returned a CrewOutput and did
not stream anything.

FlowStreamingOutput's example called flow.kickoff_streaming() and
flow.kickoff_streaming_async(); neither method exists. Flow-level
streaming is exposed through Flow.kickoff with stream=True and
returns a StreamSession, not a FlowStreamingOutput.

Refs #7285

* docs(streaming): clarify Flow.kickoff does not take stream param

Flow.kickoff() has no stream parameter; the runtime returns a
StreamSession when self.stream is True. Reword the FlowStreamingOutput
note so callers know to configure the Flow with stream=True before
calling kickoff().

Addresses CodeRabbit review on #7286.

* docs(streaming): restore FlowStreamingOutput example

Add back an Example block showing valid usage of FlowStreamingOutput.
The class is only ever constructed directly with a chunk-producing
iterator (see lib/crewai/tests/test_streaming.py), so the example
mirrors that pattern instead of the original snippet that referenced
non-existent Flow.kickoff_streaming methods.

Addresses review feedback on #7286.

* docs(streaming): swap FlowStreamingOutput example for public Flow streaming path

Replace the test-only FlowStreamingOutput(sync_iterator=...) example
with the actual public flow-streaming path: Flow.stream=True followed
by kickoff() / kickoff_async(), which return StreamSession /
AsyncStreamSession. The example is labeled explicitly to make clear
that Flow.kickoff() does not return a FlowStreamingOutput, and points
readers at the streaming-flow-execution guide.

Addresses review feedback on #7286.

---------

Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-07 16:27:15 +05:30
DrewWhittleNZ
193a166e61 fix(schema): support list-form type arrays in JSON schema conversion (#7281)
* fix(schema): support list-form "type" arrays in JSON schema conversion

_json_schema_to_pydantic_type already handles anyOf/oneOf for nullable
unions -- the form Pydantic's own schema generation produces for
Optional[T] fields -- but had no handling for the other, equally valid
JSON Schema way of expressing the same thing: a list-form type array,
e.g. {"type": ["string", "null"]}. This is what .NET/System.Text.Json
-based schema generators produce instead, so any MCP tool schema from
a non-Python server using this form crashed create_model_from_schema
outright with "Unsupported JSON schema type: ['string', 'null']" --
taking down the entire MCPServerAdapter connection, not just the one
affected tool.

Confirmed against a real self-hosted MCP server (Equibles,
github.com/daniel3303/Equibles): several of its tools (e.g.
ListCompanyDocuments's startDate/endDate filters) use exactly this
pattern, and MCPServerAdapter couldn't connect to it at all as a
result -- reproduced identically on both Windows and macOS.

Fix mirrors the existing anyOf/oneOf handling: treat each entry in a
list-form type the same way an anyOf member is handled, building a
Union of the corresponding Python types. A single-element list
collapses to that one type via typing.Union's own behavior, and
"null" entries resolve to None (matching how the type == "null"
branch already behaves), producing the same Optional[T] shape as the
anyOf case would.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(schema): preserve union members when applying FORMAT_TYPE_MAP

CodeRabbit flagged this reviewing #7058: the format override in
_json_schema_to_pydantic_field replaced the whole resolved type with
FORMAT_TYPE_MAP[format_], even when that type was a Union built from a
list-form `type` (or anyOf/oneOf) rather than a plain `str`. For a
schema like {"type": ["string", "null"], "format": "date-time"}, this
collapsed Union[str, None] down to plain datetime, silently dropping
the null option -- masked for non-required fields by the
Optional-rewrap at the end of the same function, but not for a
required-but-nullable field (a valid, if unusual, JSON Schema shape).
The same override also drops any non-string members of a multi-type
array (e.g. ["string", "integer", "null"]) regardless of required
status, since nothing rewraps those.

Narrow the override to the `str` member specifically: replace `type_`
outright when it's already plain `str`, or substitute only the `str`
element inside a Union via get_origin/get_args, leaving null and
other type-array members untouched.

Added two tests covering the previously-broken cases: a required
nullable formatted field, and a multi-type array (string/integer/null)
with a format.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-07 12:36:02 +05:30
Shxiao
7fe8317fc4 fix(llm): correct gpt-4o-mini context window 200000 -> 128000 (#7294)
gpt-4o-mini's official context window is 128,000 tokens (OpenAI
announcement and API docs; litellm's model database agrees), but the
shared LLM_CONTEXT_WINDOW_SIZES table and the OpenAI/Azure provider-local
tables listed 200000 - apparently copied from the neighboring o3-mini /
o4-mini entries. With CONTEXT_WINDOW_USAGE_RATIO = 0.85, crews resolved
the usable window to 170000 instead of 108800, letting history grow past
the model's real 128k limit and failing with API 400s on long runs.

Fixes #7293
2026-09-07 11:11:57 +05:30