Compare commits

..

8 Commits

Author SHA1 Message Date
Devin AI
affe5709c1 fix: capture thought output from Gemini thinking models (issue #4647)
- Add thinking_config parameter to GeminiCompletion.__init__ (accepts dict or ThinkingConfig)
- Include thinking_config in _prepare_generation_config when set
- Rewrite _process_stream_chunk to iterate over parts directly instead of using chunk.text, avoiding warnings when non-text parts (thought, function_call) are present
- Convert _extract_text_from_response from staticmethod to instance method; separate thought parts from text parts and store thoughts in self.previous_thoughts
- Add 11 tests covering thinking config initialization, generation config integration, thought part extraction in streaming and non-streaming paths

Co-Authored-By: João <joao@crewai.com>
2026-02-28 12:14:10 +00:00
Musthaq Ahamad
3899910aa9 docs: sync Composio tool docs across locales (#4639)
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
Mark stale issues and pull requests / stale (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
* docs: update Composio tool docs across locales

Align the Composio automation docs with the new session-based example flow and keep localized pages in sync with the updated English content.

Made-with: Cursor

* docs: clarify manual user authentication wording

Refine the Composio auth section language to reflect session-based automatic auth during agent chat while keeping the manual `authorize` flow explicit.

Made-with: Cursor

* docs: sync updated Composio auth wording across locales

Propagate the latest English wording updates for CrewAI provider initialization and manual user authentication guidance to pt-BR and ko docs.

Made-with: Cursor
2026-02-27 13:38:45 -08:00
Greyson LaLonde
757a435ee3 chore: update changelog and version for v1.10.1a1
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
2026-02-27 09:58:48 -05:00
Greyson LaLonde
8bfdb188f7 feat: bump versions to 1.10.1a1 2026-02-27 09:44:47 -05:00
João Moura
1bdb9496a3 refactor: update step callback methods to support asynchronous invocation (#4633)
* refactor: update step callback methods to support asynchronous invocation

- Replaced synchronous step callback invocations with asynchronous counterparts in the CrewAgentExecutor class.
- Introduced a new async method _ainvoke_step_callback to handle step callbacks in an async context, improving responsiveness and performance in asynchronous workflows.

* chore: bump version to 1.10.1b1 across multiple files

- Updated version strings from 1.10.1b to 1.10.1b1 in various project files including pyproject.toml and __init__.py files.
- Adjusted dependency specifications to reflect the new version in relevant templates and modules.
2026-02-27 07:35:03 -03:00
Joao Moura
979aa26c3d bump new alpha version 2026-02-27 01:43:33 -08:00
João Moura
514c082882 refactor: implement lazy loading for heavy dependencies in Memory module (#4632)
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
Mark stale issues and pull requests / stale (push) Has been cancelled
- Introduced lazy imports for the Memory and EncodingFlow classes to optimize import time and reduce initial load, particularly beneficial for deployment scenarios like Celery pre-fork.
- Updated the Memory class to include new configuration options for aggregation queries, enhancing its functionality.
- Adjusted the __getattr__ method in both the crewai and memory modules to support lazy loading of specified attributes.
2026-02-27 03:20:02 -03:00
Greyson LaLonde
c9e8068578 docs: update changelog and version for v1.10.0 2026-02-26 19:14:25 -05:00
22 changed files with 794 additions and 198 deletions

View File

@@ -4,6 +4,106 @@ description: "Product updates, improvements, and bug fixes for CrewAI"
icon: "clock"
mode: "wide"
---
<Update label="Feb 27, 2026">
## v1.10.1a1
[View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.10.1a1)
## What's Changed
### Features
- Implement asynchronous invocation support in step callback methods
- Implement lazy loading for heavy dependencies in Memory module
### Documentation
- Update changelog and version for v1.10.0
### Refactoring
- Refactor step callback methods to support asynchronous invocation
- Refactor to implement lazy loading for heavy dependencies in Memory module
### Bug Fixes
- Fix branch for release notes
## Contributors
@greysonlalonde, @joaomdmoura
</Update>
<Update label="Feb 27, 2026">
## v1.10.1a1
[View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.10.1a1)
## What's Changed
### Refactoring
- Refactor step callback methods to support asynchronous invocation
- Implement lazy loading for heavy dependencies in Memory module
### Documentation
- Update changelog and version for v1.10.0
### Bug Fixes
- Make branch for release notes
## Contributors
@greysonlalonde, @joaomdmoura
</Update>
<Update label="Feb 26, 2026">
## v1.10.0
[View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.10.0)
## What's Changed
### Features
- Enhance MCP tool resolution and related events
- Update lancedb version and add lance-namespace packages
- Enhance JSON argument parsing and validation in CrewAgentExecutor and BaseTool
- Migrate CLI HTTP client from requests to httpx
- Add versioned documentation
- Add yanked detection for version notes
- Implement user input handling in Flows
- Enhance HITL self-loop functionality in human feedback integration tests
- Add started_event_id and set in eventbus
- Auto update tools.specs
### Bug Fixes
- Validate tool kwargs even when empty to prevent cryptic TypeError
- Preserve null types in tool parameter schemas for LLM
- Map output_pydantic/output_json to native structured output
- Ensure callbacks are ran/awaited if promise
- Capture method name in exception context
- Preserve enum type in router result; improve types
- Fix cyclic flows silently breaking when persistence ID is passed in inputs
- Correct CLI flag format from --skip-provider to --skip_provider
- Ensure OpenAI tool call stream is finalized
- Resolve complex schema $ref pointers in MCP tools
- Enforce additionalProperties=false in schemas
- Reject reserved script names for crew folders
- Resolve race condition in guardrail event emission test
### Documentation
- Add litellm dependency note for non-native LLM providers
- Clarify NL2SQL security model and hardening guidance
- Add 96 missing actions across 9 integrations
### Refactoring
- Refactor crew to provider
- Extract HITL to provider pattern
- Improve hook typing and registration
## Contributors
@dependabot[bot], @github-actions[bot], @github-code-quality[bot], @greysonlalonde, @heitorado, @hobostay, @joaomdmoura, @johnvan7, @jonathansampson, @lorenzejay, @lucasgomide, @mattatcha, @mplachta, @nicoferdi96, @theCyberTech, @thiagomoretto, @vinibrsl
</Update>
<Update label="Jan 26, 2026">
## v1.9.0

View File

@@ -18,77 +18,46 @@ Composio is an integration platform that allows you to connect your AI agents to
To incorporate Composio tools into your project, follow the instructions below:
```shell
pip install composio-crewai
pip install composio composio-crewai
pip install crewai
```
After the installation is complete, either run `composio login` or export your composio API key as `COMPOSIO_API_KEY`. Get your Composio API key from [here](https://app.composio.dev)
After the installation is complete, set your Composio API key as `COMPOSIO_API_KEY`. Get your Composio API key from [here](https://platform.composio.dev)
## Example
The following example demonstrates how to initialize the tool and execute a github action:
1. Initialize Composio toolset
1. Initialize Composio with CrewAI Provider
```python Code
from composio_crewai import ComposioToolSet, App, Action
from composio_crewai import ComposioProvider
from composio import Composio
from crewai import Agent, Task, Crew
toolset = ComposioToolSet()
composio = Composio(provider=ComposioProvider())
```
2. Connect your GitHub account
2. Create a new Composio Session and retrieve the tools
<CodeGroup>
```shell CLI
composio add github
```
```python Code
request = toolset.initiate_connection(app=App.GITHUB)
print(f"Open this URL to authenticate: {request.redirectUrl}")
```python
session = composio.create(
user_id="your-user-id",
toolkits=["gmail", "github"] # optional, default is all toolkits
)
tools = session.tools()
```
Read more about sessions and user management [here](https://docs.composio.dev/docs/configuring-sessions)
</CodeGroup>
3. Get Tools
3. Authenticating users manually
- Retrieving all the tools from an app (not recommended for production):
Composio automatically authenticates the users during the agent chat session. However, you can also authenticate the user manually by calling the `authorize` method.
```python Code
tools = toolset.get_tools(apps=[App.GITHUB])
connection_request = session.authorize("github")
print(f"Open this URL to authenticate: {connection_request.redirect_url}")
```
- Filtering tools based on tags:
```python Code
tag = "users"
filtered_action_enums = toolset.find_actions_by_tags(
App.GITHUB,
tags=[tag],
)
tools = toolset.get_tools(actions=filtered_action_enums)
```
- Filtering tools based on use case:
```python Code
use_case = "Star a repository on GitHub"
filtered_action_enums = toolset.find_actions_by_use_case(
App.GITHUB, use_case=use_case, advanced=False
)
tools = toolset.get_tools(actions=filtered_action_enums)
```
<Tip>Set `advanced` to True to get actions for complex use cases</Tip>
- Using specific tools:
In this demo, we will use the `GITHUB_STAR_A_REPOSITORY_FOR_THE_AUTHENTICATED_USER` action from the GitHub app.
```python Code
tools = toolset.get_tools(
actions=[Action.GITHUB_STAR_A_REPOSITORY_FOR_THE_AUTHENTICATED_USER]
)
```
Learn more about filtering actions [here](https://docs.composio.dev/patterns/tools/use-tools/use-specific-actions)
4. Define agent
```python Code
@@ -116,4 +85,4 @@ crew = Crew(agents=[crewai_agent], tasks=[task])
crew.kickoff()
```
* More detailed list of tools can be found [here](https://app.composio.dev)
* More detailed list of tools can be found [here](https://docs.composio.dev/toolkits)

View File

@@ -4,6 +4,106 @@ description: "CrewAI의 제품 업데이트, 개선 사항 및 버그 수정"
icon: "clock"
mode: "wide"
---
<Update label="2026년 2월 27일">
## v1.10.1a1
[GitHub 릴리스 보기](https://github.com/crewAIInc/crewAI/releases/tag/1.10.1a1)
## 변경 사항
### 기능
- 단계 콜백 메서드에서 비동기 호출 지원 구현
- 메모리 모듈의 무거운 의존성에 대한 지연 로딩 구현
### 문서
- v1.10.0에 대한 변경 로그 및 버전 업데이트
### 리팩토링
- 비동기 호출을 지원하기 위해 단계 콜백 메서드 리팩토링
- 메모리 모듈의 무거운 의존성에 대한 지연 로딩을 구현하기 위해 리팩토링
### 버그 수정
- 릴리스 노트의 분기 수정
## 기여자
@greysonlalonde, @joaomdmoura
</Update>
<Update label="2026년 2월 27일">
## v1.10.1a1
[GitHub 릴리스 보기](https://github.com/crewAIInc/crewAI/releases/tag/1.10.1a1)
## 변경 사항
### 리팩토링
- 비동기 호출을 지원하기 위해 단계 콜백 메서드 리팩토링
- 메모리 모듈의 무거운 의존성에 대해 지연 로딩 구현
### 문서화
- v1.10.0에 대한 변경 로그 및 버전 업데이트
### 버그 수정
- 릴리스 노트를 위한 브랜치 생성
## 기여자
@greysonlalonde, @joaomdmoura
</Update>
<Update label="2026년 2월 26일">
## v1.10.0
[GitHub 릴리스 보기](https://github.com/crewAIInc/crewAI/releases/tag/1.10.0)
## 변경 사항
### 기능
- MCP 도구 해상도 및 관련 이벤트 개선
- lancedb 버전 업데이트 및 lance-namespace 패키지 추가
- CrewAgentExecutor 및 BaseTool에서 JSON 인수 파싱 및 검증 개선
- CLI HTTP 클라이언트를 requests에서 httpx로 마이그레이션
- 버전화된 문서 추가
- 버전 노트에 대한 yanked 감지 추가
- Flows에서 사용자 입력 처리 구현
- 인간 피드백 통합 테스트에서 HITL 자기 루프 기능 개선
- eventbus에 started_event_id 추가 및 설정
- tools.specs 자동 업데이트
### 버그 수정
- 빈 경우에도 도구 kwargs를 검증하여 모호한 TypeError 방지
- LLM을 위한 도구 매개변수 스키마에서 null 타입 유지
- output_pydantic/output_json을 네이티브 구조화된 출력으로 매핑
- 약속이 있는 경우 콜백이 실행/대기되도록 보장
- 예외 컨텍스트에서 메서드 이름 캡처
- 라우터 결과에서 enum 타입 유지; 타입 개선
- 입력으로 지속성 ID가 전달될 때 조용히 깨지는 순환 흐름 수정
- CLI 플래그 형식을 --skip-provider에서 --skip_provider로 수정
- OpenAI 도구 호출 스트림이 완료되도록 보장
- MCP 도구에서 복잡한 스키마 $ref 포인터 해결
- 스키마에서 additionalProperties=false 강제 적용
- 크루 폴더에 대해 예약된 스크립트 이름 거부
- 가드레일 이벤트 방출 테스트에서 경쟁 조건 해결
### 문서
- 비네이티브 LLM 공급자를 위한 litellm 종속성 노트 추가
- NL2SQL 보안 모델 및 강화 지침 명확화
- 9개 통합에서 96개의 누락된 작업 추가
### 리팩토링
- crew를 provider로 리팩토링
- HITL을 provider 패턴으로 추출
- 훅 타이핑 및 등록 개선
## 기여자
@dependabot[bot], @github-actions[bot], @github-code-quality[bot], @greysonlalonde, @heitorado, @hobostay, @joaomdmoura, @johnvan7, @jonathansampson, @lorenzejay, @lucasgomide, @mattatcha, @mplachta, @nicoferdi96, @theCyberTech, @thiagomoretto, @vinibrsl
</Update>
<Update label="2026년 1월 26일">
## v1.9.0

View File

@@ -18,77 +18,46 @@ Composio는 AI 에이전트를 250개 이상의 도구와 연결할 수 있는
Composio 도구를 프로젝트에 통합하려면 아래 지침을 따르세요:
```shell
pip install composio-crewai
pip install composio composio-crewai
pip install crewai
```
설치가 완료된 후, `composio login`을 실행하거나 Composio API 키를 `COMPOSIO_API_KEY`로 export하세요. Composio API 키는 [여기](https://app.composio.dev)에서 받을 수 있습니다.
설치가 완료되면 Composio API 키를 `COMPOSIO_API_KEY`로 설정하세요. Composio API 키는 [여기](https://platform.composio.dev)에서 받을 수 있습니다.
## 예시
다음 예시는 도구를 초기화하고 github action을 실행하는 방법을 보여줍니다:
다음 예시는 도구를 초기화하고 GitHub 액션을 실행하는 방법을 보여줍니다:
1. Composio 도구 세트 초기화
1. CrewAI Provider와 함께 Composio 초기화
```python Code
from composio_crewai import ComposioToolSet, App, Action
from composio_crewai import ComposioProvider
from composio import Composio
from crewai import Agent, Task, Crew
toolset = ComposioToolSet()
composio = Composio(provider=ComposioProvider())
```
2. GitHub 계정 연결
2. 새 Composio 세션을 만들고 도구 가져오기
<CodeGroup>
```shell CLI
composio add github
```
```python Code
request = toolset.initiate_connection(app=App.GITHUB)
print(f"Open this URL to authenticate: {request.redirectUrl}")
```python
session = composio.create(
user_id="your-user-id",
toolkits=["gmail", "github"] # optional, default is all toolkits
)
tools = session.tools()
```
세션 및 사용자 관리에 대한 자세한 내용은 [여기](https://docs.composio.dev/docs/configuring-sessions)를 참고하세요.
</CodeGroup>
3. 도구 가져오
3. 사용자 수동 인증하
- 앱에서 모든 도구를 가져오기 (프로덕션 환경에서는 권장하지 않음):
Composio는 에이전트 채팅 세션 중에 사용자를 자동으로 인증합니다. 하지만 `authorize` 메서드를 호출해 사용자를 수동으로 인증할 수도 있습니다.
```python Code
tools = toolset.get_tools(apps=[App.GITHUB])
connection_request = session.authorize("github")
print(f"Open this URL to authenticate: {connection_request.redirect_url}")
```
- 태그를 기반으로 도구 필터링:
```python Code
tag = "users"
filtered_action_enums = toolset.find_actions_by_tags(
App.GITHUB,
tags=[tag],
)
tools = toolset.get_tools(actions=filtered_action_enums)
```
- 사용 사례를 기반으로 도구 필터링:
```python Code
use_case = "Star a repository on GitHub"
filtered_action_enums = toolset.find_actions_by_use_case(
App.GITHUB, use_case=use_case, advanced=False
)
tools = toolset.get_tools(actions=filtered_action_enums)
```
<Tip>`advanced`를 True로 설정하면 복잡한 사용 사례를 위한 액션을 가져올 수 있습니다</Tip>
- 특정 도구 사용하기:
이 데모에서는 GitHub 앱의 `GITHUB_STAR_A_REPOSITORY_FOR_THE_AUTHENTICATED_USER` 액션을 사용합니다.
```python Code
tools = toolset.get_tools(
actions=[Action.GITHUB_STAR_A_REPOSITORY_FOR_THE_AUTHENTICATED_USER]
)
```
액션 필터링에 대해 더 자세한 내용을 보려면 [여기](https://docs.composio.dev/patterns/tools/use-tools/use-specific-actions)를 참고하세요.
4. 에이전트 정의
```python Code
@@ -116,4 +85,4 @@ crew = Crew(agents=[crewai_agent], tasks=[task])
crew.kickoff()
```
* 더욱 자세한 도구 리스트는 [여기](https://app.composio.dev)에서 확인하실 수 있습니다.
* 더욱 자세한 도구 목록은 [여기](https://docs.composio.dev/toolkits)에서 확인 수 있습니다.

View File

@@ -4,6 +4,106 @@ description: "Atualizações de produto, melhorias e correções do CrewAI"
icon: "clock"
mode: "wide"
---
<Update label="27 fev 2026">
## v1.10.1a1
[Ver release no GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.10.1a1)
## O que Mudou
### Funcionalidades
- Implementar suporte a invocação assíncrona em métodos de callback de etapas
- Implementar carregamento sob demanda para dependências pesadas no módulo de Memória
### Documentação
- Atualizar changelog e versão para v1.10.0
### Refatoração
- Refatorar métodos de callback de etapas para suportar invocação assíncrona
- Refatorar para implementar carregamento sob demanda para dependências pesadas no módulo de Memória
### Correções de Bugs
- Corrigir branch para notas de lançamento
## Contribuidores
@greysonlalonde, @joaomdmoura
</Update>
<Update label="27 fev 2026">
## v1.10.1a1
[Ver release no GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.10.1a1)
## O que Mudou
### Refatoração
- Refatorar métodos de callback de etapas para suportar invocação assíncrona
- Implementar carregamento sob demanda para dependências pesadas no módulo de Memória
### Documentação
- Atualizar changelog e versão para v1.10.0
### Correções de Bugs
- Criar branch para notas de lançamento
## Contribuidores
@greysonlalonde, @joaomdmoura
</Update>
<Update label="26 fev 2026">
## v1.10.0
[Ver release no GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.10.0)
## O que Mudou
### Recursos
- Aprimorar a resolução da ferramenta MCP e eventos relacionados
- Atualizar a versão do lancedb e adicionar pacotes lance-namespace
- Aprimorar a análise e validação de argumentos JSON no CrewAgentExecutor e BaseTool
- Migrar o cliente HTTP da CLI de requests para httpx
- Adicionar documentação versionada
- Adicionar detecção de versões removidas para notas de versão
- Implementar tratamento de entrada do usuário em Flows
- Aprimorar a funcionalidade de auto-loop HITL nos testes de integração de feedback humano
- Adicionar started_event_id e definir no eventbus
- Atualizar automaticamente tools.specs
### Correções de Bugs
- Validar kwargs da ferramenta mesmo quando vazios para evitar TypeError crípticos
- Preservar tipos nulos nos esquemas de parâmetros da ferramenta para LLM
- Mapear output_pydantic/output_json para saída estruturada nativa
- Garantir que callbacks sejam executados/aguardados se forem promessas
- Capturar o nome do método no contexto da exceção
- Preservar tipo enum no resultado do roteador; melhorar tipos
- Corrigir fluxos cíclicos que quebram silenciosamente quando o ID de persistência é passado nas entradas
- Corrigir o formato da flag da CLI de --skip-provider para --skip_provider
- Garantir que o fluxo de chamada da ferramenta OpenAI seja finalizado
- Resolver ponteiros $ref de esquema complexos nas ferramentas MCP
- Impor additionalProperties=false nos esquemas
- Rejeitar nomes de scripts reservados para pastas de equipe
- Resolver condição de corrida no teste de emissão de eventos de guardrail
### Documentação
- Adicionar nota de dependência litellm para provedores de LLM não nativos
- Esclarecer o modelo de segurança NL2SQL e orientações de fortalecimento
- Adicionar 96 ações ausentes em 9 integrações
### Refatoração
- Refatorar crew para provider
- Extrair HITL para padrão de provider
- Melhorar tipagem e registro de hooks
## Contribuidores
@dependabot[bot], @github-actions[bot], @github-code-quality[bot], @greysonlalonde, @heitorado, @hobostay, @joaomdmoura, @johnvan7, @jonathansampson, @lorenzejay, @lucasgomide, @mattatcha, @mplachta, @nicoferdi96, @theCyberTech, @thiagomoretto, @vinibrsl
</Update>
<Update label="26 jan 2026">
## v1.9.0

View File

@@ -11,84 +11,53 @@ mode: "wide"
Composio é uma plataforma de integração que permite conectar seus agentes de IA a mais de 250 ferramentas. Os principais recursos incluem:
- **Autenticação de Nível Empresarial**: Suporte integrado para OAuth, Chaves de API, JWT com atualização automática de token
- **Observabilidade Completa**: Logs detalhados de uso das ferramentas, registros de execução, e muito mais
- **Observabilidade Completa**: Logs detalhados de uso das ferramentas, carimbos de data/hora de execução e muito mais
## Instalação
Para incorporar as ferramentas Composio em seu projeto, siga as instruções abaixo:
```shell
pip install composio-crewai
pip install composio composio-crewai
pip install crewai
```
Após a conclusão da instalação, execute `composio login` ou exporte sua chave de API do composio como `COMPOSIO_API_KEY`. Obtenha sua chave de API Composio [aqui](https://app.composio.dev)
Após concluir a instalação, defina sua chave de API do Composio como `COMPOSIO_API_KEY`. Obtenha sua chave de API do Composio [aqui](https://platform.composio.dev)
## Exemplo
O exemplo a seguir demonstra como inicializar a ferramenta e executar uma ação do github:
O exemplo a seguir demonstra como inicializar a ferramenta e executar uma ação do GitHub:
1. Inicialize o conjunto de ferramentas Composio
1. Inicialize o Composio com o Provider do CrewAI
```python Code
from composio_crewai import ComposioToolSet, App, Action
from composio_crewai import ComposioProvider
from composio import Composio
from crewai import Agent, Task, Crew
toolset = ComposioToolSet()
composio = Composio(provider=ComposioProvider())
```
2. Conecte sua conta do GitHub
2. Crie uma nova sessão Composio e recupere as ferramentas
<CodeGroup>
```shell CLI
composio add github
```
```python Code
request = toolset.initiate_connection(app=App.GITHUB)
print(f"Open this URL to authenticate: {request.redirectUrl}")
```python
session = composio.create(
user_id="your-user-id",
toolkits=["gmail", "github"] # optional, default is all toolkits
)
tools = session.tools()
```
Leia mais sobre sessões e gerenciamento de usuários [aqui](https://docs.composio.dev/docs/configuring-sessions)
</CodeGroup>
3. Obtenha ferramentas
3. Autenticação manual dos usuários
- Recuperando todas as ferramentas de um app (não recomendado em produção):
O Composio autentica automaticamente os usuários durante a sessão de chat do agente. No entanto, você também pode autenticar o usuário manualmente chamando o método `authorize`.
```python Code
tools = toolset.get_tools(apps=[App.GITHUB])
connection_request = session.authorize("github")
print(f"Open this URL to authenticate: {connection_request.redirect_url}")
```
- Filtrando ferramentas com base em tags:
```python Code
tag = "users"
filtered_action_enums = toolset.find_actions_by_tags(
App.GITHUB,
tags=[tag],
)
tools = toolset.get_tools(actions=filtered_action_enums)
```
- Filtrando ferramentas com base no caso de uso:
```python Code
use_case = "Star a repository on GitHub"
filtered_action_enums = toolset.find_actions_by_use_case(
App.GITHUB, use_case=use_case, advanced=False
)
tools = toolset.get_tools(actions=filtered_action_enums)
```
<Tip>Defina `advanced` como True para obter ações para casos de uso complexos</Tip>
- Usando ferramentas específicas:
Neste exemplo, usaremos a ação `GITHUB_STAR_A_REPOSITORY_FOR_THE_AUTHENTICATED_USER` do app GitHub.
```python Code
tools = toolset.get_tools(
actions=[Action.GITHUB_STAR_A_REPOSITORY_FOR_THE_AUTHENTICATED_USER]
)
```
Saiba mais sobre como filtrar ações [aqui](https://docs.composio.dev/patterns/tools/use-tools/use-specific-actions)
4. Defina o agente
```python Code
@@ -116,4 +85,4 @@ crew = Crew(agents=[crewai_agent], tasks=[task])
crew.kickoff()
```
* Uma lista mais detalhada de ferramentas pode ser encontrada [aqui](https://app.composio.dev)
* Uma lista mais detalhada de ferramentas pode ser encontrada [aqui](https://docs.composio.dev/toolkits)

View File

@@ -152,4 +152,4 @@ __all__ = [
"wrap_file_source",
]
__version__ = "1.10.0"
__version__ = "1.10.1a1"

View File

@@ -11,7 +11,7 @@ dependencies = [
"pytube~=15.0.0",
"requests~=2.32.5",
"docker~=7.1.0",
"crewai==1.10.0",
"crewai==1.10.1a1",
"tiktoken~=0.8.0",
"beautifulsoup4~=4.13.4",
"python-docx~=1.2.0",

View File

@@ -291,4 +291,4 @@ __all__ = [
"ZapierActionTools",
]
__version__ = "1.10.0"
__version__ = "1.10.1a1"

View File

@@ -53,7 +53,7 @@ Repository = "https://github.com/crewAIInc/crewAI"
[project.optional-dependencies]
tools = [
"crewai-tools==1.10.0",
"crewai-tools==1.10.1a1",
]
embeddings = [
"tiktoken~=0.8.0"

View File

@@ -10,7 +10,6 @@ from crewai.flow.flow import Flow
from crewai.knowledge.knowledge import Knowledge
from crewai.llm import LLM
from crewai.llms.base_llm import BaseLLM
from crewai.memory.unified_memory import Memory
from crewai.process import Process
from crewai.task import Task
from crewai.tasks.llm_guardrail import LLMGuardrail
@@ -41,7 +40,7 @@ def _suppress_pydantic_deprecation_warnings() -> None:
_suppress_pydantic_deprecation_warnings()
__version__ = "1.10.0"
__version__ = "1.10.1a1"
_telemetry_submitted = False
@@ -72,6 +71,25 @@ def _track_install_async() -> None:
_track_install_async()
_LAZY_IMPORTS: dict[str, tuple[str, str]] = {
"Memory": ("crewai.memory.unified_memory", "Memory"),
}
def __getattr__(name: str) -> Any:
"""Lazily import heavy modules (e.g. Memory → lancedb) on first access."""
if name in _LAZY_IMPORTS:
module_path, attr = _LAZY_IMPORTS[name]
import importlib
mod = importlib.import_module(module_path)
val = getattr(mod, attr)
globals()[name] = val
return val
raise AttributeError(f"module 'crewai' has no attribute {name!r}")
__all__ = [
"LLM",
"Agent",

View File

@@ -1259,7 +1259,7 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
formatted_answer, tool_result
)
self._invoke_step_callback(formatted_answer) # type: ignore[arg-type]
await self._ainvoke_step_callback(formatted_answer) # type: ignore[arg-type]
self._append_message(formatted_answer.text) # type: ignore[union-attr]
except OutputParserError as e:
@@ -1374,7 +1374,7 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
output=answer,
text=answer,
)
self._invoke_step_callback(formatted_answer)
await self._ainvoke_step_callback(formatted_answer)
self._append_message(answer) # Save final answer to messages
self._show_logs(formatted_answer)
return formatted_answer
@@ -1386,7 +1386,7 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
output=answer,
text=output_json,
)
self._invoke_step_callback(formatted_answer)
await self._ainvoke_step_callback(formatted_answer)
self._append_message(output_json)
self._show_logs(formatted_answer)
return formatted_answer
@@ -1397,7 +1397,7 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
output=str(answer),
text=str(answer),
)
self._invoke_step_callback(formatted_answer)
await self._ainvoke_step_callback(formatted_answer)
self._append_message(str(answer)) # Save final answer to messages
self._show_logs(formatted_answer)
return formatted_answer
@@ -1491,7 +1491,7 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
def _invoke_step_callback(
self, formatted_answer: AgentAction | AgentFinish
) -> None:
"""Invoke step callback.
"""Invoke step callback (sync context).
Args:
formatted_answer: Current agent response.
@@ -1501,6 +1501,19 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
if inspect.iscoroutine(cb_result):
asyncio.run(cb_result)
async def _ainvoke_step_callback(
self, formatted_answer: AgentAction | AgentFinish
) -> None:
"""Invoke step callback (async context).
Args:
formatted_answer: Current agent response.
"""
if self.step_callback:
cb_result = self.step_callback(formatted_answer)
if inspect.iscoroutine(cb_result):
await cb_result
def _append_message(
self, text: str, role: Literal["user", "assistant", "system"] = "assistant"
) -> None:

View File

@@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
authors = [{ name = "Your Name", email = "you@example.com" }]
requires-python = ">=3.10,<3.14"
dependencies = [
"crewai[tools]==1.10.0"
"crewai[tools]==1.10.1a1"
]
[project.scripts]

View File

@@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
authors = [{ name = "Your Name", email = "you@example.com" }]
requires-python = ">=3.10,<3.14"
dependencies = [
"crewai[tools]==1.10.0"
"crewai[tools]==1.10.1a1"
]
[project.scripts]

View File

@@ -5,7 +5,7 @@ description = "Power up your crews with {{folder_name}}"
readme = "README.md"
requires-python = ">=3.10,<3.14"
dependencies = [
"crewai[tools]==1.10.0"
"crewai[tools]==1.10.1a1"
]
[tool.crewai]

View File

@@ -16,7 +16,7 @@ from collections.abc import (
Sequence,
ValuesView,
)
from concurrent.futures import Future
from concurrent.futures import Future, ThreadPoolExecutor
import copy
import enum
import inspect
@@ -1739,7 +1739,12 @@ class Flow(Generic[T], metaclass=FlowMeta):
async def _run_flow() -> Any:
return await self.kickoff_async(inputs, input_files)
return asyncio.run(_run_flow())
try:
asyncio.get_running_loop()
with ThreadPoolExecutor(max_workers=1) as pool:
return pool.submit(asyncio.run, _run_flow()).result()
except RuntimeError:
return asyncio.run(_run_flow())
async def kickoff_async(
self,

View File

@@ -34,6 +34,8 @@ except ImportError:
) from None
logger = logging.getLogger(__name__)
STRUCTURED_OUTPUT_TOOL_NAME = "structured_output"
@@ -61,6 +63,7 @@ class GeminiCompletion(BaseLLM):
interceptor: BaseInterceptor[Any, Any] | None = None,
use_vertexai: bool | None = None,
response_format: type[BaseModel] | None = None,
thinking_config: types.ThinkingConfig | dict[str, Any] | None = None,
**kwargs: Any,
):
"""Initialize Google Gemini chat completion client.
@@ -93,6 +96,14 @@ class GeminiCompletion(BaseLLM):
api_version="v1" is automatically configured.
response_format: Pydantic model for structured output. Used as default when
response_model is not passed to call()/acall() methods.
thinking_config: Configuration for Gemini thinking models (e.g. gemini-2.5-pro).
Can be a ThinkingConfig object or a dict with 'include_thoughts'
and optionally 'thinking_budget' keys.
When enabled, the model's reasoning/thought output is captured
and logged. Example:
thinking_config={"include_thoughts": True}
thinking_config=ThinkingConfig(include_thoughts=True,
thinking_budget=10000)
**kwargs: Additional parameters
"""
if interceptor is not None:
@@ -130,6 +141,17 @@ class GeminiCompletion(BaseLLM):
self.tools: list[dict[str, Any]] | None = None
self.response_format = response_format
# Thinking config for Gemini thinking models (e.g. gemini-2.5-pro)
if isinstance(thinking_config, dict):
self.thinking_config: types.ThinkingConfig | None = types.ThinkingConfig(
**thinking_config
)
else:
self.thinking_config = thinking_config
# Store previous thought content for multi-turn conversations
self.previous_thoughts: list[str] = []
# Model-specific settings
version_match = re.search(r"gemini-(\d+(?:\.\d+)?)", model.lower())
self.supports_tools = bool(
@@ -481,6 +503,10 @@ class GeminiCompletion(BaseLLM):
if self.stop_sequences:
config_params["stop_sequences"] = self.stop_sequences
# Add thinking config for thinking models (e.g. gemini-2.5-pro)
if self.thinking_config is not None:
config_params["thinking_config"] = self.thinking_config
if tools and self.supports_tools:
gemini_tools = self._convert_tools_for_interference(tools)
@@ -916,6 +942,11 @@ class GeminiCompletion(BaseLLM):
) -> tuple[str, dict[int, dict[str, Any]], dict[str, int]]:
"""Process a single streaming chunk.
Instead of using ``chunk.text`` (which triggers a warning when non-text
parts like ``function_call`` or ``thought_signature`` are present), this
method iterates over the candidate parts directly to extract text,
thought content, and function calls without side effects.
Args:
chunk: The streaming chunk response
full_response: Accumulated response text
@@ -931,19 +962,31 @@ class GeminiCompletion(BaseLLM):
if chunk.usage_metadata:
usage_data = self._extract_token_usage(chunk)
if chunk.text:
full_response += chunk.text
self._emit_stream_chunk_event(
chunk=chunk.text,
from_task=from_task,
from_agent=from_agent,
response_id=response_id,
)
# Iterate over parts directly to avoid the warning triggered by chunk.text
# when non-text parts (function_call, thought_signature) are present.
if chunk.candidates:
candidate = chunk.candidates[0]
if candidate.content and candidate.content.parts:
for part in candidate.content.parts:
# Handle thought parts from thinking models
if getattr(part, "thought", False) and part.text:
logger.debug(
"Gemini thinking model thought: %s", part.text
)
self.previous_thoughts.append(part.text)
continue
# Handle regular text parts
if hasattr(part, "text") and part.text and not part.function_call:
full_response += part.text
self._emit_stream_chunk_event(
chunk=part.text,
from_task=from_task,
from_agent=from_agent,
response_id=response_id,
)
# Handle function call parts
if part.function_call:
call_index = len(function_calls)
call_id = f"call_{call_index}"
@@ -1305,19 +1348,21 @@ class GeminiCompletion(BaseLLM):
}
return {"total_tokens": 0}
@staticmethod
def _extract_text_from_response(response: GenerateContentResponse) -> str:
def _extract_text_from_response(self, response: GenerateContentResponse) -> str:
"""Extract text content from Gemini response without triggering warnings.
This method directly accesses the response parts to extract text content,
avoiding the warning that occurs when using response.text on responses
containing non-text parts (e.g., 'thought_signature' from thinking models).
Thought parts (where ``part.thought == True``) are separated from regular
text and stored in ``self.previous_thoughts`` for downstream access.
Args:
response: The Gemini API response
Returns:
Concatenated text content from all text parts
Concatenated text content from all non-thought text parts
"""
if not response.candidates:
return ""
@@ -1326,11 +1371,13 @@ class GeminiCompletion(BaseLLM):
if not candidate.content or not candidate.content.parts:
return ""
text_parts = [
part.text
for part in candidate.content.parts
if hasattr(part, "text") and part.text
]
text_parts: list[str] = []
for part in candidate.content.parts:
if getattr(part, "thought", False) and part.text:
logger.debug("Gemini thinking model thought: %s", part.text)
self.previous_thoughts.append(part.text)
elif hasattr(part, "text") and part.text:
text_parts.append(part.text)
return "".join(text_parts)

View File

@@ -1,6 +1,14 @@
"""Memory module: unified Memory with LLM analysis and pluggable storage."""
"""Memory module: unified Memory with LLM analysis and pluggable storage.
Heavy dependencies are lazily imported so that
``import crewai`` does not initialise at runtime — critical for
Celery pre-fork and similar deployment patterns.
"""
from __future__ import annotations
from typing import Any
from crewai.memory.encoding_flow import EncodingFlow
from crewai.memory.memory_scope import MemoryScope, MemorySlice
from crewai.memory.types import (
MemoryMatch,
@@ -10,7 +18,24 @@ from crewai.memory.types import (
embed_text,
embed_texts,
)
from crewai.memory.unified_memory import Memory
_LAZY_IMPORTS: dict[str, tuple[str, str]] = {
"Memory": ("crewai.memory.unified_memory", "Memory"),
"EncodingFlow": ("crewai.memory.encoding_flow", "EncodingFlow"),
}
def __getattr__(name: str) -> Any:
"""Lazily import Memory / EncodingFlow to avoid pulling in lancedb at import time."""
if name in _LAZY_IMPORTS:
import importlib
module_path, attr = _LAZY_IMPORTS[name]
mod = importlib.import_module(module_path)
val = getattr(mod, attr)
globals()[name] = val
return val
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
__all__ = [

View File

@@ -21,7 +21,6 @@ from crewai.llms.base_llm import BaseLLM
from crewai.memory.analyze import extract_memories_from_content
from crewai.memory.recall_flow import RecallFlow
from crewai.memory.storage.backend import StorageBackend
from crewai.memory.storage.lancedb_storage import LanceDBStorage
from crewai.memory.types import (
MemoryConfig,
MemoryMatch,
@@ -148,12 +147,10 @@ class Memory:
else None
)
# Storage is initialized eagerly (local, no API key needed).
self._storage: StorageBackend
if storage == "lancedb":
self._storage = LanceDBStorage()
elif isinstance(storage, str):
self._storage = LanceDBStorage(path=storage)
if isinstance(storage, str):
from crewai.memory.storage.lancedb_storage import LanceDBStorage
self._storage = LanceDBStorage() if storage == "lancedb" else LanceDBStorage(path=storage)
else:
self._storage = storage

View File

@@ -1190,3 +1190,287 @@ def test_gemini_cached_prompt_tokens_with_tools():
# cached_prompt_tokens should be populated (may be 0 if Gemini
# doesn't cache for this particular request, but the field should exist)
assert usage.cached_prompt_tokens >= 0
# ────────────────────────────────────────────────────────────────────────────
# Tests for Gemini thinking model support (issue #4647)
# ────────────────────────────────────────────────────────────────────────────
def test_gemini_thinking_config_dict_initialization():
"""Test that thinking_config can be passed as a dict and is converted to ThinkingConfig."""
from google.genai import types as genai_types
llm = LLM(
model="google/gemini-2.5-flash",
thinking_config={"include_thoughts": True},
)
from crewai.llms.providers.gemini.completion import GeminiCompletion
assert isinstance(llm, GeminiCompletion)
assert llm.thinking_config is not None
assert isinstance(llm.thinking_config, genai_types.ThinkingConfig)
assert llm.thinking_config.include_thoughts is True
def test_gemini_thinking_config_object_initialization():
"""Test that thinking_config can be passed as a ThinkingConfig object."""
from google.genai import types as genai_types
tc = genai_types.ThinkingConfig(include_thoughts=True, thinking_budget=10000)
llm = LLM(
model="google/gemini-2.5-flash",
thinking_config=tc,
)
from crewai.llms.providers.gemini.completion import GeminiCompletion
assert isinstance(llm, GeminiCompletion)
assert llm.thinking_config is tc
assert llm.thinking_config.include_thoughts is True
assert llm.thinking_config.thinking_budget == 10000
def test_gemini_thinking_config_none_by_default():
"""Test that thinking_config is None when not provided."""
llm = LLM(model="google/gemini-2.0-flash-001")
from crewai.llms.providers.gemini.completion import GeminiCompletion
assert isinstance(llm, GeminiCompletion)
assert llm.thinking_config is None
def test_gemini_thinking_config_in_generation_config():
"""Test that thinking_config is included in the GenerateContentConfig."""
from google.genai import types as genai_types
llm = LLM(
model="google/gemini-2.5-flash",
thinking_config={"include_thoughts": True},
)
config = llm._prepare_generation_config()
assert config.thinking_config is not None
assert isinstance(config.thinking_config, genai_types.ThinkingConfig)
assert config.thinking_config.include_thoughts is True
def test_gemini_thinking_config_not_in_generation_config_when_none():
"""Test that thinking_config is absent from GenerateContentConfig when not set."""
llm = LLM(model="google/gemini-2.0-flash-001")
config = llm._prepare_generation_config()
assert config.thinking_config is None
def test_gemini_extract_text_filters_out_thought_parts():
"""Test that _extract_text_from_response separates thought parts from text."""
llm = LLM(model="google/gemini-2.5-flash")
# Build a fake response with thought + text parts
mock_response = MagicMock()
thought_part = MagicMock()
thought_part.thought = True
thought_part.text = "Let me think about this..."
thought_part.function_call = None
text_part = MagicMock()
text_part.thought = False
text_part.text = "The answer is 42."
text_part.function_call = None
candidate = MagicMock()
candidate.content.parts = [thought_part, text_part]
mock_response.candidates = [candidate]
llm.previous_thoughts = []
result = llm._extract_text_from_response(mock_response)
assert result == "The answer is 42."
assert len(llm.previous_thoughts) == 1
assert llm.previous_thoughts[0] == "Let me think about this..."
def test_gemini_extract_text_no_thought_parts():
"""Test _extract_text_from_response with no thought parts (normal response)."""
llm = LLM(model="google/gemini-2.0-flash-001")
mock_response = MagicMock()
text_part = MagicMock()
text_part.thought = False
text_part.text = "Hello world"
text_part.function_call = None
candidate = MagicMock()
candidate.content.parts = [text_part]
mock_response.candidates = [candidate]
llm.previous_thoughts = []
result = llm._extract_text_from_response(mock_response)
assert result == "Hello world"
assert len(llm.previous_thoughts) == 0
def test_gemini_stream_chunk_handles_thought_parts():
"""Test that _process_stream_chunk captures thought parts and emits text parts."""
import json as json_mod
llm = LLM(model="google/gemini-2.5-flash")
llm.previous_thoughts = []
# Build a mock chunk with a thought part and a text part
thought_part = MagicMock()
thought_part.thought = True
thought_part.text = "Reasoning step 1"
thought_part.function_call = None
text_part = MagicMock()
text_part.thought = False
text_part.text = "Final answer"
text_part.function_call = None
chunk = MagicMock()
chunk.response_id = "resp_123"
chunk.usage_metadata = None
candidate = MagicMock()
candidate.content.parts = [thought_part, text_part]
chunk.candidates = [candidate]
with patch.object(llm, "_emit_stream_chunk_event"):
full_response, function_calls, usage_data = llm._process_stream_chunk(
chunk=chunk,
full_response="",
function_calls={},
usage_data={"total_tokens": 0},
)
assert full_response == "Final answer"
assert len(llm.previous_thoughts) == 1
assert llm.previous_thoughts[0] == "Reasoning step 1"
def test_gemini_stream_chunk_handles_function_call_without_warning():
"""Test that _process_stream_chunk handles function calls without triggering chunk.text."""
llm = LLM(model="google/gemini-2.5-flash")
llm.previous_thoughts = []
# Build a mock chunk with a function call part
func_part = MagicMock()
func_part.thought = False
func_part.text = None
func_part.function_call.name = "get_weather"
func_part.function_call.args = {"location": "Tokyo"}
chunk = MagicMock()
chunk.response_id = "resp_456"
chunk.usage_metadata = None
candidate = MagicMock()
candidate.content.parts = [func_part]
chunk.candidates = [candidate]
with patch.object(llm, "_emit_stream_chunk_event"):
full_response, function_calls, usage_data = llm._process_stream_chunk(
chunk=chunk,
full_response="",
function_calls={},
usage_data={"total_tokens": 0},
)
assert full_response == ""
assert len(function_calls) == 1
assert function_calls[0]["name"] == "get_weather"
assert function_calls[0]["args"] == {"location": "Tokyo"}
def test_gemini_stream_chunk_mixed_thought_text_and_function_call():
"""Test _process_stream_chunk with thought, text, and function call parts."""
llm = LLM(model="google/gemini-2.5-flash")
llm.previous_thoughts = []
thought_part = MagicMock()
thought_part.thought = True
thought_part.text = "I need to use a tool"
thought_part.function_call = None
func_part = MagicMock()
func_part.thought = False
func_part.text = None
func_part.function_call.name = "search"
func_part.function_call.args = {"query": "hello"}
chunk = MagicMock()
chunk.response_id = "resp_789"
chunk.usage_metadata = None
candidate = MagicMock()
candidate.content.parts = [thought_part, func_part]
chunk.candidates = [candidate]
with patch.object(llm, "_emit_stream_chunk_event"):
full_response, function_calls, usage_data = llm._process_stream_chunk(
chunk=chunk,
full_response="",
function_calls={},
usage_data={"total_tokens": 0},
)
assert full_response == ""
assert len(function_calls) == 1
assert function_calls[0]["name"] == "search"
assert len(llm.previous_thoughts) == 1
assert llm.previous_thoughts[0] == "I need to use a tool"
def test_gemini_previous_thoughts_accumulate_across_chunks():
"""Test that previous_thoughts accumulate across multiple streaming chunks."""
llm = LLM(model="google/gemini-2.5-flash")
llm.previous_thoughts = []
# First chunk with thought
thought1 = MagicMock()
thought1.thought = True
thought1.text = "Step 1"
thought1.function_call = None
chunk1 = MagicMock()
chunk1.response_id = "resp_1"
chunk1.usage_metadata = None
candidate1 = MagicMock()
candidate1.content.parts = [thought1]
chunk1.candidates = [candidate1]
# Second chunk with thought + text
thought2 = MagicMock()
thought2.thought = True
thought2.text = "Step 2"
thought2.function_call = None
text_part = MagicMock()
text_part.thought = False
text_part.text = "Result"
text_part.function_call = None
chunk2 = MagicMock()
chunk2.response_id = "resp_1"
chunk2.usage_metadata = None
candidate2 = MagicMock()
candidate2.content.parts = [thought2, text_part]
chunk2.candidates = [candidate2]
with patch.object(llm, "_emit_stream_chunk_event"):
full_response = ""
function_calls: dict = {}
usage_data = {"total_tokens": 0}
full_response, function_calls, usage_data = llm._process_stream_chunk(
chunk=chunk1, full_response=full_response,
function_calls=function_calls, usage_data=usage_data,
)
full_response, function_calls, usage_data = llm._process_stream_chunk(
chunk=chunk2, full_response=full_response,
function_calls=function_calls, usage_data=usage_data,
)
assert full_response == "Result"
assert len(llm.previous_thoughts) == 2
assert llm.previous_thoughts[0] == "Step 1"
assert llm.previous_thoughts[1] == "Step 2"

View File

@@ -1,3 +1,3 @@
"""CrewAI development tools."""
__version__ = "1.10.0"
__version__ = "1.10.1a1"

View File

@@ -200,7 +200,7 @@ def add_docs_version(docs_json_path: Path, version: str) -> bool:
Args:
docs_json_path: Path to docs/docs.json.
version: Version string (e.g., "1.10.0").
version: Version string (e.g., "1.10.1b1").
Returns:
True if docs.json was updated, False otherwise.