mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-06-26 18:48:10 +00:00
Compare commits
4 Commits
fix/codeql
...
codex/trac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f608177f5 | ||
|
|
f364a7d988 | ||
|
|
2771c02f45 | ||
|
|
1dfaf3d552 |
@@ -5,15 +5,49 @@ icon: wrench
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
### Watch: Building CrewAI Agents & Flows with Coding Agent Skills
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 18,
|
||||
padding: "24px",
|
||||
marginBottom: 32,
|
||||
borderRadius: 12,
|
||||
border: "1px solid rgba(235,102,88,0.28)",
|
||||
background: "linear-gradient(180deg, rgba(235,102,88,0.14) 0%, rgba(235,102,88,0.06) 100%)"
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<p style={{ margin: 0, color: "#EB6658", fontSize: 13, fontWeight: 700, textTransform: "uppercase" }}>
|
||||
Coding agent setup
|
||||
</p>
|
||||
<h2 style={{ margin: "6px 0 8px" }}>Set up CrewAI in your coding agent</h2>
|
||||
<p style={{ margin: 0, color: "var(--mint-text-2)", maxWidth: 760 }}>
|
||||
Copy a ready-to-paste setup prompt for Claude Code, Codex, Cursor, or any coding agent. It installs the official CrewAI skills, checks the CLI, and points the agent at the right docs before it edits code.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
Install our coding agent skills (Claude Code, Codex, ...) to quickly get your coding agents up and running with CrewAI.
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="button button-primary"
|
||||
onClick={async (event) => {
|
||||
const prompt = `Set up this environment so I can build with CrewAI.
|
||||
<div style={{ display: "flex", flexWrap: "wrap", gap: 12, alignItems: "center" }}>
|
||||
<button
|
||||
type="button"
|
||||
style={{
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
minHeight: 42,
|
||||
padding: "0 16px",
|
||||
borderRadius: 8,
|
||||
border: "1px solid #EB6658",
|
||||
background: "#EB6658",
|
||||
color: "#FFFFFF",
|
||||
fontSize: 15,
|
||||
fontWeight: 700,
|
||||
lineHeight: 1,
|
||||
cursor: "pointer",
|
||||
boxShadow: "0 10px 24px rgba(235,102,88,0.22)"
|
||||
}}
|
||||
onClick={async (event) => {
|
||||
const prompt = `Set up this environment so I can build with CrewAI.
|
||||
|
||||
First install the official CrewAI coding-agent skills if this environment supports npx:
|
||||
|
||||
@@ -48,21 +82,49 @@ Setup steps:
|
||||
Do not hardcode API keys. Use .env.
|
||||
Do not invent CLI flags. Validate with crewai --help or crewai create --help.
|
||||
If a command fails, show the exact command and error, explain the likely cause, fix what you can safely fix, and retry once.`;
|
||||
const button = event.currentTarget;
|
||||
try {
|
||||
await navigator.clipboard.writeText(prompt);
|
||||
button.textContent = "Copied";
|
||||
} catch {
|
||||
button.textContent = "Copy failed";
|
||||
} finally {
|
||||
window.setTimeout(() => {
|
||||
button.textContent = "Copy instructions for coding agents";
|
||||
}, 1600);
|
||||
}
|
||||
}}
|
||||
>
|
||||
Copy instructions for coding agents
|
||||
</button>
|
||||
const button = event.currentTarget;
|
||||
const resetTimeout = button.dataset.resetTimeout;
|
||||
if (resetTimeout) {
|
||||
window.clearTimeout(Number(resetTimeout));
|
||||
}
|
||||
try {
|
||||
await navigator.clipboard.writeText(prompt);
|
||||
button.textContent = "Copied";
|
||||
} catch {
|
||||
button.textContent = "Copy failed";
|
||||
} finally {
|
||||
button.dataset.resetTimeout = String(window.setTimeout(() => {
|
||||
button.textContent = "Copy agent setup prompt";
|
||||
delete button.dataset.resetTimeout;
|
||||
}, 1600));
|
||||
}
|
||||
}}
|
||||
>
|
||||
Copy agent setup prompt
|
||||
</button>
|
||||
<a
|
||||
href="/en/guides/coding-tools/build-with-ai"
|
||||
style={{
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
minHeight: 42,
|
||||
padding: "0 16px",
|
||||
borderRadius: 8,
|
||||
border: "1px solid rgba(235,102,88,0.36)",
|
||||
color: "#EB6658",
|
||||
fontSize: 15,
|
||||
fontWeight: 700,
|
||||
lineHeight: 1,
|
||||
textDecoration: "none"
|
||||
}}
|
||||
>
|
||||
View coding-agent guide
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
### Watch: Building CrewAI Agents & Flows with Coding Agent Skills
|
||||
|
||||
<iframe src="https://www.loom.com/embed/befb9f68b81f42ad8112bfdd95a780af" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen style={{width: "100%", height: "400px"}}></iframe>
|
||||
|
||||
|
||||
130
docs/index.mdx
130
docs/index.mdx
@@ -27,9 +27,133 @@ mode: "wide"
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 12, justifyContent: 'center' }}>
|
||||
<a className="button button-primary" href="/en/quickstart">Get started</a>
|
||||
<a className="button" href="/en/changelog">View changelog</a>
|
||||
<a className="button" href="/en/api-reference/introduction">API Reference</a>
|
||||
<a
|
||||
href="/en/quickstart"
|
||||
style={{
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
minHeight: 42,
|
||||
padding: "0 16px",
|
||||
borderRadius: 8,
|
||||
border: "1px solid #EB6658",
|
||||
background: "#EB6658",
|
||||
color: "#FFFFFF",
|
||||
fontWeight: 700,
|
||||
lineHeight: 1,
|
||||
textDecoration: "none"
|
||||
}}
|
||||
>
|
||||
Get started
|
||||
</a>
|
||||
<button
|
||||
type="button"
|
||||
style={{
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
minHeight: 42,
|
||||
padding: "0 16px",
|
||||
borderRadius: 8,
|
||||
border: "1px solid rgba(235,102,88,0.36)",
|
||||
background: "rgba(235,102,88,0.08)",
|
||||
color: "#EB6658",
|
||||
fontWeight: 700,
|
||||
lineHeight: 1,
|
||||
cursor: "pointer"
|
||||
}}
|
||||
onClick={async (event) => {
|
||||
const prompt = `Set up this environment so I can build with CrewAI.
|
||||
|
||||
First install the official CrewAI coding-agent skills if this environment supports npx:
|
||||
|
||||
npx skills add crewaiinc/skills
|
||||
|
||||
If npx is missing or the current agent cannot load skills, do not fail the whole setup. Report the exact issue and continue using the CrewAI docs directly.
|
||||
|
||||
Use these CrewAI docs as source of truth before making assumptions:
|
||||
- https://skills.crewai.com
|
||||
- https://docs.crewai.com/llms.txt
|
||||
- https://docs.crewai.com/en/installation
|
||||
- https://docs.crewai.com/en/guides/coding-tools/build-with-ai
|
||||
|
||||
Setup steps:
|
||||
1. Check python3 --version. CrewAI requires Python >=3.10 and <3.14.
|
||||
2. Install uv if missing:
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
3. Source the uv environment if needed:
|
||||
source "$HOME/.local/bin/env"
|
||||
4. Install the CrewAI CLI:
|
||||
uv tool install crewai
|
||||
5. Verify the CLI:
|
||||
crewai version
|
||||
crewai create --help
|
||||
6. Create a project:
|
||||
CREWAI_DMN=true crewai create
|
||||
7. After project creation, inspect the generated files before editing.
|
||||
8. Run:
|
||||
crewai install
|
||||
crewai run
|
||||
|
||||
Do not hardcode API keys. Use .env.
|
||||
Do not invent CLI flags. Validate with crewai --help or crewai create --help.
|
||||
If a command fails, show the exact command and error, explain the likely cause, fix what you can safely fix, and retry once.`;
|
||||
const button = event.currentTarget;
|
||||
const resetTimeout = button.dataset.resetTimeout;
|
||||
if (resetTimeout) {
|
||||
window.clearTimeout(Number(resetTimeout));
|
||||
}
|
||||
try {
|
||||
await navigator.clipboard.writeText(prompt);
|
||||
button.textContent = "Copied";
|
||||
} catch {
|
||||
button.textContent = "Copy failed";
|
||||
} finally {
|
||||
button.dataset.resetTimeout = String(window.setTimeout(() => {
|
||||
button.textContent = "Copy agent setup prompt";
|
||||
delete button.dataset.resetTimeout;
|
||||
}, 1600));
|
||||
}
|
||||
}}
|
||||
>
|
||||
Copy agent setup prompt
|
||||
</button>
|
||||
<a
|
||||
href="/guides/coding-tools/build-with-ai"
|
||||
style={{
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
minHeight: 42,
|
||||
padding: "0 16px",
|
||||
borderRadius: 8,
|
||||
border: "1px solid rgba(235,102,88,0.28)",
|
||||
color: "#EB6658",
|
||||
fontWeight: 700,
|
||||
lineHeight: 1,
|
||||
textDecoration: "none"
|
||||
}}
|
||||
>
|
||||
Coding-agent guide
|
||||
</a>
|
||||
<a
|
||||
href="/en/api-reference/introduction"
|
||||
style={{
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
minHeight: 42,
|
||||
padding: "0 16px",
|
||||
borderRadius: 8,
|
||||
border: "1px solid rgba(235,102,88,0.18)",
|
||||
color: "var(--mint-text-2)",
|
||||
fontWeight: 700,
|
||||
lineHeight: 1,
|
||||
textDecoration: "none"
|
||||
}}
|
||||
>
|
||||
API Reference
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,8 @@ import shutil
|
||||
import click
|
||||
from crewai_core.telemetry import Telemetry
|
||||
|
||||
from crewai_cli.version import get_crewai_tools_dependency
|
||||
|
||||
|
||||
DECLARATIVE_FLOW_FOLDERS = ("crews", "tools", "knowledge", "skills")
|
||||
|
||||
@@ -71,6 +73,9 @@ def _create_python_flow(
|
||||
content = content.replace("{{name}}", name)
|
||||
content = content.replace("{{flow_name}}", class_name)
|
||||
content = content.replace("{{folder_name}}", folder_name)
|
||||
content = content.replace(
|
||||
"{{crewai_tools_dependency}}", get_crewai_tools_dependency()
|
||||
)
|
||||
|
||||
with open(dst_file, "w") as file:
|
||||
file.write(content)
|
||||
@@ -138,6 +143,9 @@ def _create_declarative_flow(
|
||||
content = content.replace("{{name}}", name)
|
||||
content = content.replace("{{flow_name}}", class_name)
|
||||
content = content.replace("{{folder_name}}", folder_name)
|
||||
content = content.replace(
|
||||
"{{crewai_tools_dependency}}", get_crewai_tools_dependency()
|
||||
)
|
||||
dst_file.write_text(content, encoding="utf-8")
|
||||
|
||||
(project_root / ".env").write_text("OPENAI_API_KEY=YOUR_API_KEY", encoding="utf-8")
|
||||
|
||||
@@ -20,6 +20,7 @@ from crewai_cli.utils import (
|
||||
load_env_vars,
|
||||
write_env_file,
|
||||
)
|
||||
from crewai_cli.version import get_crewai_tools_dependency
|
||||
|
||||
|
||||
# ── Provider / model data ───────────────────────────────────────
|
||||
@@ -89,7 +90,7 @@ description = "{name} using crewAI"
|
||||
authors = [{{ name = "Your Name", email = "you@example.com" }}]
|
||||
requires-python = ">=3.10,<3.14"
|
||||
dependencies = [
|
||||
"crewai[tools]==1.14.8a1"
|
||||
"{crewai_tools_dependency}"
|
||||
]
|
||||
|
||||
[build-system]
|
||||
@@ -1134,7 +1135,11 @@ def create_json_crew(
|
||||
|
||||
# Write pyproject.toml
|
||||
(folder_path / "pyproject.toml").write_text(
|
||||
_PYPROJECT_TOML.format(folder_name=folder_name, name=name),
|
||||
_PYPROJECT_TOML.format(
|
||||
folder_name=folder_name,
|
||||
name=name,
|
||||
crewai_tools_dependency=get_crewai_tools_dependency(),
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import threading
|
||||
import time
|
||||
from typing import Any, ClassVar, cast
|
||||
|
||||
from crewai_core.telemetry import Telemetry
|
||||
from rich.text import Text
|
||||
from textual import work
|
||||
from textual.app import App, ComposeResult
|
||||
@@ -571,6 +572,7 @@ FooterKey .footer-key--key {
|
||||
self._want_deploy: bool = False
|
||||
self._trace_url: str | None = None
|
||||
self._consent_screen: TraceConsentScreen | None = None
|
||||
self._telemetry: Telemetry | None = None
|
||||
|
||||
# ── Layout ──────────────────────────────────────────────
|
||||
|
||||
@@ -1042,10 +1044,21 @@ FooterKey .footer-key--key {
|
||||
self._unsubscribe()
|
||||
self.exit(self._crew_result)
|
||||
|
||||
def _record_tui_button_click(self, button_name: str) -> None:
|
||||
try:
|
||||
if self._telemetry is None:
|
||||
self._telemetry = Telemetry()
|
||||
self._telemetry.set_tracer()
|
||||
self._telemetry.tui_button_clicked_span(button_name)
|
||||
except Exception: # noqa: S110
|
||||
pass
|
||||
|
||||
def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||
if event.button.id in ("btn-traces", "btn-traces-done"):
|
||||
self._record_tui_button_click("view_traces")
|
||||
self.action_view_traces()
|
||||
elif event.button.id == "btn-deploy":
|
||||
self._record_tui_button_click("deploy")
|
||||
self.action_deploy_crew()
|
||||
|
||||
def _scroll_to_result(self) -> None:
|
||||
|
||||
@@ -19,7 +19,7 @@ from crewai_cli.utils import (
|
||||
is_dmn_mode_enabled,
|
||||
read_toml,
|
||||
)
|
||||
from crewai_cli.version import get_crewai_version
|
||||
from crewai_cli.version import get_crewai_tools_dependency, get_crewai_version
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -32,12 +32,12 @@ if TYPE_CHECKING:
|
||||
_INPUT_PLACEHOLDER_RE = re.compile(r"(?<!{){([A-Za-z_][A-Za-z0-9_\-]*)}(?!})")
|
||||
_CREWAI_CLI_RUNNER_PACKAGE_DIR_ENV = "CREWAI_CLI_RUNNER_PACKAGE_DIR"
|
||||
_CREWAI_RUNNER_SOURCE_DIR_ENV = "CREWAI_RUNNER_SOURCE_DIR"
|
||||
_FULL_CREWAI_INSTALL_MESSAGE = """\
|
||||
_FULL_CREWAI_INSTALL_MESSAGE = f"""\
|
||||
CrewAI CLI is installed without the `crewai` package required to run crews.
|
||||
|
||||
Install the full CrewAI prerelease package:
|
||||
Install the full CrewAI package:
|
||||
|
||||
uv tool install --force --prerelease=allow 'crewai[tools]==1.14.8a1'
|
||||
uv tool install --force '{get_crewai_tools_dependency()}'
|
||||
|
||||
The quotes are required in zsh so `crewai[tools]` is not treated as a glob.
|
||||
"""
|
||||
|
||||
@@ -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.15.0"
|
||||
"{{crewai_tools_dependency}}"
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
|
||||
@@ -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.15.0"
|
||||
"{{crewai_tools_dependency}}"
|
||||
]
|
||||
|
||||
[build-system]
|
||||
|
||||
@@ -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.15.0"
|
||||
"{{crewai_tools_dependency}}"
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
|
||||
@@ -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.15.0"
|
||||
"{{crewai_tools_dependency}}"
|
||||
]
|
||||
|
||||
[tool.crewai]
|
||||
|
||||
@@ -23,6 +23,7 @@ from crewai_cli.utils import (
|
||||
tree_copy,
|
||||
tree_find_and_replace,
|
||||
)
|
||||
from crewai_cli.version import get_crewai_tools_dependency
|
||||
|
||||
|
||||
console = Console()
|
||||
@@ -81,6 +82,9 @@ class ToolCommand(BaseCommand, PlusAPIMixin):
|
||||
tree_copy(template_dir, project_root)
|
||||
tree_find_and_replace(project_root, "{{folder_name}}", folder_name)
|
||||
tree_find_and_replace(project_root, "{{class_name}}", class_name)
|
||||
tree_find_and_replace(
|
||||
project_root, "{{crewai_tools_dependency}}", get_crewai_tools_dependency()
|
||||
)
|
||||
|
||||
agents_md_src = Path(__file__).parent.parent / "templates" / "AGENTS.md"
|
||||
if agents_md_src.exists():
|
||||
|
||||
@@ -19,6 +19,8 @@ from crewai_core.tool_credentials import (
|
||||
)
|
||||
from rich.console import Console
|
||||
|
||||
from crewai_cli.version import get_crewai_tools_dependency
|
||||
|
||||
|
||||
__all__ = [
|
||||
"build_env_with_all_tool_credentials",
|
||||
@@ -73,6 +75,9 @@ def copy_template(
|
||||
content = content.replace("{{name}}", name)
|
||||
content = content.replace("{{crew_name}}", class_name)
|
||||
content = content.replace("{{folder_name}}", folder_name)
|
||||
content = content.replace(
|
||||
"{{crewai_tools_dependency}}", get_crewai_tools_dependency()
|
||||
)
|
||||
|
||||
with open(dst, "w") as file:
|
||||
file.write(content)
|
||||
|
||||
@@ -13,10 +13,26 @@ from crewai_core.version import (
|
||||
is_current_version_yanked as is_current_version_yanked,
|
||||
is_newer_version_available as is_newer_version_available,
|
||||
)
|
||||
from packaging.version import Version
|
||||
|
||||
from crewai_cli import __version__ as _crewai_cli_version
|
||||
|
||||
|
||||
def get_crewai_dependency_range(current_version: str | None = None) -> str:
|
||||
"""Return the supported CrewAI dependency range for generated projects."""
|
||||
parsed_version = Version(current_version or _crewai_cli_version)
|
||||
return f">={parsed_version},<{parsed_version.major + 1}.0.0"
|
||||
|
||||
|
||||
def get_crewai_tools_dependency(current_version: str | None = None) -> str:
|
||||
"""Return the generated-project dependency for CrewAI with tools."""
|
||||
return f"crewai[tools]{get_crewai_dependency_range(current_version)}"
|
||||
|
||||
|
||||
__all__ = [
|
||||
"check_version",
|
||||
"get_crewai_dependency_range",
|
||||
"get_crewai_tools_dependency",
|
||||
"get_crewai_version",
|
||||
"get_latest_version_from_pypi",
|
||||
"is_current_version_yanked",
|
||||
|
||||
@@ -176,7 +176,7 @@ def test_create_project_zip_keeps_json_project_root_shape(tmp_path: Path):
|
||||
[project]
|
||||
name = "json_crew"
|
||||
version = "0.1.0"
|
||||
dependencies = ["crewai[tools]==1.14.8a1"]
|
||||
dependencies = ["crewai[tools]>=1.15.0,<2.0.0"]
|
||||
|
||||
[tool.crewai]
|
||||
type = "crew"
|
||||
|
||||
@@ -735,8 +735,9 @@ def test_json_create_provider_preselects_default_model(tmp_path, monkeypatch):
|
||||
|
||||
pyproject = tomli.loads((tmp_path / "json_crew" / "pyproject.toml").read_text())
|
||||
dependency = pyproject["project"]["dependencies"][0]
|
||||
assert dependency == "crewai[tools]==1.14.8a1"
|
||||
assert Version("1.14.8a1") in Requirement(dependency).specifier
|
||||
assert dependency == "crewai[tools]>=1.15.0,<2.0.0"
|
||||
assert Version("1.15.0") in Requirement(dependency).specifier
|
||||
assert Version("2.0.0") not in Requirement(dependency).specifier
|
||||
assert pyproject["tool"]["hatch"]["build"]["targets"]["wheel"][
|
||||
"only-include"
|
||||
] == ["agents", "crew.jsonc", "tools", "knowledge", "skills"]
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from datetime import datetime
|
||||
import time
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -126,6 +128,37 @@ def test_chain_deploy_does_not_login_for_deploy_exit(monkeypatch, capsys) -> Non
|
||||
assert "Deploy failed with exit code 42" in capsys.readouterr().out
|
||||
|
||||
|
||||
def test_view_traces_button_click_records_telemetry(monkeypatch) -> None:
|
||||
app = CrewRunApp()
|
||||
app._status = "completed"
|
||||
app._trace_url = "https://app.crewai.com/traces/test"
|
||||
app._telemetry = Mock()
|
||||
opened_urls: list[str] = []
|
||||
|
||||
monkeypatch.setattr("webbrowser.open", lambda url: opened_urls.append(url))
|
||||
|
||||
app.on_button_pressed(SimpleNamespace(button=SimpleNamespace(id="btn-traces")))
|
||||
|
||||
app._telemetry.tui_button_clicked_span.assert_called_once_with("view_traces")
|
||||
assert opened_urls == ["https://app.crewai.com/traces/test"]
|
||||
|
||||
|
||||
def test_deploy_button_click_records_telemetry() -> None:
|
||||
app = CrewRunApp()
|
||||
app._status = "completed"
|
||||
app._crew_result = object()
|
||||
app._telemetry = Mock()
|
||||
app._unsubscribe = lambda: None # type: ignore[method-assign]
|
||||
exits: list[object] = []
|
||||
app.exit = lambda result: exits.append(result) # type: ignore[method-assign]
|
||||
|
||||
app.on_button_pressed(SimpleNamespace(button=SimpleNamespace(id="btn-deploy")))
|
||||
|
||||
app._telemetry.tui_button_clicked_span.assert_called_once_with("deploy")
|
||||
assert app._want_deploy is True
|
||||
assert exits == [app._crew_result]
|
||||
|
||||
|
||||
def test_conversation_turn_done_records_assistant_message() -> None:
|
||||
class RawResult:
|
||||
raw = "hello from the flow"
|
||||
|
||||
@@ -25,10 +25,7 @@ def test_missing_crewai_package_shows_full_install_hint(monkeypatch):
|
||||
|
||||
message = exc_info.value.message
|
||||
assert "CrewAI CLI is installed without the `crewai` package" in message
|
||||
assert (
|
||||
"uv tool install --force --prerelease=allow 'crewai[tools]==1.14.8a1'"
|
||||
in message
|
||||
)
|
||||
assert "uv tool install --force 'crewai[tools]>=1.15.0,<2.0.0'" in message
|
||||
assert "quotes are required in zsh" in message
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ from unittest.mock import MagicMock, patch
|
||||
|
||||
from crewai_cli.version import get_crewai_version as _get_ver
|
||||
from crewai_cli.version import (
|
||||
get_crewai_dependency_range,
|
||||
get_crewai_tools_dependency,
|
||||
get_crewai_version,
|
||||
get_latest_version_from_pypi,
|
||||
is_current_version_yanked,
|
||||
@@ -31,6 +33,11 @@ def test_dynamic_versioning_consistency() -> None:
|
||||
assert len(package_version.strip()) > 0
|
||||
|
||||
|
||||
def test_generated_project_dependency_uses_next_major_upper_bound() -> None:
|
||||
assert get_crewai_dependency_range("1.15.0") == ">=1.15.0,<2.0.0"
|
||||
assert get_crewai_tools_dependency("1.15.0") == "crewai[tools]>=1.15.0,<2.0.0"
|
||||
|
||||
|
||||
class TestVersionChecking:
|
||||
"""Test version checking utilities."""
|
||||
|
||||
|
||||
@@ -54,6 +54,10 @@ def test_create_success(mock_subprocess, capsys, tool_command):
|
||||
)
|
||||
assert os.path.isfile(os.path.join("test_tool", "src", "test_tool", "tool.py"))
|
||||
|
||||
with open(os.path.join("test_tool", "pyproject.toml"), "r") as f:
|
||||
content = f.read()
|
||||
assert '"crewai[tools]>=1.15.0,<2.0.0"' in content
|
||||
|
||||
with open(os.path.join("test_tool", "src", "test_tool", "tool.py"), "r") as f:
|
||||
content = f.read()
|
||||
assert "class TestTool" in content
|
||||
|
||||
@@ -249,6 +249,17 @@ class Telemetry:
|
||||
|
||||
self._safe_telemetry_procedure(_operation)
|
||||
|
||||
def tui_button_clicked_span(self, button_name: str) -> None:
|
||||
"""Records when a user clicks a button in the CLI TUI."""
|
||||
|
||||
def _operation() -> None:
|
||||
tracer = trace.get_tracer("crewai.telemetry")
|
||||
span = tracer.start_span("TUI Button Clicked")
|
||||
self._add_attribute(span, "button_name", button_name)
|
||||
close_span(span)
|
||||
|
||||
self._safe_telemetry_procedure(_operation)
|
||||
|
||||
def flow_creation_span(self, flow_name: str) -> None:
|
||||
"""Records the creation of a new flow."""
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
from unittest.mock import Mock
|
||||
|
||||
from crewai_core import (
|
||||
constants,
|
||||
@@ -128,3 +129,29 @@ def test_core_telemetry_skips_duplicate_tracer_provider(
|
||||
|
||||
assert called is False
|
||||
assert telemetry.trace_set is True
|
||||
|
||||
|
||||
def test_core_telemetry_records_tui_button_click(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
from crewai_core.telemetry import Telemetry
|
||||
|
||||
Telemetry._instance = None
|
||||
monkeypatch.delenv("OTEL_SDK_DISABLED", raising=False)
|
||||
monkeypatch.delenv("CREWAI_DISABLE_TELEMETRY", raising=False)
|
||||
monkeypatch.delenv("CREWAI_DISABLE_TRACKING", raising=False)
|
||||
|
||||
tracer = Mock()
|
||||
span = Mock()
|
||||
tracer.start_span.return_value = span
|
||||
monkeypatch.setattr(
|
||||
"crewai_core.telemetry.trace.get_tracer",
|
||||
lambda _name: tracer,
|
||||
)
|
||||
|
||||
telemetry = Telemetry()
|
||||
telemetry.tui_button_clicked_span("view_traces")
|
||||
|
||||
tracer.start_span.assert_called_once_with("TUI Button Clicked")
|
||||
span.set_attribute.assert_called_once_with("button_name", "view_traces")
|
||||
span.end.assert_called_once()
|
||||
|
||||
Reference in New Issue
Block a user