mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-09-21 10:26:25 +00:00
dcb02da8e4ec032dec032c82f78e232cb0a9c0ae
66 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
c3f83cd866 |
feat(llm): re-resolve llm_overlay after input interpolation rewrites an agent's role (#7518)
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
* feat(llm): re-resolve llm_overlay after input interpolation rewrites an agent's role llm_overlay (#7500) resolves an agent's model at construction, by its role text. A CrewBase crew declares roles as templates in YAML — "Researcher for {repo}" — that Crew._interpolate_inputs rewrites at kickoff, after construction. An overlay keyed by the interpolated role, which is the text every trace records, never matched: on a production flow a plan routed 3 of 5 agents and left the two templated ones on their declared model. Agent.interpolate_inputs now looks the overlay up again when the rewrite changed the role: a key sets llm to the mapped model (create_llm, as construction does), carrying the streaming flag Crew.kickoff(stream=True) set on the instance it replaces; a miss, no active overlay, or an unchanged role leaves llm exactly as it is — construction's resolution and instance stand, nothing reverts. The executor binds agent.llm per task, after interpolation, so the task runs on the new model (pinned through prepare_kickoff). Not followed by the swap, documented: a task's string guardrail LLM, an auto-created Memory LLM, the crew_creation span. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(llm): read llm_overlay once per agent — a re-validation must not replace an llm the agent already runs on Found while battle-testing the previous commit with real calls: the event bus registers an agent in its RuntimeState the first time it emits, and RuntimeState(root=[agent]) re-runs Agent.post_init_setup on the same object. Inside a block that maps the agent's role, the construction-time overlay read (#7500) then replaced the llm the agent was already running on and dropped the state set on it (stream=True). An agent built outside the block picked the mapped model up on its second standalone kickoff inside one, against #7500's own contract; Crew.replay inside a block did the same. A private flag marks the construction-time read as done; a re-validation keeps the llm the agent has — the one construction resolved, or the one interpolate_inputs set when the role changed. Copies (kickoff_for_each) are new instances and read the overlay as before. Zero-cost tests through RuntimeState; docstrings corrected (a crew Memory built at kickoff does follow the swap; a stream must be iterated inside the block). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
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> |
||
|
|
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>
|
||
|
|
6ad3bf9390 |
fix(agents): render message content parts as text, not a python repr (#7109)
* fix(agents): render message content parts as text, not a Python repr
A message whose `content` is a multimodal parts list collapsed to
`str(content)` wherever a message had to become a string, so the model
saw `[{'type': 'text', 'text': 'hello'}]` in Current Task, and memory
stored and searched that same repr.
Four sites flattened it that way: the turn promoted into the executor
prompt, the memory recall query, what `_save_kickoff_to_memory` writes,
and `_message_content_text` (token estimation and oversized-message
splitting).
The extraction already existed, inline in `_format_messages_for_summary`
-- text blocks joined, or `[multimodal content]` when a list carries
none. This lifts it to `_content_parts_text` and routes all five callers
through it, so summary, prompt, memory and token counting agree.
`_message_content_text` becomes `message_content_text`: it now has a
caller outside its module, and `agent/core.py` imports only public names
from `agent_utils`. It is not re-exported from any `__init__`, so no
public import path changes.
`test_list_content_uses_str` pinned the repr, so it is intentionally
rewritten to pin the text. Every other existing caller is unchanged:
30 failures on main, 30 on this branch, identical names.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VwxiogL9mQg9q8cx4qLfYJ
* fix(agents): skip a content part whose text is not a string
`_content_parts_text` joined `block["text"]` straight into a string, and
content blocks are `dict[str, Any]` arriving from a model, so a `text`
key holding an int, dict or None raised `TypeError`. That was contained
to summarization before; routing the prompt, memory and token-estimation
paths through the same helper widened it to `Agent.kickoff`, where the
old `str()` had merely produced an ugly string.
Such a block carries no usable text, so it is skipped. A list left with
nothing usable still falls back to `[multimodal content]`.
Writes the convention down in AGENTS.md rather than leaving it in a
review thread: never `str()` a message's content, use
`message_content_text`. Four sites had independently reached for
`str()`, which is what this whole change is undoing.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VwxiogL9mQg9q8cx4qLfYJ
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
3df34d9169 |
fix: skip interception hooks on crewai-internal flows (#7079)
* fix: skip interception hooks on crewai-internal flows The `AgentExecutor` and the memory encoding/recall flows are `Flow` subclasses CrewAI runs for its own bookkeeping, and they were dispatching interception points as if their methods were the caller's steps — a hook saw machinery no user wrote, and a policy could deny a run over it. `Flow._skip_interception` now suppresses every point on a flow marked `is_crewai_internal`, except the execution boundary on machinery that is itself the run the caller asked for. A standalone `Agent.kickoff()` keeps its boundary and stays blockable, while the same executor bound to a crew or nested in a caller's flow stays silent, so boundaries only ever fire at the root. * docs: note that the resume match id feeds the boundary check `from_pending` seeds `_flow_match_id` from `instance.flow_id` for the usage listener's filter, and `resume_async` forces `current_flow_id` to it for the duration of the resume. `AgentExecutor._owns_execution_boundary` compares the two, so seeding the original persisted id instead would make a resumed standalone agent disown a boundary its kickoff already opened. |
||
|
|
47fa48d787 |
fix: close the agent scope on every failed attempt (#6997)
* fix: close the agent scope on every failed attempt `_check_execution_error` only emitted `AgentExecutionErrorEvent` once the retries were exhausted, but each retry re-enters `execute_task` and opens a new `agent_execution_started` scope. The scopes left open were then popped by the next ending event, so `task_failed` closed an agent scope instead of `task_started` and the task never got its own terminal pairing. Passthrough exceptions keep bubbling untouched, since a HITL pause must leave its scope open for the resume. * fix: return the retried result instead of finalizing it twice A retry reenters `execute_task`, whose own `_finalize_task_execution` already emitted `AgentExecutionCompletedEvent`, and the outer frame then finalized the same result again. The duplicate used to be absorbed by the `agent_execution_started` scope that a failed attempt left open, so closing every attempt exposed it: the extra completed event popped `task_started`, and the task and crew ends paired with the wrong scopes. --------- Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com> |
||
|
|
6388421510 |
[OSS-128] Handle oversized single messages during chunking (#7014)
* fix(OSS-128): split oversized messages before context chunking Normalize single messages that exceed the token budget before boundary chunking so summarization LLM calls do not replay the same context error. Reserve summarization prompt overhead from the chunk budget for large context windows. * refactor(OSS-128): inline message content text extraction as lambda * refactor(OSS-128): restore _message_content_text as a function Revert the lambda assignment to satisfy ruff E731 and keep the helper readable alongside the LLMMessage content shape. * refactor(OSS-128): drop summarization prompt overhead from chunk budget Use the full context window size for message chunking instead of subtracting a fixed prompt overhead. * fix(OSS-128): preserve LLMMessage fields when splitting oversized content Copy the original message attributes into each sub-message and only replace content when expanding oversized entries for chunking. * test(OSS-128): assert rendered summarization requests fit raw context Verify each chunked summarization payload, including system and instruction overhead, stays within the model limit implied by the 85% context window usage ratio. |
||
|
|
754d7323be |
fix: native tool calls broken over OpenAI Responses API (#6515)
* fix(agent): recognize OpenAI Responses API tool-call shape in native tool loop
is_tool_call_list() and extract_tool_call_info() only recognized
Chat-Completions-style ({"function": {...}}), Anthropic-style
({"name", "input"}), and Gemini-style tool-call shapes. The Responses
API's function_call output items are flat dicts shaped
{"id", "name", "arguments"} with no nested "function" key and no
"input" key, so they matched none of the checks.
This caused is_tool_call_list() to misclassify a genuine tool call as
a plain text answer, so the native tool loop returned the raw
tool-call list as the agent's final output instead of executing the
tool. Even after recognizing the shape, extract_tool_call_info() would
have passed an empty arguments dict, since it only read "input" for
the dict fallback.
Verified against LLM(api="responses") with tools attached: the agent
now correctly executes the tool with the parsed arguments instead of
returning the unexecuted tool-call JSON as its answer.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* test(agent_utils): cover OpenAI Responses API tool-call shape
Regression tests for is_tool_call_list() and extract_tool_call_info()
against the Responses API's flat {"id", "name", "arguments"} dict
shape, alongside existing Chat-Completions and Bedrock/Anthropic
shapes to confirm no regression there.
Confirmed these tests fail against the pre-fix version of
agent_utils.py (3 failures matching exactly the Responses API cases)
and pass against the fix in
|
||
|
|
8b646620be |
fix(events): stop a failed turn from marking the next one failed (#6965)
* fix(telemetry): stop a failed turn from marking the next one failed
A conversational session that opts out of deferred finalization ends each
turn with its own FlowFailedEvent, emitted inside kickoff() before
handle_turn() emits ConversationTurnFailedEvent. The flag was therefore set
after the run that owned it had already cleared it, survived on the
instance, and reported the next healthy turn as failed.
Gate the flag on the run still having its start stamp: a deferring session
keeps it (no per-turn terminal event), so it still reports a failed turn at
session end.
Also aligns the Flow Lifecycle Signals privacy row with the rest of the
telemetry table, which qualifies every user-authored field it records with
"should not include personal info", and fixes a telemetry test that built
InputResponse with an unsupported `value` keyword - ask() swallowed the
TypeError, so the test asserted the signals while exercising the
provider-error path.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test(telemetry): cover the streamed turn emitter of the failure flag
stream_turn() is the second emitter of ConversationTurnFailedEvent and
leaks the same flag as handle_turn(). Both regression tests fail on
|
||
|
|
7642e615a3 |
feat(flow): report flow outcome, duration and human-in-the-loop signals (#6961)
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
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(flow): report flow outcome and human-in-the-loop signals A flow reported only that it started. FlowFinishedEvent, FlowFailedEvent, MethodExecutionFailedEvent, MethodExecutionPausedEvent and FlowPausedEvent all reached the console formatter and stopped there, and FlowInputRequestedEvent, FlowInputReceivedEvent and ConversationTurnFailedEvent had no listener at all - so success rate, failure rate and every HITL pause were unmeasurable. Adds flow:completed, flow:failed, flow:method_failed, flow:paused, flow:hitl_paused, flow:input_requested, flow:input_received and flow:conversation_turn_failed as feature-usage spans, which the existing feature-usage aggregation already reads. Deliberately does not hold the Flow Execution span open to measure duration: flow_executions_daily_target counts those spans at start, so a run that never finishes would disappear from the count entirely. Duration needs its own span. Counts only - flow names, method names, error text and flow state are never recorded. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ASfWmW3RGy4qAQm6s8U9jH * feat(flow): record how long a flow ran Adds a Flow Completed span carrying flow_name, duration_ms and outcome, emitted when a flow finishes or fails. Elapsed time comes from a monotonic stamp taken at flow start and cleared on use. Kept separate from the Flow Execution span rather than holding that one open: it is emitted and closed at start and the daily aggregate counts it, so holding it would drop every run that is killed or crashes from the execution count. A killed run now simply has no Flow Completed row, and the count is unaffected. Elapsed time is an explicit duration_ms attribute rather than the span's own duration, which the ingestion pipeline stores as a suffixed string ("0.0000184s") that downstream aggregation parses to zero. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ASfWmW3RGy4qAQm6s8U9jH * feat(flow): tag flow origin and report resumed runs Two gaps found while testing the pause/resume path end to end. Resumed runs were invisible. There is no resume event: a restored run re-enters through kickoff(), so it looked identical to a fresh start. flow:resumed is derived from _is_execution_resuming at flow start, which makes flow:paused - flow:resumed the abandonment rate. Flow counts are dominated by CrewAI's own AgentExecutor, which is itself a Flow and runs once per agent execution - it is the top flow in the warehouse by a wide margin. Nothing distinguished it from a user's flows except guessing at the name. Both Flow Execution and Flow Completed now carry origin: "internal" when the flow class is defined under crewai.*, "user" otherwise. Tagging only the new span would have left the existing daily count unsplittable. Both span methods take origin with a default, so their signatures stay backward compatible. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ASfWmW3RGy4qAQm6s8U9jH * fix(flow): scope outcome and resume signals to user flows Two findings from review, both confirmed against the code. Outcome features counted CrewAI's own flows. The agent executor, memory encoding and memory recall are all Flows and all set suppress_flow_events; they run far more often than anything a user wrote, so flow:completed, flow:failed and flow:method_failed were mostly bookkeeping. Those three are now emitted only for flows the caller wrote. Internal outcomes are still recorded on the Flow Completed span, which carries origin. flow:resumed counted checkpoint restores. _is_execution_resuming is set both by from_pending (a human pause) and by a checkpoint restore that never paused for anyone, so resumes could exceed pauses and the abandonment rate was unusable. Keyed off _pending_feedback_context instead, which only from_pending sets. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ASfWmW3RGy4qAQm6s8U9jH * fix(flow): declare internal flows instead of inferring them Three findings from review, all confirmed against the code. Gating on suppress_flow_events was wrong. That flag asks for console quiet and is a public field, so a caller who set it on their own flow silently lost flow:completed, flow:failed and flow:method_failed. Deciding origin from the defining module was also wrong. Flow.from_declaration() returns a Flow typed in crewai.flow.flow, so a caller's declarative flow was reported as one of CrewAI's own - the inversion this split exists to prevent. Both had the same root cause: the discriminator was inferred. Flow now declares is_crewai_internal, set on the agent executor and the memory encoding/recall flows, and one helper serves both origin and the outcome gate. A failed conversational session was reported as completed. Its session closes with FlowFinishedEvent whatever happened, so a failed turn produced flow:conversation_turn_failed and flow:completed together. The turn failure is now recorded on the flow and read back when the session finishes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ASfWmW3RGy4qAQm6s8U9jH * refactor(flow): report flow lifecycle as spans, not feature usage Flow start, completion, pause and method failure are lifecycle facts, and the lifecycle is reported as spans everywhere else. Reporting them through feature usage put them in a table that aggregates on the feature string alone - it cannot carry origin, duration or outcome, so those signals could never be split between a user's flows and the ones CrewAI runs for itself. Adds Flow Paused and Flow Method Failed spans, and a resumed marker on Flow Execution so a run restored from a pause is not counted as a second fresh start. Removes the duplicate feature rows for completed, failed, method_failed, paused and resumed - every one of those facts is now on a span, with more attached to it than the feature row ever carried. Feature usage keeps only genuine adoption signals: flow:hitl_paused, flow:input_requested, flow:input_received and flow:conversation_turn_failed. Also clears the conversational turn-failure flag on every terminal path. A turn that failed without deferred finalization ends via FlowFailedEvent, and the flag left set there marked the next run on that instance as failed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ASfWmW3RGy4qAQm6s8U9jH * test(flow): update the flow_execution_span caller for the resumed argument Adding the resumed marker changed a signature that tests/utilities/test_events.py asserts on exactly, and that assertion was not re-run before pushing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ASfWmW3RGy4qAQm6s8U9jH * test(flow): make the checkpoint-restore guard actually guard The test asserted that flow:resumed was absent from feature usage, but that signal moved onto the Flow Execution span. The assertion could no longer fail, so a regression that mis-tagged checkpoint restores as resumes would have gone unnoticed. Now asserts the resumed attribute, and waits for the handlers: the manual emit dispatches asynchronously, so the previous shape also read its result before the listener had run. Confirmed it discriminates - keying resumed off _is_execution_resuming again fails it with [('RestoredFlow', True)] == [('RestoredFlow', False)]. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ASfWmW3RGy4qAQm6s8U9jH * fix(telemetry): record the resumed marker as a string Verified end to end against the live collector and ClickHouse: the pipeline encodes a boolean attribute as the presence of a vBool key, so false arrives as the key simply being absent. That is invisible in the schema and easy to read wrongly - crew_memory is extracted as "the attribute exists" and consequently reports 1 for 99.8% of crews against a field that defaults to False. A string leaves nothing to infer. Confirmed in the warehouse: the emitted span reads resumed = "false". Adds direct coverage for the attributes each flow span records, including both resumed values, and resets the Telemetry singleton in the helper so more than one span method can be exercised per session. 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> |
||
|
|
65a4b7cede |
fix: emit FlowStartedEvent when a boundary hook aborts the flow (#6953)
* fix: emit FlowStartedEvent when a boundary hook aborts the flow A HookAborted at EXECUTION_START or INPUT propagated before `FlowStartedEvent` was emitted, so a policy deny left logs but no record of the execution. On abort, stamp the state id and open the flow scope before re-raising: the deny surfaces as a started -> failed execution while normal runs keep the existing ordering — the started event carries hook-resolved inputs and `id` rewrites keep redirecting persistence restoration. * docs: translate execution-boundary-hooks page to ar, ko, and pt-BR The English page updated on this branch had never been localized. Translate it into the three supported locales following `DOCS_TRANSLATIONS.md` and register the page in each locale's navigation in `docs/docs.json`. Untranslated link targets (the step-hooks page and the aborting-an-operation anchor) are omitted rather than pointed at English, matching the locale navigation convention. |
||
|
|
e264e058a7 |
fix: preserve provider on LiteLLM-routed models (#6849)
* fix: preserve provider on LiteLLM-routed models LiteLLM construction computed the real provider in `__new__` but never passed it into init, so `BaseLLM` silently defaulted every shared-path model to `openai`. Infer the provider from a `provider/model` prefix when none is supplied so groq, cohere, mistral, and the rest report themselves correctly to callers like the policy engine. * fix: avoid double-prefixing instructor model strings With LiteLLM models now carrying a real `provider` while `model` keeps its `provider/name` form, `InternalInstructor` was building `groq/groq/...` for `instructor.from_provider`. Skip the prefix when the model string is already qualified. * fix: format LiteLLM multimodal content as OpenAI-shaped blocks Preserving the real provider on the LiteLLM path made `format_multimodal_content` emit Anthropic-native blocks for `anthropic/...` models, which LiteLLM rejects. Keep `provider` as the model identity for policies, but format multimodal blocks with the OpenAI chat schema when `is_litellm` is set. Expose the formatter helper on `BaseLLM` so native OpenAI/Azure completions share the same API. |
||
|
|
34230a0182 |
fix: harden brittle LLM event-bus mocks (#6861)
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
* fix: patch the event-bus singleton in usage event tests `TestEmitCallCompletedEventPassesUsage` mocked `CrewAIEventsBus.emit` on the class, but `_emit_call_completed_event` calls the `crewai_event_bus` singleton. Under CI that left the real bus emitting and the mock never seeing a call. Patch the singleton where `base_llm` imports it instead. * fix: harden llm call-failed event test against VCR fallback `test_llm_emits_call_failed_event` marked VCR while mocking `_handle_completion`, and its cassette recorded a successful reply. When the class-level patch missed under xdist, VCR replayed success and the expected exception never fired. Patch the instance method and drop the cassette so the failure path cannot silently succeed. * fix: patch the event-bus singleton instance in emit mocks `patch.object(CrewAIEventsBus, "emit")` misses callers when an instance-level `emit` shadows the class method — common under xdist after other suites touch the singleton. Patch `crewai_event_bus.emit` on the shared instance instead across the LLM event mock fixtures. |
||
|
|
453676c61a |
feat(tools): surface tool failures instead of reporting them as success (#6712)
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 / 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
* feat(tools): surface tool failures instead of reporting them as success
A tool can finish without raising and still fail to do what it was asked.
Slack answers HTTP 200 with `{"ok": false, "error": "channel_not_found"}`;
an MCP server sets `isError`; a CrewAI AMP action returns
`API request failed: ...`. In every case the call "worked", so the error
text reached the agent as an ordinary result, the agent narrated the
problem in prose, and the run was recorded as a success.
Concretely: five failed `slackbot_send_message` calls each rendered as
"Tool Execution Completed", the task passed, and the crew passed -- with
the only evidence being a sentence in the final answer. Nothing
downstream could tell the difference, and an agent that keeps going on a
step that silently did nothing builds the rest of its work on it.
Give that outcome a type and a reaction:
- `ToolFailure` -- what a tool returns instead of an error string. The
agent still reads prose via `as_agent_message()`, so model behavior is
unchanged; the framework now knows the call failed.
- `ToolFailurePolicy` -- `ignore` (previous behavior), `warn` (default:
record + emit, keep going), `raise` (abort with
`ToolExecutionFailedError`). Resolved most-specific-first: tool, task,
agent, crew.
- `ToolFailureDetectedEvent` -- emitted before a `raise` aborts, so
subscribers always observe the failure. `ToolUsageFinishedEvent` also
carries a `failure` field so a trace UI can mark the call failed
without correlating two events.
- `tool_failures` on `TaskOutput`, `CrewOutput` and `LiteAgentOutput`,
plus `has_tool_failures`, so consumers never parse a string.
Detection is strictly declarative -- no string sniffing, so a tool that
legitimately returns text about an error is never misread as failing.
Failures come from a returned `ToolFailure`, a raised exception, MCP
`isError`, a spent `max_usage_count`, or an unknown tool.
Wired into all four tool-execution paths (the ReAct path and the three
native function-calling implementations). Sources updated to report
structurally: `MCPClient.call_tool_result()` preserves `isError` that
`call_tool()` dropped, and `CrewAIPlatformActionTool` returns a
`ToolFailure` for non-2xx and for caught exceptions.
Two latent bugs fixed along the way: `ToolUsage` assumed every agent has
a `fingerprint` (LiteAgent does not), and policy resolution now tolerates
malformed values rather than letting telemetry take down a tool call.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETacm2dMASfpMAYUiDu5YG
* fix(tools): address review round 1 on tool-failure signalling
Five real defects from Bugbot, none of them cosmetic.
Tool-scoped policy never applied (high). `resolve_tool_failure_policy`
read `tool_failure_policy` off the object handed to it, but every
execution path passes the `CrewStructuredTool` wrapper, which never
carried the attribute -- and `BaseTool` never declared it in the first
place. A tool-scoped `raise`/`ignore` was silently ignored while the
docs and a unit test claimed otherwise; the test passed only because it
called the resolver directly with an authored tool. Declared the field on
`BaseTool`, propagated it through `to_structured_tool()` and
`CrewStructuredTool`, and made resolution fall back through
`_original_tool` so either shape works.
A failed call still printed the green "Completed" panel, then the red
one. That is the terminal version of the exact bug this PR is about.
Suppressed the success panel when the call reported failure.
A raised tool printed twice: `ToolUsageErrorEvent` already renders a red
panel, and the new failure panel repeated it. The event is still emitted
-- policy and traces need it -- but the duplicate console output is gone.
Both decisions now live in named predicates on `ConsoleFormatter` rather
than inline in the listener closure, so they are directly testable.
Unknown tools were reported on the ReAct path but silently ignored on all
three native paths, so the same miss was loud or silent depending on
executor style. Native paths now record `UNKNOWN_TOOL` too. This also
surfaced a live `NameError`: ruff had pruned `ToolFailureReason` from
`agent_utils` as unused, so the new branch would have crashed at runtime.
`LiteAgentOutput` had `tool_failures` but not `has_tool_failures`, which
the PR promised on all three output types -- an `AttributeError` for any
caller sharing one check across result types.
Testing: 16 further tests, 45 total. Two console tests were passing
vacuously because `emit()` dispatches sync handlers on a thread pool, so
the assertions raced the handler; they now assert on the predicates
directly, and the native-path test drains the bus with `flush()` and
checks the synchronously-written record. Full suite still matches
baseline exactly at 377 pre-existing failures.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETacm2dMASfpMAYUiDu5YG
* chore: update tool specifications
* fix(tools): address review round 2 and fix CI type failure
CI caught a type error I should have: widening `agent` to accept a
`LiteAgent` (so a standalone LiteAgent resolves its own policy) left the
declared signatures behind. Widened `execute_tool_and_check_finality`,
its async twin, and `ToolCallHookContext` to `Agent | BaseAgent |
LiteAgent | None`, which is what those actually receive now.
Seven CodeRabbit findings, all verified against the code first:
`raise` was being downgraded by three enclosing handlers. With
`max_execution_time` set, `_execute_with_timeout` wrapped every exception
in `RuntimeError`, so `_check_execution_error` no longer recognized the
passthrough and sent the task through the retry loop instead of aborting.
`StepExecutor.execute` turned it into `StepResult(success=False)` and let
the plan continue. `LiteAgent.kickoff` ran it through
`handle_unknown_error` and printed "This is likely a bug - please report
it" for what is a deliberate, configured stop.
Failure records were dropped on two paths. `reset_tool_failures()` only
ran in `_prepare_task_execution`, so `Agent.kickoff()` / `kickoff_async()`
— which enter through `_prepare_kickoff` — accumulated records across
runs. And a guardrail retry calls `execute_task` again, which resets the
agent, so a tool that failed on a blocked attempt vanished from the final
output entirely: a run could report zero failures having demonstrably
failed one. Failures now accumulate across guardrail attempts.
Writing the tests for that surfaced a further miss of my own:
`Agent.kickoff()` builds its `LiteAgentOutput` in `agent/core.py` via
`AgentExecutor`, not through `LiteAgent`, so `tool_failures` was always
empty there regardless of the recording fix. Wired up, and the LiteAgent
path now reads from whichever agent the executor was handed
(`original_agent` under kickoff, `self` standalone) rather than assuming.
`last_tool_failures` returns a copy, so a caller cannot mutate the
agent's record or watch it shift mid-run.
Testing: 7 further tests, 52 total, covering the timeout wrapper, the
retry limit, kickoff reset, the kickoff output path, copy semantics and
guardrail accumulation. Full suite matches baseline exactly at 377
pre-existing failures; mypy clean on every changed file.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETacm2dMASfpMAYUiDu5YG
* fix(tools): make crew-scoped policy real and close the last raise leak
Two findings, and the first was a documented feature that never worked.
`resolve_tool_failure_policy` consulted a crew, and the docs advertised
crew as a scope, but `Crew` had no `tool_failure_policy` field at all --
and even with one it was unreachable, because `BaseAgent` defaulted the
policy to `WARN` rather than `None`, so resolution always stopped at the
agent. Crew-level configuration was silently ignored.
Fixed by making "inherit" the default everywhere instead of baking `warn`
into one layer: `Crew` gains the field, and `BaseAgent`/`LiteAgent`
default to `None` like `Task` and `BaseTool` already did. The resolver
owns the single fallback, so the chain is genuinely
tool > task > agent > crew > warn and the effective default with nothing
configured is still `warn`. Reading `agent.tool_failure_policy` now
returns `None` (meaning "inherit") rather than `WARN`.
The other: `StepExecutor` re-raised `ToolExecutionFailedError` from its
outer handler, but the nested handler around the native-to-text tooling
fallback still caught it and returned `StepResult(success=False)`. An
agent whose LLM lacked native tool calling would therefore not abort
under `raise`. That is the third distinct place this exception was being
downgraded; it now re-raises there too.
Testing: 8 further tests, 60 total, including the full precedence chain
walked one level at a time and crew-scoped `raise`/`ignore` driven
end-to-end through `kickoff()` rather than only through the resolver --
the gap that let the original crew bug pass review. Full suite matches
baseline exactly at 377 pre-existing failures; mypy clean on every
changed file.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETacm2dMASfpMAYUiDu5YG
* docs: trim comments and docstrings on tool-failure signalling
Prose only -- no behavior change. Cut the module docstring, the longer
class and method docstrings, the multi-line inline comments, and the
verbose Field descriptions down to what actually earns its place. Net 87
lines lighter.
Kept the "why" in every case where the reason is non-obvious (why the
event fires before a raise, why the policy reads through the tool wrapper,
why the bus needs draining in tests) and dropped the restatements of what
the code already says.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETacm2dMASfpMAYUiDu5YG
* fix(tools): make ignore truly silent, stop caching failures, close 4 gaps
Six findings from the latest review round, all verified against the code
before touching it.
`ignore` was not silent. `ToolUsageFinishedEvent.failure` was set before
the policy ran, so traces still saw a failed call under a policy documented
as surfacing nothing. Worse, the console then showed *no* panel at all:
green was suppressed because `failure` was present, red was skipped because
`ignore` never emits `ToolFailureDetectedEvent`. New `reportable_failure()`
resolves the policy before the finished event and drops the flag under
`ignore`; wired into all four execution paths.
Failures were being cached. `CacheHandler.add` stored a `ToolFailure` like
any other result, so a transient error became permanent for the rest of the
run and every later hit re-reported a call that never re-ran. The cache now
refuses to store declared failures -- fixed at the single choke point rather
than at each of the four call sites.
A spent `max_usage_count` was invisible on the shared native path.
`BaseTool._claim_usage` returned a bare string that only the executors
recognising that exact message treated as a failure. It now returns a
`ToolFailure` with `USAGE_LIMIT`, so every path records it.
A guardrail returning a whole `TaskOutput` replaced the output without
carrying accumulated failures over, so earlier attempts vanished from
`CrewOutput.tool_failures`. New `merge_tool_failures()` combines and
deduplicates, and the retry-rebuild path uses it too.
A hook-blocked call inherited a cached failure and attributed it to a call
that never ran. Now cleared. Not reachable through the built-in cache once
failures stop being cached, so the test injects a custom cache handler that
does retain them -- verified to fail without the guard.
Also removed a `datetime` import left unused by the earlier console-test
rewrite.
Testing: 13 further tests, 73 total. Full suite matches baseline exactly at
377 pre-existing failures; the usage-limit suites that `_claim_usage`
touches pass unchanged; mypy clean on every changed file.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETacm2dMASfpMAYUiDu5YG
* fix(tools): let raise through the parallel native path, guard all handlers
Chasing down CodeRabbit's note about callers of
execute_single_native_tool_call turned up a fifth place this exception was
being downgraded: the experimental executor's parallel branch wrapped
future.result() in a broad except and folded the abort into a fake tool
result, so the remaining parallel calls carried on. The sequential path and
crew_agent_executor's parallel branch were already fine.
Five separate handlers have swallowed this during review, so added a guard
test asserting the passthrough at every site rather than trusting the next
one gets spotted.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETacm2dMASfpMAYUiDu5YG
* fix(tools): keep a failed tool out of the final answer, finish crew scope
Three more findings, all confirmed against the code.
A failed `result_as_answer` tool still became the task's output. The native
paths already excluded raised errors and hook blocks from short-circuiting,
but not declared failures -- so an error message silently became the answer,
which is the exact shape of bug this PR exists to prevent. Fixed on all
paths, and there were three independent override points, not one:
`ToolResult.result_as_answer` in tool_utils, the `execution_result`
finality checks in both executors, and `process_tool_results()`, which
reads `agent.tools_results` back separately. The first two fixes alone left
the behavior unchanged; only the third made the test pass.
`ToolUsage` never received a crew, so a crew-level `ignore` half-applied:
recording and `ToolFailureDetectedEvent` stayed quiet, but the flag was
still attached to `ToolUsageFinishedEvent`. It now takes and stores `crew`.
`CrewAgentExecutor.invoke`/`ainvoke` routed a deliberate stop through
`handle_unknown_error`, printing "An unknown error occurred" on verbose
runs. LiteAgent already special-cased this; both now do.
Testing: 5 further tests, 79 total, including that a *successful*
`result_as_answer` tool still short-circuits. Full suite matches baseline
exactly at 377 pre-existing failures; mypy clean on every changed file.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETacm2dMASfpMAYUiDu5YG
* fix(tools): report malformed tool args, correlate the failure event
Two findings from the latest round.
Malformed native tool arguments returned early with a plain error dict and
never reported a failure, so `ToolFailureReason.INVALID_INPUT` was declared
but unreferenced -- a bad tool call was absent from records, events and
`raise` aborts. `parse_tool_call_args` now carries an INVALID_INPUT failure
on the error dict and both executors report it before returning.
`ToolFailureDetectedEvent` never set `agent_id`, so a trace could not tie it
to a specific agent instance. Fixing that exposed the same gap running the
other way: `ToolUsage`'s own started/finished/error events never set
`agent_id` either, so on the ReAct path the paired finished event had
nothing to correlate against. Both now set it.
Set explicitly rather than via `from_agent`, which would also overwrite
`agent_role` and lose the `_original_role` preference those events already
apply -- a behavior change that has nothing to do with correlation.
Testing: 5 further tests, 84 total, asserting the ids match between the
failure event and its paired finished event. One existing test pinned the
exact key set of the parse-error dict and was updated for the new key. Full
suite matches baseline at 377 pre-existing failures; the one apparent
addition was the known `test_trace_enable_disable` order-flake, confirmed by
re-running rather than assumed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETacm2dMASfpMAYUiDu5YG
* fix(tools): scope failure accumulation per execution, drop deprecated executor
Two review requests from @lorenzejay.
Accumulation no longer lives as mutable state on the shared agent. A
ContextVar collector is opened around each execution -- task, kickoff, and
each guardrail retry -- and the output reads that collector directly instead
of copying the agent's list. ContextVars are copied per asyncio task and per
thread, so concurrent executions cannot see each other's records, and
nesting is safe for retries. `last_tool_failures` prefers the active
collector and falls back to the last completed execution, so the accessor is
correct during a run too. The per-execution reset that caused the erasure is
gone.
Reproducing this took some digging and the finding is worth recording: crew
tasks *cannot* hit it, because `AgentExecutor` refuses concurrent reuse of
one instance and raises. `agent.kickoff()` has no such guard, and there the
bug reproduces exactly as reported -- two concurrent kickoffs each returned
two records. The regression test forces the overlap with a barrier so it is
deterministic rather than timing-dependent, and I verified it reports [2, 2]
against the old behavior and [1, 1] now.
Removed the tool-failure integration from `CrewAgentExecutor` entirely; that
file is back to its state on main. Note the shared ReAct helper it calls
still records failures, since that is common code rather than new behavior in
the deprecated file -- so a `raise` policy will be swallowed by that
executor's generic handler. Flagged on the PR rather than papered over.
Testing: 89 total. Two tests I wrote for this were vacuous on the first
attempt -- they passed against the simulated pre-fix code -- so each
concurrency test was checked against the old behavior before being kept.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETacm2dMASfpMAYUiDu5YG
* fix(tools): report malformed calls everywhere, drop the unused block reason
Four findings.
`execute_single_native_tool_call` swallowed a JSON decode error into an empty
args dict and ran the tool with no input at all -- worse than not reporting
it. It now routes through `parse_tool_call_args` like the executors do, so
the StepExecutor/planning path reports INVALID_INPUT and returns instead of
executing. That also removes a duplicated inline parse.
The ReAct path returned a `ToolUsageError` message as an ordinary result
without reporting it, so a malformed call there was invisible while the
equivalent native failure was recorded. Now reported as INVALID_INPUT too.
`Agent.kickoff` opened a collector but no longer reset the agent-level list,
so `last_tool_failures` grew across kickoffs. Reset restored, matching task
execution.
`ToolFailureReason.BLOCKED_BY_HOOK` was declared and never produced. Rather
than start reporting hook blocks as failures, the member is removed: a block
is a deliberate decision by the hook author, and treating it as a failure
would make `raise` abort on an intentional veto. Added a guard test that every
remaining reason is actually produced somewhere, so a dead member cannot
reappear -- the same smell that flagged INVALID_INPUT last round.
Also switched the deprecation guard test to a single import style.
Testing: 6 further tests, 95 total, including that the tool does not run when
its args fail to parse. Full suite matches baseline at 377 pre-existing
failures; mypy clean.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETacm2dMASfpMAYUiDu5YG
* fix(tools): merge failures across kickoff guardrail retries, cancel siblings
Kickoff guardrail retries discarded the blocked attempt's failures. Each
retry calls `_execute_and_build_output`, which opens a fresh collector and
builds a new output, so a run could report zero failures having demonstrably
failed one -- the same bug already fixed on the task guardrail path, which
merges. Now merged there too. Verified the test fails without the fix.
Under `raise`, one parallel native tool aborting left its siblings running:
the pool waited for them and pending ones still started. It now shuts the
pool down with `cancel_futures=True` so a not-yet-started sibling never runs.
Threads already in flight cannot be interrupted in Python, so a concurrent
tool may still complete before the abort surfaces; that is noted at the call
site rather than left implied.
Also satisfied CodeQL by materialising the enum in the guard test's loop.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETacm2dMASfpMAYUiDu5YG
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Lorenze Jay <63378463+lorenzejay@users.noreply.github.com>
|
||
|
|
d52d0a1628 |
feat: emit FlowFailedEvent when a flow execution fails (#6718)
Some checks failed
* feat: emit FlowFailedEvent when a flow execution fails A failed flow never emitted a terminal lifecycle event, so the `flow_started` scope stayed open and consumers such as tracing closed the root span with a generic orphaned message instead of the real error. `kickoff_async` and the resume path now emit `FlowFailedEvent`, paired with `flow_started` and carrying the exception, after draining pending handlers and background memory writes. The resume path also emits the `MethodExecutionStartedEvent` it was missing for the method being resumed, so its finished or failed event pairs with its own scope instead of popping the flow's. * fix: skip FlowFailedEvent when the run never opened a scope The `kickoff_async` try block starts before `FlowStartedEvent` is emitted, so an abort in the execution-start hooks, in input handling or in state restore emitted a `flow_failed` with no opener, which pops an unrelated scope and warns about an empty scope stack. The failure event is now gated on the flow scope actually being open, either from this kickoff's `flow_started` or from a restored deferred session scope. |
||
|
|
cc0759854d |
fix(skills): resolve registry skills through the runtime's CrewAI+ client (#6658)
* fix(skills): resolve registry skills through the installed AMP client Skill downloads built their own `PlusAPI` and authenticated it from `CREWAI_USER_PAT`, the platform integration token, or the saved CLI login. Managed runtimes have no user credential to offer: they install a client of their own, which `load_agent_from_repository` already resolves through, so Agent Repository lookups worked while the skill downloads beside them failed with 401. Skills now resolve their client the same way, via `resolve_plus_client()` next to the hook it reads. A client that can't fetch skills falls back to environment credentials and warns, so older runtimes behave as they do today. `resolve_plus_response()` shares the sync/async bridging both lookups need, since `PlusAPI` is synchronous while managed clients are not. Version pinning, which the same bug was hiding: - Registry refs accept `@org/name@version`, and `@org/name@v1.2.0` since people write it both ways. `parse_skill_ref()` returns a `SkillRef(org, name, version)`; `parse_registry_ref()` keeps its `(org, name)` shape and drops the pin, so existing callers are unaffected - Agent Repository agents record a version per skill, which was parsed off the response and dropped. Those pins now travel with the refs, so publishing a new version of a skill no longer changes every agent that uses it - A pinned ref only accepts a project-local copy declaring that version in its `metadata.version` frontmatter, and the cache reports a miss when the version it recorded differs — so a pin re-resolves rather than loading another version. Unpinned refs keep hitting the cache as before - An unknown pin fails instead of quietly falling back to the newest version Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(skills): reject a blank version pin instead of floating to latest A blank `version` passed to `download_skill` read as "unpinned" and quietly resolved the latest version, which is not what a caller supplying one asked for — and it disagreed with `parse_skill_ref`, which already rejects empty pins. Not reachable through `resolve_registry_ref` or the Agent Repository auto-pinning, both of which only ever pass a non-empty version. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(skills): carry the caller's context into the worker thread When resolve_plus_response bridges an async client from inside a running loop it runs the coroutine on a worker thread, which starts with empty ContextVars. A client reading runtime state there — the platform integration token, flow context — would see defaults rather than the caller's values, which is hard to diagnose from the resulting auth or routing failure. Copy the context across, matching how the parallel-summarization bridge in this module already does it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
c06043f7e8 | fix: preserve strict tool schema property names (#6628) | ||
|
|
85c467dfe2 |
feat(cli): run declarative flows on the TUI (headless terminal fallback) (#6484)
Some checks failed
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (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
* feat(cli): run declarative flows on the TUI with a headless terminal fallback Declarative flows now run on the CrewRunApp TUI when interactive, matching declarative crews and conversational flows. Headless contexts — CREWAI_DMN (deploy), piped output, CI, any non-TTY — fall back to the direct-terminal kickoff, gated by is_interactive() (folds in the CREWAI_DMN check and requires a real TTY). The TUI shows per-method progress: a new STEPS panel driven by flow method events (FlowStarted / MethodExecutionStarted/Finished/Failed), each labeled with its declarative call type (crew/agent/expression/…) read from the flow definition. Crews/agents inside a method keep streaming in the main panel via the existing crew/task/LLM handlers. - crew_run_tui.py: _run_flow_worker (flow.kickoff in a thread worker; reuses _on_crew_done/_on_crew_failed + _stringify_output), _is_flow_run gate so crew rendering is byte-identical, flow-event subscriptions building _flow_steps, and the STEPS sidebar + flow-aware header. - run_declarative_flow.py: is_interactive() branch → _run_declarative_flow_tui (EventListener, method-type map from flow._definition, crew-parity exit codes and deploy chaining) or the existing terminal path. Deviation from the approved plan: gate on is_interactive() rather than is_dmn_mode_enabled() alone, so non-TTY runs (CI/pipes/CliRunner) never launch a TUI — this also keeps existing headless flow tests green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RBYGqJHC2TMC6fonFziuuh * fix(cli): force flow events on for the TUI so STEPS renders under suppress_flow_events Review follow-up: the STEPS panel and header are driven by flow method events (FlowStarted / MethodExecution*), but the declarative runtime skips emitting those when the flow declared config.suppress_flow_events. Interactive TUI runs would then keep STEPS on "waiting…" and the header on "Starting flow…" while nested crews still execute. _run_declarative_flow_tui now forces flow.suppress_flow_events = False for the interactive run (mirroring how the conversational path mutates the flow for the TUI). The headless/terminal path never reaches this and keeps the flow's declared setting. Regression test: test_run_declarative_flow_tui_enables_flow_events. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RBYGqJHC2TMC6fonFziuuh * fix(cli): clear flow header's current method when a method ends Review follow-up: the flow header keys off _current_method, which was set on MethodExecutionStarted but never cleared on Finished/Failed. Between steps (or after a failed method before kickoff exits) the header kept spinning the old method name while the STEPS sidebar already showed it done/failed. _clear_current_method now drops the header's active method when it ends, falling back to another still-active step (methods can overlap) or none. The header's idle fallback shows "Working…" once a step has run and "Starting flow…" only before the first method. Tests: test_current_method_clears_and_falls_back_across_overlap, plus a _current_method assertion in test_flow_method_events_build_steps. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RBYGqJHC2TMC6fonFziuuh * fix: suppress flow console panels in TUI mode; clear header agent on method change Two review follow-ups: 1) Method panels break Textual TUI (Cursor): forcing suppress_flow_events off so the STEPS panel receives events also un-gated the EventListener's Rich flow/method panels (ConsoleFormatter.print_panel prints is_flow=True panels regardless of verbose), which interleave with Textual and corrupt the TUI. print_panel now skips is_flow panels when is_tui_mode() is set (the same context the TUI worker already establishes and the tracing listeners already honor). Non-TUI/headless flow runs are unaffected. Test: test_console_formatter_tui_mode. 2) Flow header showed a stale agent (CodeRabbit): _current_agent persisted across methods. It's now cleared when a method starts and when the active method changes, so the header never shows the previous method's agent until a new agent event arrives. Test: test_flow_method_transitions_clear_current_agent. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RBYGqJHC2TMC6fonFziuuh * fix(cli): keep flow name over nested crews; show paused flow methods Two review follow-ups on the flow TUI: 1) Crew kickoff renamed the flow (Cursor): CrewKickoffStartedEvent overwrote _crew_name / the app title with a nested `call: crew` step's crew name, so the post-run summary could be labeled with a child crew. The rename is now gated on `not _is_flow_run`, preserving the flow's name; crew runs still adopt the crew name. Tests: test_crew_kickoff_does_not_rename_flow_run, test_crew_kickoff_renames_in_crew_mode. 2) Paused methods showed active (Cursor): the TUI didn't handle MethodExecutionPausedEvent, so a @human_feedback pause left the STEPS spinner running (flow status panels are suppressed in TUI mode). It now marks the step "paused" (⏸, teal) and the header shows "waiting for feedback" instead of a spinner. Test: test_method_paused_marks_step_paused. Note: interactively *providing* human feedback from the flow TUI is a separate follow-up; this only makes the pause visible instead of a silent stuck spinner. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RBYGqJHC2TMC6fonFziuuh * fix(cli): run human-feedback declarative flows on the terminal, not the TUI Two review follow-ups, both rooted in @human_feedback methods: - Paused flow marked complete (Cursor): async human feedback makes kickoff RETURN a HumanFeedbackPending marker (not raise), which _run_flow_worker would stringify and report as a successful completion with exit 0. - Sync feedback breaks TUI (Cursor): default (sync) @human_feedback collects input via the flow runtime's Rich console.print + blocking input(), which interleaves with Textual and leaves the user unable to review output or submit feedback. run_declarative_flow now routes any flow whose declarative definition declares human feedback (_flow_uses_human_feedback) to the terminal path, where blocking input and Rich prompts work natively — regardless of interactivity. Non-feedback flows still get the TUI. Tests: test_flow_uses_human_feedback_detection, test_human_feedback_flow_uses_terminal_even_when_interactive. Fully interactive human feedback inside the TUI remains a separate follow-up. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RBYGqJHC2TMC6fonFziuuh * refactor(cli): address review — Flow typing, debug logging, flow-vs-crew naming Review follow-ups from @lucasgomide: - Type flow helpers as Flow[Any] (via TYPE_CHECKING import) instead of Any and drop the defensive getattr chains — _definition is a typed PrivateAttr and name/suppress_flow_events are typed fields, so attribute access is safe. - Replace the silent `except Exception: pass` blocks with logger.debug(..., exc_info=True) so unexpected failures are diagnosable in the field (_flow_method_types, _flow_uses_human_feedback, suppress_flow_events toggle). - Flow-vs-crew naming: the flow worker now uses group="flow" (was the misleading "crew"), and the shared completion/failure handlers report the run with an entity-aware noun ("flow" vs "crew") via _run_noun. Deferred (separate PR): the os._exit(130) hard-kill on user quit is kept as-is to match the existing crew convention (run_crew._run_json_crew). Tests: test_flow_done_uses_flow_wording_for_unfinished_tool; existing crew wording tests unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RBYGqJHC2TMC6fonFziuuh --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
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 |
||
|
|
720a4c7216 |
Keep flow method progress visible for nested crews (#6295)
Inline crews default to `verbose=False`. They set the shared formatter's `verbose` value in `lib/crewai/src/crewai/crew.py`, which could hide flow method status from `lib/crewai/src/crewai/events/utils/ console_formatter.py`. Remove that `verbose` check for flow method status. Flow output is still controlled by `suppress_flow_events`. Normal quiet crews are unchanged because crew, task, and agent logs still use their own `verbose` checks. |
||
|
|
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.
|
||
|
|
9d44d0a5e5 | Serialize concrete Pydantic subclasses (#6187) | ||
|
|
fe2c236601 |
Add each composite action to FlowDefinition (#6164)
Lets a definition loop over an array without writing Python. Each
iteration exposes `item` and prior steps `outputs`.
```yaml
do:
call: each
in: state.rows
do:
- normalize:
call: tool
ref: my_tools:NormalizeRowTool
with: { row: "${ item }" }
- lead_scoring:
call: agent
# ...
```
|
||
|
|
bb477f8a91 |
JSON first crews (#6131)
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 / 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
* feat(cli): introduce JSON crew project support and TUI enhancements - Added support for creating and running JSON-defined crew projects, allowing users to scaffold projects with a new `create_json_crew.py` file. - Implemented a full-screen Textual TUI for crew execution in `crew_run_tui.py`, enhancing user interaction with a two-column layout. - Updated `run_crew.py` to prioritize JSON crew projects and added daemon mode for running without TUI. - Introduced interactive pickers in `tui_picker.py` for improved CLI prompts. - Enhanced validation for JSON crew files in `validate.py` to ensure proper structure and agent definitions. - Updated `.gitignore` to exclude demo and crewai directories. * feat: update LLM model references to gpt-5.4-mini - Changed default LLM model from gpt-4o-mini to gpt-5.4-mini across various files, including CLI options, JSON crew configurations, and agent definitions. - Enhanced benchmark and human feedback functionalities to utilize the new model. - Improved user interface elements in the TUI for better interaction and feedback during execution. - Added support for new skills directory in JSON crew project creation. * feat(benchmark): add crew-level benchmarking functionality - Introduced a new `benchmark` command in the CLI for crew-level benchmarking, allowing users to specify agents, models, and timeout settings. - Implemented `CrewBenchmarkCase` to handle crew-level benchmark cases with inputs and criteria. - Enhanced the benchmark runner to support progress tracking and detailed reporting of results for multiple models. - Added tests for loading crew benchmark cases and validating their structure. - Updated existing benchmark functions to accommodate the new crew-level execution model. * feat(cli): enhance JSON crew project functionality and TUI improvements - Added optional agent-level guardrails and advanced options in JSON crew configurations to improve output validation and flexibility. - Updated the TUI to better handle plan step statuses, including visual indicators for task completion and failure. - Introduced methods for parsing and managing step observation events, ensuring accurate updates to task statuses during execution. - Enhanced validation for JSON crew projects, ensuring proper structure and error handling for agent and task definitions. - Added comprehensive tests for new features and validation logic, ensuring robustness in JSON crew project handling. * refactor(cli): streamline JSON crew project handling and improve validation - Refactored JSON crew project loading and validation logic to enhance clarity and maintainability. - Introduced utility functions for finding JSON crew files, improving code reuse across modules. - Removed deprecated benchmark functionality and associated tests to simplify the codebase. - Updated CLI commands to utilize the new JSON project structure, ensuring compatibility with recent changes. - Enhanced test coverage for JSON crew project features, ensuring robust validation and error handling. * feat(cli): enhance activity log navigation and focus management - Added functionality to focus on the activity log when navigating through log entries. - Implemented refresh logic for the log panel to ensure updates are displayed correctly during navigation. - Improved keyboard navigation for log entries, allowing users to expand and scroll through logs seamlessly. - Added tests to verify the correct behavior of log navigation and focus management in the TUI. * feat(cli): enhance JSON crew project interaction and input handling - Introduced a new function to enable prompt line editing for better user experience during input prompts. - Updated the JSON crew project wizards to show interpolation hints for dynamic values, improving user guidance. - Enhanced the handling of missing input placeholders by prompting users for required values during crew setup. - Refactored the crew run logic to ensure proper loading and preparation of JSON-defined crews, including runtime input management. - Added tests to verify the correct behavior of new input handling features and JSON crew project interactions. * feat(cli): improve crew project input prompts and event handling - Enhanced the `_prompt_text` function to allow for configurable spacing before prompts, improving user experience during input collection. - Updated the wizards for agent and task creation to utilize the new prompt configuration, ensuring a more compact and streamlined interaction. - Introduced new plan step lifecycle events (`PlanStepStartedEvent`, `PlanStepCompletedEvent`) to better track the execution status of plan steps. - Refactored the step executor to emit these events during the execution of tasks, improving observability and debugging capabilities. - Added tests to verify the correct behavior of new prompt handling and event emissions during crew project execution. * fix: refine json-first crew interactions * fix: prioritize common json crew tools * fix: make json crew more tools expandable * fix: show json crew tools by category * feat(memory): update default embedder to OpenAI text-embedding-3-large and enhance memory compatibility - Changed the default embedding model for Memory to OpenAI text-embedding-3-large, which uses 3072-dimensional vectors. - Added warnings regarding compatibility issues with existing local memory stores created with 1536-dimensional embeddings. - Updated documentation to reflect the new default embedder and its configuration options. - Enhanced the CLI and codebase to support the new embedding model across various components, ensuring a seamless transition for users. * fix: address PR review feedback for JSON-first crews Review blockers: - Forward trained_agents_file to JSON crews: crewai run -f now exports CREWAI_TRAINED_AGENTS_FILE for the in-process JSON crew path - Wizard agent picker: Esc/cancel now reprompts instead of silently assigning the first agent - JSON tool resolution hard-fails: unknown tool names, missing custom tool files, and invalid custom tool modules raise JSONProjectError with actionable messages instead of warn-and-continue - Embedding dimension mismatch: LanceDB and Qdrant Edge storages raise EmbeddingDimensionMismatchError with reset/pin guidance instead of silently zero-filling vectors or returning empty search results - Custom tool code execution documented in loader docstring and the scaffolded project README CI fixes: - ruff format across lib/ - All 133 PR-introduced mypy errors fixed (llm.py lazy-litellm and cli.py lazy command shims now use TYPE_CHECKING imports; textual is_mounted misuse fixed; pick_many overloads; misc annotations) Bot review comments: - Empty except blocks now have explanatory comments or debug logging - Removed unused _C_BG/_C_PANEL/_C_BORDER globals and redundant import re; tests use a single import style for create_json_crew Tests: trained-agents propagation, wizard cancel, tool resolution failures, and dimension mismatch guidance. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: address second round of PR review comments Cursor Bugbot: - Wizard agent slugs: strip to [a-z0-9_] and fall back to agent_<n> so symbol-only roles can't produce an empty agents/.jsonc filename - Wizard task names: dedupe against prior task names and fall back to task_<n> for symbol-only descriptions CodeRabbit: - Agent.message(): import Task explicitly at runtime instead of relying on the namespace injection done by crewai/__init__ - Async executor: move the native-tools-unsupported fallback from _ainvoke_loop_react (self-recursion) to _ainvoke_loop_native_tools, mirroring the sync implementation - StepExecutor downgrade: keep the in-step conversation and append the text-tooling instructions instead of rebuilding messages, so completed native tool calls are not re-executed - crewai-files: extension-based MIME lookup now runs before byte sniffing so csv/xml types are not degraded to text/plain - Memory storages: validate every record in a save() batch against a consistent embedding dimension (LanceDB previously checked only the first record); added mixed-batch tests - _print_post_tui_summary now typed against CrewRunApp - Docs: Azure OpenAI default embedder change called out in the memory migration warning and provider table Code quality bots: - Removed unused _C_YELLOW/_C_CYAN (crew_run_tui) and _GREEN (tui_picker) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(cli): accordion tool picker in JSON crew wizard The flat tool list had grown to ~90 rows. The picker now shows: - Common tools always visible at the top - Every other category as a single expandable row with tool and selection counts (e.g. "Search & Research (27 tools, 2 selected)") - Expanding a category collapses the previously expanded one - Selections persist across expand/collapse via new preselected support in pick_many; cursor follows the toggled category row tui_picker gains preselected + initial_cursor options on pick_many, and Esc in multi-select now confirms the current selection instead of discarding it (required so collapsing can't silently drop choices). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(cli): remove --daemon flag from crewai run The flag only affected JSON crew projects — classic and flow projects ignored it entirely, which made the behavior inconsistent. Removed the option, the daemon code path (_run_json_crew_daemon), and its helper (_load_json_crew_with_inputs). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test: update run command tests after --daemon removal lib/crewai/tests/cli/test_run_crew.py still asserted the old run_crew(trained_agents_file=..., daemon=False) call signature. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(cli): exit codes, mid-run quit, async statuses, hyphen placeholders Addresses the latest Bugbot review round: - Failed JSON crew runs now exit non-zero (SystemExit(1)) so scripts and CI don't treat failures as success, mirroring the classic path - Quitting the TUI mid-run now ends the process (os._exit(130)); kickoff runs in a thread worker that cannot be force-cancelled, so letting the CLI return would leave LLM/tool work burning tokens in the background - Sidebar task statuses are now async-safe: completion/failure events resolve the task's own row via identity instead of assuming the most recently started task, and starting a task no longer blanket-marks earlier active rows as done - The runtime-input prompt regex now accepts hyphenated placeholder names ({my-topic}), matching kickoff's interpolation pattern Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: validation safety, custom tool sandboxing, TUI log integrity, memory error surfacing - Deploy validation no longer executes project code: validation mode checks tool declarations structurally (well-formed entries, custom tool file exists) without importing or instantiating anything. custom:<name> resolution only happens on the actual run path. - custom:<name> is constrained to [A-Za-z_][A-Za-z0-9_]* and the resolved path must stay inside the project's tools/ directory, so custom:../foo or absolute-path names cannot execute code outside it. Tool paths resolve relative to the crew project root, not cwd. - TUI task logs are built from per-task state captured at task start (idx, description, agent, start time); an out-of-order completion takes its output from the event and no longer steals or resets the current task's streamed steps/output. - EmbeddingDimensionMismatchError now inherits ValueError instead of RuntimeError so background saves surface it through MemorySaveFailedEvent instead of silently dropping the save; the shutdown catch in _background_encode_batch is narrowed to the "cannot schedule new futures" case. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(cli): declared project type wins over crew.json presence A flow project that also contains a crew.json(c) file now runs and validates as the flow it declares in pyproject.toml instead of being hijacked by the JSON crew path. Both crewai run (_has_json_crew) and deploy validation (_is_json_crew) check tool.crewai.type; a missing or unreadable pyproject still means a bare JSON crew project. Also documents why StepObservationFailedEvent intentionally marks the plan step "done": the event signals an observer failure, not a step failure, and the executor continues past it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(cli): type the declared_type locals so mypy stays clean Comparing an Any-typed .get() chain returns Any, which tripped no-any-return on the previous commit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
da8fe8c715 |
fix: respect suppress_flow_events for method-execution events (#6095)
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 / 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: respect suppress_flow_events for method-execution events * test: align suppressed-flow test with new method-event behavior |
||
|
|
f3a15a4f07 |
feat(lock_store): make locking backend overridable (#6015)
* feat(lock_store): make locking backend overridable Allow the centralised lock factory to use a pluggable backend instead of the hardcoded Redis/file selection. Backends are resolved with precedence override > CREWAI_LOCK_FACTORY env > built-in default: - set_lock_backend()/reset_lock_backend() and a scoped lock_backend() context manager for programmatic overrides - CREWAI_LOCK_FACTORY="module:callable" env import-path, resolved lazily and cached, with clear errors on malformed or non-callable specs - LockBackend Protocol documenting the contract (raw name in, context manager out; backend owns its namespacing) Default Redis/file behavior is unchanged when nothing is overridden. * refactor(lock_store): use explicit body for LockBackend protocol method Replace the no-op `...` body with `raise NotImplementedError` to satisfy the CodeQL ineffectual-statement check while keeping the Protocol structural-typing only. * refactor(lock_store): drop scoped lock_backend context manager Keep the backend overridable via set_lock_backend/reset_lock_backend and the CREWAI_LOCK_FACTORY env path, but remove the scoped lock_backend() context manager. It was speculative surface and the only thread-unsafe piece (racy save/restore of the module global); nothing depends on it. * refactor(lock_store): drop reset_lock_backend alias reset_lock_backend() was just set_lock_backend(None); callers use that directly. Clearing the override is documented on set_lock_backend. * style(lock_store): apply ruff format * refactor(lock_store): simplify overridable backend to a single setter Reduce the override surface to just set_lock_backend(): lock() uses the custom backend when one is set, otherwise the unchanged Redis/file default. Drop the CREWAI_LOCK_FACTORY env import-path, the runtime_checkable Protocol, the precedence resolver, and the getter — a custom backend is now any callable(name, *, timeout) -> context manager, registered in process. * fix(lock_store): snapshot backend to avoid check-then-call race Read the module-global backend once into a local before the None check and the call, so a concurrent set_lock_backend(None) cannot make lock() invoke None. * docs(lock_store): clarify name handling for custom backends The default namespaces the lock name; custom backends receive it verbatim. Correct the lock() docstring which implied namespacing always happens. * docs(lock_store): note set_lock_backend is for one-time startup setup |
||
|
|
fd10c64148 | chore(crewai): drop self-explanatory comments | ||
|
|
32f5e74449 |
Skip lock acquisition in CrewTrainingHandler.load when file is missing (#5935)
Every agent kickoff calls _use_trained_data, which calls CrewTrainingHandler(...).load(). Since #4827 wrapped load() in store_lock, that means every kickoff acquires the cross-process (Redis-backed when REDIS_URL is set) lock even on deployments that never train and have no trained-agents file on disk. Move the missing/empty-file short-circuit above store_lock so the lock is only acquired when there is actually a file to read. save() and the real read remain locked. |
||
|
|
3322634625 |
feat: deprecate CrewAgentExecutor, default Crew agents to AgentExecutor (#5745)
* feat: deprecate CrewAgentExecutor, default Crew agents to AgentExecutor * regen cassettes * fix tests * addressing pr comments --------- Co-authored-by: Lorenze Jay <63378463+lorenzejay@users.noreply.github.com> Co-authored-by: lorenzejay <lorenzejaytech@gmail.com> Co-authored-by: Greyson LaLonde <greyson.r.lalonde@gmail.com> |
||
|
|
93e786d263 | refactor: extract CLI into standalone crewai-cli package | ||
|
|
095f796922 | fix: prevent result_as_answer from returning hook-block message as final answer | ||
|
|
bfbdba426f |
fix: prevent result_as_answer from returning error as final answer
When a tool with result_as_answer=True raises an exception, the agent was receiving result_as_answer=True and returning the error string as the final answer. Now we set result_as_answer=False when an error event is emitted, allowing the agent to reflect and retry. Fixes crewAIInc/crewAI#5156 --------- Co-authored-by: NIK-TIGER-BILL <nik.tiger.bill@github.com> Co-authored-by: Greyson LaLonde <greyson.r.lalonde@gmail.com> |
||
|
|
17e82743f6 | fix: handle BaseModel input in convert_to_model | ||
|
|
70f391994e | fix(converter): fall through when JSON regex match isn't valid JSON | ||
|
|
14c3963d2c | fix(instructor): forward base_url and api_key to instructor.from_provider | ||
|
|
63fc2e7588 |
fix: complete recursive MCP schema handling
resolve_refs now returns type-preserving stubs instead of {} for
circular $refs, and create_model_from_schema catches JsonRefError
to fall back to lazy top-level-only inlining.
|
||
|
|
29fc4ac226 |
feat: add deploy validation CLI and improve LLM initialization ergonomics
Add crewai deploy validate to check project structure, dependencies, imports, and env usage before deploy Run validation automatically in deploy create and deploy push with skip flag support Return structured findings with stable codes and hints Add test coverage for validation scenarios refactor: defer LLM client construction to first use Move SDK client creation out of model initialization into lazy getters Add _get_sync_client and _get_async_client across providers Route all provider calls through lazy getters Surface credential errors at first real invocation refactor: standardize provider client access Align async paths to use _get_async_client Avoid client construction in lightweight config accessors Simplify provider lifecycle and improve consistency test: update suite for new behavior Update tests for lazy initialization contract Update CLI tests for validation flow and skip flag Expand coverage for provider initialization paths |
||
|
|
0e590ff669 | refactor: use shared I18N_DEFAULT singleton | ||
|
|
0450d06a65 |
refactor: use shared PRINTER singleton
Some checks failed
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (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
|
||
|
|
68e943be68 | feat: emit token usage data in LLMCallCompletedEvent | ||
|
|
6b262f5a6d |
Fix lock_store crash when redis package is not installed (#4943)
Some checks failed
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (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 lock_store crash when redis package is not installed `REDIS_URL` being set was enough to trigger a Redis lock, which would raise `ImportError` if the `redis` package wasn't available. Added `_redis_available()` to guard on both the env var and the import. * Simplify tests * Simplify tests #2 |
||
|
|
32d7b4a8d4 |
Lorenze/feat/plan execute pattern (#4817)
* feat: introduce PlanningConfig for enhanced agent planning capabilities (#4344) * feat: introduce PlanningConfig for enhanced agent planning capabilities This update adds a new PlanningConfig class to manage agent planning configurations, allowing for customizable planning behavior before task execution. The existing reasoning parameter is deprecated in favor of this new configuration, ensuring backward compatibility while enhancing the planning process. Additionally, the Agent class has been updated to utilize this new configuration, and relevant utility functions have been adjusted accordingly. Tests have been added to validate the new planning functionality and ensure proper integration with existing agent workflows. * dropping redundancy * fix test * revert handle_reasoning here * refactor: update reasoning handling in Agent class This commit modifies the Agent class to conditionally call the handle_reasoning function based on the executor class being used. The legacy CrewAgentExecutor will continue to utilize handle_reasoning, while the new AgentExecutor will manage planning internally. Additionally, the PlanningConfig class has been referenced in the documentation to clarify its role in enabling or disabling planning. Tests have been updated to reflect these changes and ensure proper functionality. * improve planning prompts * matching * refactor: remove default enabled flag from PlanningConfig in Agent class * more cassettes * fix test * refactor: update planning prompt and remove deprecated methods in reasoning handler * improve planning prompt * Lorenze/feat planning pt 2 todo list gen (#4449) * feat: introduce PlanningConfig for enhanced agent planning capabilities This update adds a new PlanningConfig class to manage agent planning configurations, allowing for customizable planning behavior before task execution. The existing reasoning parameter is deprecated in favor of this new configuration, ensuring backward compatibility while enhancing the planning process. Additionally, the Agent class has been updated to utilize this new configuration, and relevant utility functions have been adjusted accordingly. Tests have been added to validate the new planning functionality and ensure proper integration with existing agent workflows. * dropping redundancy * fix test * revert handle_reasoning here * refactor: update reasoning handling in Agent class This commit modifies the Agent class to conditionally call the handle_reasoning function based on the executor class being used. The legacy CrewAgentExecutor will continue to utilize handle_reasoning, while the new AgentExecutor will manage planning internally. Additionally, the PlanningConfig class has been referenced in the documentation to clarify its role in enabling or disabling planning. Tests have been updated to reflect these changes and ensure proper functionality. * improve planning prompts * matching * refactor: remove default enabled flag from PlanningConfig in Agent class * more cassettes * fix test * feat: enhance agent planning with structured todo management This commit introduces a new planning system within the AgentExecutor class, allowing for the creation of structured todo items from planning steps. The TodoList and TodoItem models have been added to facilitate tracking of plan execution. The reasoning plan now includes a list of steps, improving the clarity and organization of agent tasks. Additionally, tests have been added to validate the new planning functionality and ensure proper integration with existing workflows. * refactor: update planning prompt and remove deprecated methods in reasoning handler * improve planning prompt * improve handler * linted * linted * Lorenze/feat/planning pt 3 todo list execution (#4450) * feat: introduce PlanningConfig for enhanced agent planning capabilities This update adds a new PlanningConfig class to manage agent planning configurations, allowing for customizable planning behavior before task execution. The existing reasoning parameter is deprecated in favor of this new configuration, ensuring backward compatibility while enhancing the planning process. Additionally, the Agent class has been updated to utilize this new configuration, and relevant utility functions have been adjusted accordingly. Tests have been added to validate the new planning functionality and ensure proper integration with existing agent workflows. * dropping redundancy * fix test * revert handle_reasoning here * refactor: update reasoning handling in Agent class This commit modifies the Agent class to conditionally call the handle_reasoning function based on the executor class being used. The legacy CrewAgentExecutor will continue to utilize handle_reasoning, while the new AgentExecutor will manage planning internally. Additionally, the PlanningConfig class has been referenced in the documentation to clarify its role in enabling or disabling planning. Tests have been updated to reflect these changes and ensure proper functionality. * improve planning prompts * matching * refactor: remove default enabled flag from PlanningConfig in Agent class * more cassettes * fix test * feat: enhance agent planning with structured todo management This commit introduces a new planning system within the AgentExecutor class, allowing for the creation of structured todo items from planning steps. The TodoList and TodoItem models have been added to facilitate tracking of plan execution. The reasoning plan now includes a list of steps, improving the clarity and organization of agent tasks. Additionally, tests have been added to validate the new planning functionality and ensure proper integration with existing workflows. * refactor: update planning prompt and remove deprecated methods in reasoning handler * improve planning prompt * improve handler * execute todos and be able to track them * feat: introduce PlannerObserver and StepExecutor for enhanced plan execution This commit adds the PlannerObserver and StepExecutor classes to the CrewAI framework, implementing the observation phase of the Plan-and-Execute architecture. The PlannerObserver analyzes step execution results, determines plan validity, and suggests refinements, while the StepExecutor executes individual todo items in isolation. These additions improve the overall planning and execution process, allowing for more dynamic and responsive agent behavior. Additionally, new observation events have been defined to facilitate monitoring and logging of the planning process. * refactor: enhance final answer synthesis in AgentExecutor This commit improves the synthesis of final answers in the AgentExecutor class by implementing a more coherent approach to combining results from multiple todo items. The method now utilizes a single LLM call to generate a polished response, falling back to concatenation if the synthesis fails. Additionally, the test cases have been updated to reflect the changes in planning and execution, ensuring that the results are properly validated and that the plan-and-execute architecture is functioning as intended. * refactor: enhance final answer synthesis in AgentExecutor This commit improves the synthesis of final answers in the AgentExecutor class by implementing a more coherent approach to combining results from multiple todo items. The method now utilizes a single LLM call to generate a polished response, falling back to concatenation if the synthesis fails. Additionally, the test cases have been updated to reflect the changes in planning and execution, ensuring that the results are properly validated and that the plan-and-execute architecture is functioning as intended. * refactor: implement structured output handling in final answer synthesis This commit enhances the final answer synthesis process in the AgentExecutor class by introducing support for structured outputs when a response model is specified. The synthesis method now utilizes the response model to produce outputs that conform to the expected schema, while still falling back to concatenation in case of synthesis failures. This change ensures that intermediate steps yield free-text results, but the final output can be structured, improving the overall coherence and usability of the synthesized answers. * regen tests * linted * fix * Enhance PlanningConfig and AgentExecutor with Reasoning Effort Levels This update introduces a new attribute in the class, allowing users to customize the observation and replanning behavior during task execution. The class has been modified to utilize this new attribute, routing step observations based on the specified reasoning effort level: low, medium, or high. Additionally, tests have been added to validate the functionality of the reasoning effort levels, ensuring that the agent behaves as expected under different configurations. This enhancement improves the adaptability and efficiency of the planning process in agent execution. * regen cassettes for test and fix test * cassette regen * fixing tests * dry * Refactor PlannerObserver and StepExecutor to Utilize I18N for Prompts This update enhances the PlannerObserver and StepExecutor classes by integrating the I18N utility for managing prompts and messages. The system and user prompts are now retrieved from the I18N module, allowing for better localization and maintainability. Additionally, the code has been cleaned up to remove hardcoded strings, improving readability and consistency across the planning and execution processes. * Refactor PlannerObserver and StepExecutor to Utilize I18N for Prompts This update enhances the PlannerObserver and StepExecutor classes by integrating the I18N utility for managing prompts and messages. The system and user prompts are now retrieved from the I18N module, allowing for better localization and maintainability. Additionally, the code has been cleaned up to remove hardcoded strings, improving readability and consistency across the planning and execution processes. * consolidate agent logic * fix datetime * improving step executor * refactor: streamline observation and refinement process in PlannerObserver - Updated the PlannerObserver to apply structured refinements directly from observations without requiring a second LLM call. - Renamed method to for clarity. - Enhanced documentation to reflect changes in how refinements are handled. - Removed unnecessary LLM message building and parsing logic, simplifying the refinement process. - Updated event emissions to include summaries of refinements instead of raw data. * enhance step executor with tool usage events and validation - Added event emissions for tool usage, including started and finished events, to track tool execution. - Implemented validation to ensure expected tools are called during step execution, raising errors when not. - Refactored the method to handle tool execution with event logging. - Introduced a new method for parsing tool input into a structured format. - Updated tests to cover new functionality and ensure correct behavior of tool usage events. * refactor: enhance final answer synthesis logic in AgentExecutor - Updated the finalization process to conditionally skip synthesis when the last todo result is sufficient as a complete answer. - Introduced a new method to determine if the last todo result can be used directly, improving efficiency. - Added tests to verify the new behavior, ensuring synthesis is skipped when appropriate and maintained when a response model is set. * fix: update observation handling in PlannerObserver for LLM errors - Modified the error handling in the PlannerObserver to default to a conservative replan when an LLM call fails. - Updated the return values to indicate that the step was not completed successfully and that a full replan is needed. - Added a new test to verify the behavior of the observer when an LLM error occurs, ensuring the correct replan logic is triggered. * refactor: enhance planning and execution flow in agents - Updated the PlannerObserver to accept a kickoff input for standalone task execution, improving flexibility in task handling. - Refined the step execution process in StepExecutor to support multi-turn action loops, allowing for iterative tool execution and observation. - Introduced a method to extract relevant task sections from descriptions, ensuring clarity in task requirements. - Enhanced the AgentExecutor to manage step failures more effectively, triggering replans only when necessary and preserving completed task history. - Updated translations to reflect changes in planning principles and execution prompts, emphasizing concrete and executable steps. * refactor: update setup_native_tools to include tool_name_mapping - Modified the setup_native_tools function to return an additional mapping of tool names. - Updated StepExecutor and AgentExecutor classes to accommodate the new return value from setup_native_tools. * fix tests * linted * linted * feat: enhance image block handling in Anthropic provider and update AgentExecutor logic - Added a method to convert OpenAI-style image_url blocks to Anthropic's required format. - Updated AgentExecutor to handle cases where no todos are ready, introducing a needs_replan return state. - Improved fallback answer generation in AgentExecutor to prevent RuntimeErrors when no final output is produced. * lint * lint * 1. Added failed to TodoStatus (planning_types.py) - TodoStatus now includes failed as a valid state: Literal[pending, running, completed, failed] - Added mark_failed(step_number, result) method to TodoList - Added get_failed_todos() method to TodoList - Updated is_complete to treat both completed and failed as terminal states - Updated replace_pending_todos docstring to mention failed items are preserved 2. Mark running todos as failed before replan (agent_executor.py) All three effort-level handlers now call mark_failed() on the current todo before routing to replan_now: - Low effort (handle_step_observed_low): hard-failure branch - Medium effort (handle_step_observed_medium): needs_full_replan branch - High effort (decide_next_action): both needs_full_replan and step_completed_successfully=False branches 3. Updated _should_replan to use get_failed_todos() Previously filtered on todo.status == failed which was dead code. Now uses the proper accessor method that will actually find failed items. What this fixes: Before these changes, a step that triggered a replan would stay in running status permanently, causing is_complete to never return True and next_pending to skip it — leading to stuck execution states. Now failed steps are properly tracked, replanning context correctly reports them, and LiteAgentOutput.failed_todos will actually return results. * fix test * imp on failed states * adjusted the var name from AgentReActState to AgentExecutorState * addressed p0 bugs * more improvements * linted * regen cassette * addressing crictical comments * ensure configurable timeouts, max_replans and max step iterations * adjusted tools * dropping debug statements * addressed comment * fix linter * lints and test fixes * fix: default observation parse fallback to failure and clean up plan-execute types When _parse_observation_response fails all parse attempts, default to step_completed_successfully=False instead of True to avoid silently masking failures. Extract duplicate _extract_task_section into a shared utility in agent_utils. Type PlanningConfig.llm as str | BaseLLM | None instead of str | Any | None. Make StepResult a frozen dataclass for immutability consistency with StepExecutionContext. * fix: remove Any from function_calling_llm union type in step_executor * fix: make BaseTool usage count thread-safe for parallel step execution Add _usage_lock and _claim_usage() to BaseTool for atomic check-and-increment of current_usage_count. This prevents race conditions when parallel plan steps invoke the same tool concurrently via execute_todos_parallel. Remove the racy pre-check from execute_single_native_tool_call since the limit is now enforced atomically inside tool.run(). --------- Co-authored-by: Greyson LaLonde <greyson.r.lalonde@gmail.com> Co-authored-by: Greyson LaLonde <greyson@crewai.com> |
||
|
|
1ac5801578 | fix: inject tool errors as observations and resolve name collisions | ||
|
|
d259150d8d |
Enhance MCP tool resolution and related events (#4580)
* feat: enhance MCP tool resolution * feat: emit event when MCP configuration fails * feat: emit event when MCP tool execution has failed * style: resolve linter issues * refactor: use clear and natural mcp tool name resolution * test: fix broken tests * fix: resolve MCP connection leaks, slug validation, duplicate connections, and httpx exception handling --------- Co-authored-by: Greyson LaLonde <greyson.r.lalonde@gmail.com> Co-authored-by: Greyson LaLonde <greyson@crewai.com> |
||
|
|
09e3b81ca3 |
fix: preserve null types in tool parameter schemas for LLM (#4579)
* fix: preserve null types in tool parameter schemas for LLM
Tool parameter schemas were stripping null from optional fields via
generate_model_description, forcing the LLM to provide non-null values
for fields.
Adds strip_null_types parameter to generate_model_description and passes False when generating tool
schemas, so optional fields keep anyOf: [{type: T}, {type: null}]
* Update lib/crewai/src/crewai/utilities/pydantic_schema_utils.py
Co-authored-by: Gabe Milani <gabriel@crewai.com>
---------
Co-authored-by: Greyson LaLonde <greyson.r.lalonde@gmail.com>
Co-authored-by: Gabe Milani <gabriel@crewai.com>
Co-authored-by: Lorenze Jay <63378463+lorenzejay@users.noreply.github.com>
|
||
|
|
8102d0a6ca |
feat: enhance JSON argument parsing and validation in CrewAgentExecutor and BaseTool
* feat: enhance JSON argument parsing and validation in CrewAgentExecutor and BaseTool - Added error handling for malformed JSON tool arguments in CrewAgentExecutor, providing descriptive error messages. - Implemented schema validation for tool arguments in BaseTool, ensuring that invalid arguments raise appropriate exceptions. - Introduced tests to verify correct behavior for both valid and invalid JSON inputs, enhancing robustness of tool execution. * refactor: improve argument validation in BaseTool - Introduced a new private method to handle argument validation for tools, enhancing code clarity and reusability. - Updated the method to utilize the new validation method, ensuring consistent error handling for invalid arguments. - Enhanced exception handling to specifically catch , providing clearer error messages for tool argument validation failures. * feat: introduce parse_tool_call_args for improved argument parsing - Added a new utility function, parse_tool_call_args, to handle parsing of tool call arguments from JSON strings or dictionaries, enhancing error handling for malformed JSON inputs. - Updated CrewAgentExecutor and AgentExecutor to utilize the new parsing function, streamlining argument validation and improving clarity in error reporting. - Introduced unit tests for parse_tool_call_args to ensure robust functionality and correct handling of various input scenarios. * feat: add keyword argument validation in BaseTool and Tool classes - Introduced a new method `_validate_kwargs` in BaseTool to validate keyword arguments against the defined schema, ensuring proper argument handling. - Updated the `run` and `arun` methods in both BaseTool and Tool classes to utilize the new validation method, improving error handling and robustness. - Added comprehensive tests for asynchronous execution in `TestBaseToolArunValidation` to verify correct behavior for valid and invalid keyword arguments. * Potential fix for pull request finding 'Syntax error' Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> --------- Co-authored-by: lorenzejay <lorenzejaytech@gmail.com> Co-authored-by: Lorenze Jay <63378463+lorenzejay@users.noreply.github.com> Co-authored-by: Greyson LaLonde <greyson.r.lalonde@gmail.com> Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> |
||
|
|
7377e1aa26 |
fix: bedrock region was always set to "us-east-1" not respecting the env var. (#4582)
* fix: bedrock region was always set to "us-east-1" not respecting the env var. code had AWS_REGION_NAME referenced, but not used, unified to AWS_DEFAULT_REGION as per documentation * DRY code improvement and fix caught by tests. * Supporting litellm configuration |
||
|
|
2ed0c2c043 |
imp compaction (#4399)
Some checks failed
* imp compaction * fix lint * cassette gen * cassette gen * improve assert * adding azure * fix global docstring |
||
|
|
576b74b2ef |
Add call_id to LLM events for correlating requests (#4281)
When monitoring LLM events, consumers need to know which events belong to the same API call. Before this change, there was no way to correlate LLMCallStartedEvent, LLMStreamChunkEvent, and LLMCallCompletedEvent belonging to the same request. |
||
|
|
19ce56032c |
fix: improve output handling and response model integration in agents (#4307)
* fix: improve output handling and response model integration in agents - Refactored output handling in the Agent class to ensure proper conversion and formatting of outputs, including support for BaseModel instances. - Enhanced the AgentExecutor class to correctly utilize response models during execution, improving the handling of structured outputs. - Updated the Gemini and Anthropic completion providers to ensure compatibility with new response model handling, including the addition of strict mode for function definitions. - Improved the OpenAI completion provider to enforce strict adherence to function schemas. - Adjusted translations to clarify instructions regarding output formatting and schema adherence. * drop what was a print that didnt get deleted properly * fixes gemini * azure working * bedrock works * added tests * adjust test * fix tests and regen * fix tests and regen * refactor: ensure stop words are applied correctly in Azure, Gemini, and OpenAI completions; add tests to validate behavior with structured outputs * linting |