Add CrewAI TinyFish integration#22
Conversation
Add `crewai-tinyfish`: official TinyFish tools for CrewAI agents, wrapping the Search, Fetch, Agent, and Browser API surfaces as CrewAI BaseTools. - src/crewai_tinyfish: four tools with lazy SDK import, version-skew-tolerant kwargs, and TF_API_INTEGRATION="crewai" request attribution - tests: fully offline (SDK faked), 11 passing - examples: direct-tool quickstart and a Search+Fetch research crew - CI + CD workflows mirroring the langchain/google-adk packages (lint/test/build on PR, version-gated PyPI publish on merge to main) - README in the house style of the sibling integrations
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (6)
📝 WalkthroughWalkthroughAdds a new Sequence Diagram(s)sequenceDiagram
participant research_crew_py as research_crew.py
participant build_crew_fn as build_crew(topic)
participant Crew
participant WebResearcher as Web Researcher
participant TinyFishSearchTool
participant TinyFishFetchTool
participant BriefingWriter as Briefing Writer
research_crew_py->>build_crew_fn: build crew
build_crew_fn-->>research_crew_py: Crew
research_crew_py->>Crew: kickoff()
Crew->>WebResearcher: run research task
WebResearcher->>TinyFishSearchTool: search(topic)
WebResearcher->>TinyFishFetchTool: fetch source URLs
Crew->>BriefingWriter: run writing task with research context
BriefingWriter-->>research_crew_py: 5-bullet cited briefing
Suggested reviewers
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 markdownlint-cli2 (0.22.1)crewai/UPSTREAM.mdmarkdownlint-cli2 wrapper config was not available before execution Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (8)
crewai/src/crewai_tinyfish/tinyfish_browser_tool.py (1)
101-102: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win
_arunblocks the event loop. Session creation is documented as taking 10-30s (Line 45), and_runcalls it synchronously. In async crews this freezes the loop for the duration. Mirror the agent tool fix by offloading to a thread.♻️ Offload blocking work to a worker thread
- async def _arun(self, *args: Any, **kwargs: Any) -> str: - return self._run(*args, **kwargs) + async def _arun(self, *args: Any, **kwargs: Any) -> str: + import asyncio + + return await asyncio.to_thread(self._run, *args, **kwargs)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crewai/src/crewai_tinyfish/tinyfish_browser_tool.py` around lines 101 - 102, The _arun method in TinyfishBrowserTool is still calling the synchronous _run directly, which blocks the event loop during slow session creation. Update _arun to offload the blocking _run work to a worker thread, matching the agent tool approach, so async crews can continue running without freezing.crewai/UPSTREAM.md (1)
24-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAdd a language to the fenced block (markdownlint MD040). Use
textfor the directory tree listing.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crewai/UPSTREAM.md` around lines 24 - 35, The fenced directory-tree block in UPSTREAM.md is missing a language tag, triggering markdownlint MD040; update the fence around the tree listing to use text so the block is explicitly marked as plain text. Keep the change localized to the existing fenced snippet that shows the crewai_tools/tools/* directories.Source: Linters/SAST tools
crewai/src/crewai_tinyfish/tinyfish_agent_tool.py (1)
187-188: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winUse
AsyncTinyFishin_arun
tinyfish0.2.5’sagent.runis synchronous; calling it from_arunblocks the event loop. Switch this path toAsyncTinyFishandawait client.agent.run(...)instead of delegating to the sync_run(thread offload only as a fallback).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crewai/src/crewai_tinyfish/tinyfish_agent_tool.py` around lines 187 - 188, The _arun path in TinyFishAgentTool is still delegating to the synchronous _run, which blocks the event loop. Update _arun to use AsyncTinyFish and await client.agent.run(...) directly, keeping the sync _run only as a fallback or separate path. Use the existing TinyFishAgentTool and _arun/_run symbols to locate the change.crewai/pyproject.toml (1)
38-42: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDev dependencies are duplicated and diverging across two sources.
The
devextra here liststinyfish/pytest/pytest-asynciobut omitsruffandbuild, whilerequirements-dev.txtlistsbuild/pytest/pytest-asyncio/ruffbut omitstinyfish. Maintaining both invites drift. Consider making one the single source of truth (e.g.requirements-dev.txtinstalling.[dev]).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crewai/pyproject.toml` around lines 38 - 42, The dev dependency lists in pyproject.toml and requirements-dev.txt are drifting apart, so make one source of truth for the dev setup. Update the dev extra in pyproject.toml and the requirements-dev workflow to stay aligned, including tinyfish, pytest, pytest-asyncio, ruff, and build as needed, or switch requirements-dev.txt to install the dev extra directly so both paths use the same dependency set.crewai/src/crewai_tinyfish/_serde.py (1)
38-47: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low valueMinor:
as_listsilently mangles scalars that are iterable.A
strordictvalue won't raiseTypeError, solist(value)yields characters or dict keys rather than[value]. Responseresults/errorsare normally already lists so this is unlikely to bite, but if you want strict scalar-wrapping semantics, special-casestr/bytes/dict.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crewai/src/crewai_tinyfish/_serde.py` around lines 38 - 47, The as_list helper in _serde.py is incorrectly treating some scalar-like iterables as sequences, so strings, bytes, and dicts get split into elements or keys instead of being wrapped as a single item. Update as_list to special-case these types before the generic list(value) conversion, and keep the existing behavior for None and real lists while preserving scalar-wrapping semantics for any non-list input..github/workflows/crewai-publish.yml (2)
21-103: 🔒 Security & Privacy | 🔵 Trivial | ⚖️ Poor tradeoffPin all third-party actions to commit SHAs.
actions/checkout@v6,actions/setup-python@v6,astral-sh/setup-uv@v8.1.0,actions/upload-artifact@v7,actions/download-artifact@v8, andpypa/gh-action-pypi-publish@release/v1are referenced by mutable tags/branches. For a publishing workflow handling release artifacts, pin to immutable commit SHAs to mitigate supply-chain risk.@release/v1is especially risky as a moving branch ref.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/crewai-publish.yml around lines 21 - 103, Pin every third-party GitHub Action in this workflow to an immutable commit SHA instead of mutable tags or branches. Update the action references in the publish workflow for actions/checkout, actions/setup-python, astral-sh/setup-uv, actions/upload-artifact, actions/download-artifact, and pypa/gh-action-pypi-publish so the jobs use fixed commit hashes while keeping the existing build and publish steps unchanged.Source: Linters/SAST tools
90-106: 🔒 Security & Privacy | 🔵 Trivial | 🏗️ Heavy liftConsider PyPI Trusted Publishing instead of a long-lived API token.
The
publish-pypijob authenticates with a staticPYPI_API_TOKENsecret. Trusted Publishing (OIDC) removes the need to store/rotate a token; it requires addingpermissions: id-token: writeto the job and configuring a PyPI publisher. The job also has no explicitpermissionsblock, so it should be scoped down regardless.🔒 Trusted publishing sketch
publish-pypi: name: Publish to PyPI needs: build if: needs.build.outputs.version-exists == 'false' runs-on: ubuntu-latest + permissions: + id-token: write steps: - name: Download distributions uses: actions/download-artifact@v8 with: name: python-package-distributions path: dist/ - name: Publish to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: packages-dir: dist/ - password: ${{ secrets.PYPI_API_TOKEN }}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/crewai-publish.yml around lines 90 - 106, The publish-pypi job is using a long-lived PYPI_API_TOKEN secret instead of PyPI Trusted Publishing and has no explicit permissions scoping. Update the publish-pypi job in crewai-publish.yml to use OIDC by adding the required id-token: write permission (and only the minimal permissions needed) and remove the password-based secret from the pypa/gh-action-pypi-publish@release/v1 step. Keep the job aligned with Trusted Publishing setup for the existing publish workflow.Source: Linters/SAST tools
.github/workflows/crewai-ci.yml (1)
27-29: 🔒 Security & Privacy | 🔵 Trivial | ⚖️ Poor tradeoffHarden action references: pin to commit SHAs and disable credential persistence.
The
actions/checkout@v6andactions/setup-python@v6references are pinned only to mutable tags, which leaves the workflow exposed to supply-chain tampering if a tag is moved. Additionally,actions/checkoutpersists theGITHUB_TOKENinto the local git config by default; since this job doesn't push, setpersist-credentials: false.🔒 Proposed hardening
- - uses: actions/checkout@v6 + - uses: actions/checkout@<pinned-sha> # v6 + with: + persist-credentials: false - - uses: actions/setup-python@v6 + - uses: actions/setup-python@<pinned-sha> # v6 with: python-version: "3.12"🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/crewai-ci.yml around lines 27 - 29, The workflow uses mutable action tags for actions/checkout and actions/setup-python, so update those references in the CI job to immutable commit SHAs instead of version tags. In the same checkout step, set persist-credentials to false because the job does not need git credentials. Use the existing actions/checkout and actions/setup-python entries in the workflow as the places to harden.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/crewai-publish.yml:
- Around line 1-16: Add a top-level permissions block to the CrewAI CD - Publish
to PyPI workflow so the default GITHUB_TOKEN scope is minimized; keep the
existing job-level permissions in build and only widen permissions in specific
jobs if needed. Update the workflow near the on/job declarations, using the
workflow name and build job as anchors when editing.
In `@crewai/examples/research_crew.py`:
- Line 20: The example in research_crew.py uses an invalid model identifier in
the LLM setup, which will break kickoff() for users running it as-is. Update the
LLM(...) initialization to use a real, supported model id such as gpt-4o, and
keep the rest of the quickstart flow unchanged. Use the llm assignment in the
example as the place to make the replacement so the snippet remains runnable
without extra edits.
In `@crewai/UPSTREAM.md`:
- Around line 47-49: The Tinyfish minimum version is inconsistent between the
upstream notes and the package extra, so align them to one floor. Update the
version reference in UPSTREAM.md to match the dependency declaration used by the
extra (or vice versa if the package spec is intended to change), and ensure the
documented symbol tinyfish stays consistent across both places so contributors
don’t copy the wrong minimum.
---
Nitpick comments:
In @.github/workflows/crewai-ci.yml:
- Around line 27-29: The workflow uses mutable action tags for actions/checkout
and actions/setup-python, so update those references in the CI job to immutable
commit SHAs instead of version tags. In the same checkout step, set
persist-credentials to false because the job does not need git credentials. Use
the existing actions/checkout and actions/setup-python entries in the workflow
as the places to harden.
In @.github/workflows/crewai-publish.yml:
- Around line 21-103: Pin every third-party GitHub Action in this workflow to an
immutable commit SHA instead of mutable tags or branches. Update the action
references in the publish workflow for actions/checkout, actions/setup-python,
astral-sh/setup-uv, actions/upload-artifact, actions/download-artifact, and
pypa/gh-action-pypi-publish so the jobs use fixed commit hashes while keeping
the existing build and publish steps unchanged.
- Around line 90-106: The publish-pypi job is using a long-lived PYPI_API_TOKEN
secret instead of PyPI Trusted Publishing and has no explicit permissions
scoping. Update the publish-pypi job in crewai-publish.yml to use OIDC by adding
the required id-token: write permission (and only the minimal permissions
needed) and remove the password-based secret from the
pypa/gh-action-pypi-publish@release/v1 step. Keep the job aligned with Trusted
Publishing setup for the existing publish workflow.
In `@crewai/pyproject.toml`:
- Around line 38-42: The dev dependency lists in pyproject.toml and
requirements-dev.txt are drifting apart, so make one source of truth for the dev
setup. Update the dev extra in pyproject.toml and the requirements-dev workflow
to stay aligned, including tinyfish, pytest, pytest-asyncio, ruff, and build as
needed, or switch requirements-dev.txt to install the dev extra directly so both
paths use the same dependency set.
In `@crewai/src/crewai_tinyfish/_serde.py`:
- Around line 38-47: The as_list helper in _serde.py is incorrectly treating
some scalar-like iterables as sequences, so strings, bytes, and dicts get split
into elements or keys instead of being wrapped as a single item. Update as_list
to special-case these types before the generic list(value) conversion, and keep
the existing behavior for None and real lists while preserving scalar-wrapping
semantics for any non-list input.
In `@crewai/src/crewai_tinyfish/tinyfish_agent_tool.py`:
- Around line 187-188: The _arun path in TinyFishAgentTool is still delegating
to the synchronous _run, which blocks the event loop. Update _arun to use
AsyncTinyFish and await client.agent.run(...) directly, keeping the sync _run
only as a fallback or separate path. Use the existing TinyFishAgentTool and
_arun/_run symbols to locate the change.
In `@crewai/src/crewai_tinyfish/tinyfish_browser_tool.py`:
- Around line 101-102: The _arun method in TinyfishBrowserTool is still calling
the synchronous _run directly, which blocks the event loop during slow session
creation. Update _arun to offload the blocking _run work to a worker thread,
matching the agent tool approach, so async crews can continue running without
freezing.
In `@crewai/UPSTREAM.md`:
- Around line 24-35: The fenced directory-tree block in UPSTREAM.md is missing a
language tag, triggering markdownlint MD040; update the fence around the tree
listing to use text so the block is explicitly marked as plain text. Keep the
change localized to the existing fenced snippet that shows the
crewai_tools/tools/* directories.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a4f827b2-66ff-488b-9739-52e160a89ca3
📒 Files selected for processing (26)
.github/workflows/crewai-ci.yml.github/workflows/crewai-publish.ymlcrewai/.env.examplecrewai/.gitignorecrewai/LICENSEcrewai/Makefilecrewai/README.mdcrewai/UPSTREAM.mdcrewai/examples/quickstart.pycrewai/examples/research_crew.pycrewai/pyproject.tomlcrewai/requirements-dev.txtcrewai/src/crewai_tinyfish/__init__.pycrewai/src/crewai_tinyfish/_client.pycrewai/src/crewai_tinyfish/_serde.pycrewai/src/crewai_tinyfish/tinyfish_agent_tool.pycrewai/src/crewai_tinyfish/tinyfish_browser_tool.pycrewai/src/crewai_tinyfish/tinyfish_fetch_tool.pycrewai/src/crewai_tinyfish/tinyfish_search_tool.pycrewai/tests/conftest.pycrewai/tests/test_agent_tool.pycrewai/tests/test_browser_tool.pycrewai/tests/test_fetch_tool.pycrewai/tests/test_search_tool.pygoogle-adk/README.mdgoogle-adk/pyproject.toml
| name: CrewAI CD - Publish to PyPI | ||
|
|
||
| on: | ||
| push: | ||
| branches: [main] | ||
| paths: | ||
| - ".github/workflows/crewai-publish.yml" | ||
| - "crewai/**" | ||
|
|
||
| jobs: | ||
| build: | ||
| name: Build distribution | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| outputs: |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Add a minimal top-level permissions block.
No permissions block is declared at the workflow level, so jobs inherit the default (often broad) GITHUB_TOKEN scopes. Restrict to least privilege at the top and let jobs widen only as needed.
🔒 Proposed fix
on:
push:
branches: [main]
paths:
- ".github/workflows/crewai-publish.yml"
- "crewai/**"
+permissions:
+ contents: read
+
jobs:📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| name: CrewAI CD - Publish to PyPI | |
| on: | |
| push: | |
| branches: [main] | |
| paths: | |
| - ".github/workflows/crewai-publish.yml" | |
| - "crewai/**" | |
| jobs: | |
| build: | |
| name: Build distribution | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| outputs: | |
| name: CrewAI CD - Publish to PyPI | |
| on: | |
| push: | |
| branches: [main] | |
| paths: | |
| - ".github/workflows/crewai-publish.yml" | |
| - "crewai/**" | |
| permissions: | |
| contents: read | |
| jobs: | |
| build: | |
| name: Build distribution | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| outputs: |
🧰 Tools
🪛 zizmor (1.26.1)
[warning] 1-107: overly broad permissions (excessive-permissions): default permissions used due to no permissions: block
(excessive-permissions)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/crewai-publish.yml around lines 1 - 16, Add a top-level
permissions block to the CrewAI CD - Publish to PyPI workflow so the default
GITHUB_TOKEN scope is minimized; keep the existing job-level permissions in
build and only widen permissions in specific jobs if needed. Update the workflow
near the on/job declarations, using the workflow name and build job as anchors
when editing.
Source: Linters/SAST tools
- Offload sync SDK calls to a worker thread in every tool's _arun (asyncio.to_thread) so async crews don't block the event loop during slow Agent/Browser calls - Harden _serde.as_list to wrap str/bytes/dict as single items instead of splitting them into characters/keys - Align dev tooling: add ruff + build to the [dev] extra so `.[dev]` is a complete toolchain - UPSTREAM.md: tag the directory-tree fence as text (markdownlint MD040) and align the documented tinyfish floor to >=0.2.5
Summary
Adds
crewai-tinyfish— official TinyFish tools for CrewAI agents, wrapping all four TinyFish API surfaces (Search, Fetch, Agent, Browser) as CrewAIBaseTools. Mirrors the structure and house style of the existinglangchainandgoogle-adkintegrations.What's included
crewai/src/crewai_tinyfish/— four tools:TinyFishSearchTool(Search),TinyFishFetchTool(Fetch),TinyFishAgentTool(Agent),TinyFishBrowserSessionTool(Browser)tinyfishextra), version-skew-tolerant kwargs, graceful error strings,_arunasync delegationTF_API_INTEGRATION="crewai"request attribution, matching the sibling packagescrewai/tests/— fully offline (TinyFish client faked); 11 passingcrewai/examples/—quickstart.py(direct tool smoke test) andresearch_crew.py(Search + Fetch research crew)crewai/README.md— written in the house style of the langchain/adk READMEscrewai-ci.yml(lint + test + build on PR) andcrewai-publish.yml(version-gated PyPI publish on merge tomain, mirroring the sibling publish workflows)Verification
Replicated the exact CI sequence locally in a clean env (no
tinyfishSDK installed, as on the runner):pip install -e . -r requirements-dev.txt✓make lint(ruff check + format check) ✓make test→ 11 passed ✓python -m build→ wheel + sdist,twine checkPASSED ✓All four tools were also exercised live against the TinyFish API (Search, Fetch, Agent, Browser-session + Playwright CDP connect), and a full CrewAI crew ran end-to-end using the Search + Fetch tools.
Publishing notes
crewai-tinyfishdoes not yet exist on PyPI; the publish workflow is version-gated, so it publishes only whenpyproject.tomlversionis new.PYPI_API_TOKENsecret, which has already created new projects (tinyfish-adk,langchain-tinyfish), so it has new-project scope.