diff --git a/.gitignore b/.gitignore
index 785c2c299..d7e89fcaa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,3 +30,4 @@ chromadb-*.lock
.crewai/memory
blogs/*
secrets/*
+UNKNOWN.egg-info/
diff --git a/README.md b/README.md
index c832d0025..817f5155f 100644
--- a/README.md
+++ b/README.md
@@ -83,6 +83,7 @@ intelligent automations.
## Table of contents
+- [Build with AI](#build-with-ai)
- [Why CrewAI?](#why-crewai)
- [Getting Started](#getting-started)
- [Key Features](#key-features)
@@ -101,6 +102,32 @@ intelligent automations.
- [Telemetry](#telemetry)
- [License](#license)
+## Build with AI
+
+Using an AI coding agent? Teach it CrewAI best practices in one command:
+
+**Claude Code:**
+```shell
+/plugin marketplace add crewAIInc/skills
+/plugin install crewai-skills@crewai-plugins
+/reload-plugins
+```
+Four skills that activate automatically when you ask relevant CrewAI questions:
+
+| Skill | When it runs |
+|-------|--------------|
+| `getting-started` | Scaffolding new projects, choosing between `LLM.call()` / `Agent` / `Crew` / `Flow`, wiring `crew.py` / `main.py` |
+| `design-agent` | Configuring agents — role, goal, backstory, tools, LLMs, memory, guardrails |
+| `design-task` | Writing task descriptions, dependencies, structured output (`output_pydantic`, `output_json`), human review |
+| `ask-docs` | Querying the live [CrewAI docs MCP server](https://docs.crewai.com/mcp) for up-to-date API details |
+
+**Cursor, Codex, Windsurf, and others ([skills.sh](https://skills.sh/crewaiinc/skills)):**
+```shell
+npx skills add crewaiinc/skills
+```
+
+This installs the official [CrewAI Skills](https://github.com/crewAIInc/skills) — structured instructions that teach coding agents how to scaffold Flows, configure Crews, design agents and tasks, and follow CrewAI patterns.
+
## Why CrewAI?
diff --git a/docs/ar/changelog.mdx b/docs/ar/changelog.mdx
index 7b4ad9f17..acbb285bf 100644
--- a/docs/ar/changelog.mdx
+++ b/docs/ar/changelog.mdx
@@ -4,6 +4,126 @@ description: "تحديثات المنتج والتحسينات وإصلاحات
icon: "clock"
mode: "wide"
---
+
+ ## v1.14.3a3
+
+ [عرض الإصدار على GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.3a3)
+
+ ## ما الذي تغير
+
+ ### الميزات
+ - إضافة دعم لـ e2b
+ - تنفيذ التراجع إلى DefaultAzureCredential عند عدم توفير مفتاح API
+
+ ### إصلاحات الأخطاء
+ - ترقية lxml إلى >=6.1.0 لمعالجة مشكلة الأمان GHSA-vfmq-68hx-4jfw
+
+ ### الوثائق
+ - إزالة الأسئلة الشائعة حول التسعير من صفحة البناء باستخدام الذكاء الاصطناعي عبر جميع اللغات
+
+ ### الأداء
+ - تحسين وقت بدء التشغيل البارد بنسبة ~29% من خلال التحميل الكسول لمجموعة أدوات MCP وأنواع الأحداث
+
+ ## المساهمون
+
+ @alex-clawd, @github-advanced-security[bot], @greysonlalonde, @iris-clawd, @lorenzejay, @mattatcha
+
+
+
+
+ ## v1.14.3a2
+
+ [عرض الإصدار على GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.3a2)
+
+ ## ما الذي تغير
+
+ ### الميزات
+ - إضافة دعم لـ bedrock V4
+ - إضافة أدوات Daytona sandbox لوظائف محسّنة
+ - إضافة صفحة "البناء باستخدام الذكاء الاصطناعي" — مستندات أصلية للذكاء الاصطناعي لوكلاء البرمجة
+ - إضافة "البناء باستخدام الذكاء الاصطناعي" إلى التنقل في صفحة "البدء" وملفات الصفحات لجميع اللغات (en, ko, pt-BR, ar)
+
+ ### إصلاحات الأخطاء
+ - إصلاح انتشار أسماء @CrewBase الضمنية إلى أحداث الطاقم
+ - حل مشكلة تكرار تهيئة الدفعات في دمج بيانات التنفيذ الوصفية
+ - إصلاح تسلسل حقول مرجع فئة Task لعمليات التحقق من النقاط
+ - التعامل مع نتيجة BaseModel في حلقة إعادة المحاولة للحدود
+ - تحديث python-dotenv إلى الإصدار >=1.2.2 للامتثال الأمني
+
+ ### الوثائق
+ - تحديث سجل التغييرات والإصدار لـ v1.14.3a1
+ - تحديث الأوصاف وتطبيق الترجمات الفعلية
+
+ ## المساهمون
+
+ @MatthiasHowellYopp, @github-actions[bot], @greysonlalonde, @iris-clawd, @lorenzejay, @renatonitta
+
+
+
+
+ ## v1.14.3a1
+
+ [عرض الإصدار على GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.3a1)
+
+ ## ما الذي تغير
+
+ ### الميزات
+ - إضافة دعم نقاط التحقق والفروع لوكلاء مستقلين
+
+ ### إصلاحات الأخطاء
+ - الحفاظ على thought_signature في استدعاءات أداة البث Gemini
+ - إصدار task_started عند استئناف الفرع وإعادة تصميم واجهة المستخدم النصية لنقاط التحقق
+ - تصحيح ترتيب التشغيل الجاف ومعالجة الفرع القديم الذي تم التحقق منه في إصدار أدوات التطوير
+ - استخدام تواريخ مستقبلية في اختبارات تقليم نقاط التحقق لمنع الفشل المعتمد على الوقت (#5543)
+
+ ### الوثائق
+ - تحديث سجل التغييرات والإصدار لـ v1.14.2
+
+ ## المساهمون
+
+ @alex-clawd, @greysonlalonde
+
+
+
+
+ ## v1.14.2
+
+ [عرض الإصدار على GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.2)
+
+ ## ما الذي تغير
+
+ ### الميزات
+ - إضافة أوامر استئناف النقاط التفتيش، والاختلاف، والتنظيف مع تحسين إمكانية الاكتشاف.
+ - إضافة معلمة `from_checkpoint` إلى `Agent.kickoff` والطرق ذات الصلة.
+ - إضافة أوامر إدارة القوالب لقوالب المشاريع.
+ - إضافة تلميحات استئناف إلى إصدار أدوات المطور عند الفشل.
+ - إضافة واجهة سطر الأوامر للتحقق من النشر وتعزيز سهولة استخدام تهيئة LLM.
+ - إضافة تقسيم النقاط التفتيشية مع تتبع النسب.
+ - إثراء تتبع رموز LLM مع رموز الاستدلال ورموز إنشاء التخزين المؤقت.
+
+ ### إصلاحات الأخطاء
+ - إصلاح المطالبة بشأن تعارضات الفروع القديمة في إصدار أدوات المطور.
+ - تصحيح الثغرات في `authlib` و `langchain-text-splitters` و `pypdf`.
+ - تحديد نطاق معالجات البث لمنع تلوث أجزاء التشغيل المتقاطعة.
+ - إرسال نقاط التفتيش عبر واجهات Flow في TUI.
+ - استخدام نمط البحث المتكرر لاكتشاف نقاط التفتيش بتنسيق JSON.
+ - التعامل مع مخططات JSON الدائرية في أداة حل MCP.
+ - الحفاظ على معلمات استدعاء أداة Bedrock من خلال إزالة القيمة الافتراضية الصحيحة.
+ - إصدار حدث flow_finished بعد استئناف HITL.
+ - إصلاح ثغرات متنوعة من خلال تحديث التبعيات، بما في ذلك `requests` و `cryptography` و `pytest`.
+ - إصلاح لإيقاف تمرير وضع صارم إلى واجهة برمجة التطبيقات Bedrock Converse.
+
+ ### الوثائق
+ - توثيق المعلمات المفقودة وإضافة قسم النقاط التفتيشية.
+ - تحديث سجل التغييرات والإصدار للإصدار v1.14.2 ومرشحي الإصدار السابقين.
+ - إضافة توثيق ميزة A2A الخاصة بالشركات وتحديث وثائق A2A المفتوحة المصدر.
+
+ ## المساهمون
+
+ @Yanhu007، @alex-clawd، @github-actions[bot]، @greysonlalonde، @iris-clawd، @lorenzejay، @lucasgomide
+
+
+
## v1.14.2rc1
diff --git a/docs/ar/guides/coding-tools/build-with-ai.mdx b/docs/ar/guides/coding-tools/build-with-ai.mdx
new file mode 100644
index 000000000..88a94e84d
--- /dev/null
+++ b/docs/ar/guides/coding-tools/build-with-ai.mdx
@@ -0,0 +1,214 @@
+---
+title: "البناء باستخدام الذكاء الاصطناعي"
+description: "كل ما يحتاجه وكلاء البرمجة بالذكاء الاصطناعي للبناء والنشر والتوسع مع CrewAI — المهارات، وثائق مقروءة آلياً، النشر، وميزات المؤسسات."
+icon: robot
+mode: "wide"
+---
+
+# البناء باستخدام الذكاء الاصطناعي
+
+CrewAI مُصمَّم أصلاً للعمل مع الذكاء الاصطناعي. تجمع هذه الصفحة ما يحتاجه وكيل البرمجة بالذكاء الاصطناعي للبناء مع CrewAI — سواءً كان Claude Code أو Codex أو Cursor أو Gemini CLI أو أي مساعد آخر يساعد المطوّر على إيصال الـ crews والـ flows.
+
+### وكلاء البرمجة المدعومون
+
+
+
+
+
+
+
+
+
+
+ صُممت هذه الصفحة للبشر وللمساعدين الذكيين على حدٍّ سواء. إذا كنت وكيل برمجة، ابدأ بـ **Skills** للحصول على سياق CrewAI، ثم استخدم **llms.txt** للوصول الكامل إلى الوثائق.
+
+
+---
+
+## 1. Skills — علِّم وكيلك CrewAI
+
+**Skills** حزم تعليمات تمنح وكلاء البرمجة معرفة عميقة بـ CrewAI — كيفية إنشاء هيكل Flows، وضبط Crews، استخدام الأدوات، واتباع اتفاقيات الإطار.
+
+
+
+
+ مهارات CrewAI متاحة في **سوق إضافات Claude Code** — نفس قناة التوزيع التي تستخدمها شركات رائدة في مجال الذكاء الاصطناعي:
+ ```shell
+ /plugin marketplace add crewAIInc/skills
+ /plugin install crewai-skills@crewai-plugins
+ /reload-plugins
+ ```
+
+ تُفعَّل أربع مهارات تلقائياً عند طرح أسئلة متعلقة بـ CrewAI:
+
+ | المهارة | متى تُستخدم |
+ |---------|-------------|
+ | `getting-started` | مشاريع جديدة، الاختيار بين `LLM.call()` / `Agent` / `Crew` / `Flow`، ربط `crew.py` / `main.py` |
+ | `design-agent` | ضبط الوكلاء — الدور، الهدف، الخلفية، الأدوات، نماذج اللغة، الذاكرة، الحدود الآمنة |
+ | `design-task` | وصف المهام، التبعيات، المخرجات المنظمة (`output_pydantic`، `output_json`)، المراجعة البشرية |
+ | `ask-docs` | الاستعلام من [خادم CrewAI docs MCP](https://docs.crewai.com/mcp) للحصول على تفاصيل واجهة البرمجة الحالية |
+
+
+ يعمل مع Claude Code أو Codex أو Cursor أو Gemini CLI أو أي وكيل برمجة:
+ ```shell
+ npx skills add crewaiinc/skills
+ ```
+ يُجلب من [سجل skills.sh](https://skills.sh/crewaiinc/skills).
+
+
+
+
+
+ استخدم إحدى الطريقتين أعلاه — سوق إضافات Claude Code أو `npx skills add`. كلاهما يثبّت الحزمة الرسمية [crewAIInc/skills](https://github.com/crewAIInc/skills).
+
+
+ تعلّم الحزمة وكيلك:
+ - **Flows** — تطبيقات ذات حالة، خطوات، وتشغيل crews
+ - **Crews والوكلاء** — أنماط YAML أولاً، الأدوار، المهام، التفويض
+ - **الأدوات والتكاملات** — البحث، واجهات API، خوادم MCP، وأدوات CrewAI الشائعة
+ - **هيكل المشروع** — هياكل CLI واتفاقيات المستودع
+ - **أنماط محدثة** — يتماشى مع وثائق CrewAI الحالية وأفضل الممارسات
+
+
+ يمكن لوكيلك الآن إنشاء هيكل وبناء مشاريع CrewAI دون أن تعيد شرح الإطار في كل جلسة.
+
+
+
+
+
+ كيف تعمل المهارات في وكلاء CrewAI — الحقن، التفعيل، والأنماط.
+
+
+ نظرة على حزمة crewAIInc/skills وما تتضمنه.
+
+
+ إعداد AGENTS.md لـ Claude Code وCodex وCursor وGemini CLI.
+
+
+ القائمة الرسمية — المهارات، إحصاءات التثبيت، والتدقيق.
+
+
+
+---
+
+## 2. llms.txt — وثائق مقروءة آلياً
+
+ينشر CrewAI ملف `llms.txt` يمنح المساعدين الذكيين وصولاً مباشراً إلى الوثائق الكاملة بصيغة مقروءة آلياً.
+
+```
+https://docs.crewai.com/llms.txt
+```
+
+
+
+ [`llms.txt`](https://llmstxt.org/) معيار ناشئ لجعل الوثائق قابلة للاستهلاك من قبل نماذج اللغة الكبيرة. بدلاً من استخراج HTML، يمكن لوكيلك جلب ملف نصي واحد منظم بكل المحتوى المطلوب.
+
+ ملف `llms.txt` الخاص بـ CrewAI **متاح فعلياً** — يمكن لوكيلك استخدامه الآن.
+
+
+ وجِّه وكيل البرمجة إلى عنوان URL عندما يحتاج إلى مرجع CrewAI:
+
+ ```
+ Fetch https://docs.crewai.com/llms.txt for CrewAI documentation.
+ ```
+
+ يمكن للعديد من وكلاء البرمجة (Claude Code، Cursor، وغيرهما) جلب عناوين URL مباشرة. يحتوي الملف على وثائق منظمة تغطي مفاهيم CrewAI وواجهات البرمجة والأدلة.
+
+
+ - **دون استخراج ويب** — محتوى نظيف ومنظم في طلب واحد
+ - **دائماً محدث** — يُقدَّم مباشرة من docs.crewai.com
+ - **محسّن لنماذج اللغة** — مُنسَّق لنوافذ السياق لا للمتصفحات
+ - **يُكمّل Skills** — المهارات تعلّم الأنماط، وllms.txt يوفّر المرجع
+
+
+
+---
+
+## 3. النشر للمؤسسات
+
+انتقل من crew محلي إلى الإنتاج على **CrewAI AMP** (منصة إدارة الوكلاء) في دقائق.
+
+
+
+ أنشئ الهيكل واختبر crew أو flow:
+ ```bash
+ crewai create crew my_crew
+ cd my_crew
+ crewai run
+ ```
+
+
+ تأكد أن هيكل مشروعك جاهز:
+ ```bash
+ crewai deploy --prepare
+ ```
+ راجع [دليل التحضير](/ar/enterprise/guides/prepare-for-deployment) لتفاصيل الهيكل والمتطلبات.
+
+
+ ادفع إلى منصة CrewAI AMP:
+ ```bash
+ crewai deploy
+ ```
+ يمكنك أيضاً النشر عبر [تكامل GitHub](/ar/enterprise/guides/deploy-to-amp) أو [Crew Studio](/ar/enterprise/guides/enable-crew-studio).
+
+
+ يحصل الـ crew المنشور على نقطة نهاية REST. دمجه في أي تطبيق:
+ ```bash
+ curl -X POST https://app.crewai.com/api/v1/crews//kickoff \
+ -H "Authorization: Bearer $CREWAI_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{"inputs": {"topic": "AI agents"}}'
+ ```
+
+
+
+
+
+ دليل النشر الكامل — CLI وGitHub وCrew Studio.
+
+
+ نظرة على المنصة — ما يوفّره AMP لـ crews في الإنتاج.
+
+
+
+---
+
+## 4. ميزات المؤسسات
+
+CrewAI AMP مُصمَّم لفرق الإنتاج. إليك ما تحصل عليه بعد النشر.
+
+
+
+ مسارات تنفيذ مفصّلة، وسجلات، ومقاييس أداء لكل تشغيل crew. راقب قرارات الوكلاء، استدعاءات الأدوات، وإكمال المهام في الوقت الفعلي.
+
+
+ واجهة منخفضة/بدون كود لإنشاء crews وتخصيصها ونشرها بصرياً — ثم التصدير إلى الشيفرة أو النشر مباشرة.
+
+
+ بث أحداث فورية من تنفيذات الـ crews إلى أنظمتك. تكامل مع Slack أو Zapier أو أي مستهلك ويبهوك.
+
+
+ SSO وRBAC وضوابط على مستوى المؤسسة. أدر من يمكنه إنشاء crews ونشرها والوصول إليها.
+
+
+ انشر وشارك أدواتاً مخصصة عبر مؤسستك. ثبّت أدوات المجتمع من السجل.
+
+
+ شغّل CrewAI AMP على بنيتك التحتية. قدرات المنصة كاملة مع ضوابط إقامة البيانات والامتثال.
+
+
+
+
+
+ لفرق تحتاج نقل سير عمل وكلاء الذكاء الاصطناعي من النماذج الأولية إلى الإنتاج — مع المراقبة وضوابط الوصول والبنية التحتية القابلة للتوسع. سواءً كنت ناشئاً أو مؤسسة كبيرة، يتولى AMP التعقيد التشغيلي لتتفرغ لبناء الوكلاء.
+
+
+ - **السحابة (app.crewai.com)** — تُدار من CrewAI، أسرع طريق إلى الإنتاج
+ - **Factory (استضافة ذاتية)** — على بنيتك التحتية لسيطرة كاملة على البيانات
+ - **هجين** — دمج السحابة والاستضافة الذاتية حسب حساسية البيانات
+
+
+
+
+ سجّل وانشر أول crew لك في الإنتاج.
+
diff --git a/docs/docs.json b/docs/docs.json
index 3f37157df..e2fe48ff0 100644
--- a/docs/docs.json
+++ b/docs/docs.json
@@ -56,7 +56,7 @@
},
"versions": [
{
- "version": "v1.14.1",
+ "version": "v1.14.2",
"default": true,
"tabs": [
{
@@ -79,6 +79,7 @@
"group": "Get Started",
"pages": [
"en/introduction",
+ "en/guides/coding-tools/build-with-ai",
"en/skills",
"en/installation",
"en/quickstart"
@@ -127,7 +128,484 @@
"group": "Coding Tools",
"icon": "terminal",
"pages": [
- "en/guides/coding-tools/agents-md"
+ "en/guides/coding-tools/agents-md",
+ "en/guides/coding-tools/build-with-ai"
+ ]
+ },
+ {
+ "group": "Advanced",
+ "icon": "gear",
+ "pages": [
+ "en/guides/advanced/customizing-prompts",
+ "en/guides/advanced/fingerprinting"
+ ]
+ },
+ {
+ "group": "Migration",
+ "icon": "shuffle",
+ "pages": [
+ "en/guides/migration/migrating-from-langgraph"
+ ]
+ }
+ ]
+ },
+ {
+ "group": "Core Concepts",
+ "pages": [
+ "en/concepts/agents",
+ "en/concepts/agent-capabilities",
+ "en/concepts/tasks",
+ "en/concepts/crews",
+ "en/concepts/flows",
+ "en/concepts/production-architecture",
+ "en/concepts/knowledge",
+ "en/concepts/skills",
+ "en/concepts/llms",
+ "en/concepts/files",
+ "en/concepts/processes",
+ "en/concepts/collaboration",
+ "en/concepts/training",
+ "en/concepts/memory",
+ "en/concepts/reasoning",
+ "en/concepts/planning",
+ "en/concepts/testing",
+ "en/concepts/cli",
+ "en/concepts/tools",
+ "en/concepts/event-listener",
+ "en/concepts/checkpointing"
+ ]
+ },
+ {
+ "group": "MCP Integration",
+ "pages": [
+ "en/mcp/overview",
+ "en/mcp/dsl-integration",
+ "en/mcp/stdio",
+ "en/mcp/sse",
+ "en/mcp/streamable-http",
+ "en/mcp/multiple-servers",
+ "en/mcp/security"
+ ]
+ },
+ {
+ "group": "Tools",
+ "pages": [
+ "en/tools/overview",
+ {
+ "group": "File & Document",
+ "icon": "folder-open",
+ "pages": [
+ "en/tools/file-document/overview",
+ "en/tools/file-document/filereadtool",
+ "en/tools/file-document/filewritetool",
+ "en/tools/file-document/pdfsearchtool",
+ "en/tools/file-document/docxsearchtool",
+ "en/tools/file-document/mdxsearchtool",
+ "en/tools/file-document/xmlsearchtool",
+ "en/tools/file-document/txtsearchtool",
+ "en/tools/file-document/jsonsearchtool",
+ "en/tools/file-document/csvsearchtool",
+ "en/tools/file-document/directorysearchtool",
+ "en/tools/file-document/directoryreadtool",
+ "en/tools/file-document/ocrtool",
+ "en/tools/file-document/pdf-text-writing-tool"
+ ]
+ },
+ {
+ "group": "Web Scraping & Browsing",
+ "icon": "globe",
+ "pages": [
+ "en/tools/web-scraping/overview",
+ "en/tools/web-scraping/scrapewebsitetool",
+ "en/tools/web-scraping/scrapeelementfromwebsitetool",
+ "en/tools/web-scraping/scrapflyscrapetool",
+ "en/tools/web-scraping/seleniumscrapingtool",
+ "en/tools/web-scraping/scrapegraphscrapetool",
+ "en/tools/web-scraping/spidertool",
+ "en/tools/web-scraping/browserbaseloadtool",
+ "en/tools/web-scraping/hyperbrowserloadtool",
+ "en/tools/web-scraping/stagehandtool",
+ "en/tools/web-scraping/firecrawlcrawlwebsitetool",
+ "en/tools/web-scraping/firecrawlscrapewebsitetool",
+ "en/tools/web-scraping/oxylabsscraperstool",
+ "en/tools/web-scraping/brightdata-tools"
+ ]
+ },
+ {
+ "group": "Search & Research",
+ "icon": "magnifying-glass",
+ "pages": [
+ "en/tools/search-research/overview",
+ "en/tools/search-research/serperdevtool",
+ "en/tools/search-research/bravesearchtool",
+ "en/tools/search-research/exasearchtool",
+ "en/tools/search-research/linkupsearchtool",
+ "en/tools/search-research/githubsearchtool",
+ "en/tools/search-research/websitesearchtool",
+ "en/tools/search-research/codedocssearchtool",
+ "en/tools/search-research/youtubechannelsearchtool",
+ "en/tools/search-research/youtubevideosearchtool",
+ "en/tools/search-research/tavilysearchtool",
+ "en/tools/search-research/tavilyextractortool",
+ "en/tools/search-research/arxivpapertool",
+ "en/tools/search-research/serpapi-googlesearchtool",
+ "en/tools/search-research/serpapi-googleshoppingtool",
+ "en/tools/search-research/databricks-query-tool"
+ ]
+ },
+ {
+ "group": "Database & Data",
+ "icon": "database",
+ "pages": [
+ "en/tools/database-data/overview",
+ "en/tools/database-data/mysqltool",
+ "en/tools/database-data/pgsearchtool",
+ "en/tools/database-data/snowflakesearchtool",
+ "en/tools/database-data/nl2sqltool",
+ "en/tools/database-data/qdrantvectorsearchtool",
+ "en/tools/database-data/weaviatevectorsearchtool",
+ "en/tools/database-data/mongodbvectorsearchtool",
+ "en/tools/database-data/singlestoresearchtool"
+ ]
+ },
+ {
+ "group": "AI & Machine Learning",
+ "icon": "brain",
+ "pages": [
+ "en/tools/ai-ml/overview",
+ "en/tools/ai-ml/dalletool",
+ "en/tools/ai-ml/visiontool",
+ "en/tools/ai-ml/aimindtool",
+ "en/tools/ai-ml/llamaindextool",
+ "en/tools/ai-ml/langchaintool",
+ "en/tools/ai-ml/ragtool",
+ "en/tools/ai-ml/codeinterpretertool"
+ ]
+ },
+ {
+ "group": "Cloud & Storage",
+ "icon": "cloud",
+ "pages": [
+ "en/tools/cloud-storage/overview",
+ "en/tools/cloud-storage/s3readertool",
+ "en/tools/cloud-storage/s3writertool",
+ "en/tools/cloud-storage/bedrockkbretriever"
+ ]
+ },
+ {
+ "group": "Integrations",
+ "icon": "plug",
+ "pages": [
+ "en/tools/integration/overview",
+ "en/tools/integration/bedrockinvokeagenttool",
+ "en/tools/integration/crewaiautomationtool",
+ "en/tools/integration/mergeagenthandlertool"
+ ]
+ },
+ {
+ "group": "Automation",
+ "icon": "bolt",
+ "pages": [
+ "en/tools/automation/overview",
+ "en/tools/automation/apifyactorstool",
+ "en/tools/automation/composiotool",
+ "en/tools/automation/multiontool",
+ "en/tools/automation/zapieractionstool"
+ ]
+ }
+ ]
+ },
+ {
+ "group": "Observability",
+ "pages": [
+ "en/observability/tracing",
+ "en/observability/overview",
+ "en/observability/arize-phoenix",
+ "en/observability/braintrust",
+ "en/observability/datadog",
+ "en/observability/galileo",
+ "en/observability/langdb",
+ "en/observability/langfuse",
+ "en/observability/langtrace",
+ "en/observability/maxim",
+ "en/observability/mlflow",
+ "en/observability/neatlogs",
+ "en/observability/openlit",
+ "en/observability/opik",
+ "en/observability/patronus-evaluation",
+ "en/observability/portkey",
+ "en/observability/weave",
+ "en/observability/truefoundry"
+ ]
+ },
+ {
+ "group": "Learn",
+ "pages": [
+ "en/learn/overview",
+ "en/learn/llm-selection-guide",
+ "en/learn/conditional-tasks",
+ "en/learn/coding-agents",
+ "en/learn/create-custom-tools",
+ "en/learn/custom-llm",
+ "en/learn/custom-manager-agent",
+ "en/learn/customizing-agents",
+ "en/learn/dalle-image-generation",
+ "en/learn/force-tool-output-as-result",
+ "en/learn/hierarchical-process",
+ "en/learn/human-input-on-execution",
+ "en/learn/human-in-the-loop",
+ "en/learn/human-feedback-in-flows",
+ "en/learn/kickoff-async",
+ "en/learn/kickoff-for-each",
+ "en/learn/llm-connections",
+ "en/learn/litellm-removal-guide",
+ "en/learn/multimodal-agents",
+ "en/learn/replay-tasks-from-latest-crew-kickoff",
+ "en/learn/sequential-process",
+ "en/learn/using-annotations",
+ "en/learn/execution-hooks",
+ "en/learn/llm-hooks",
+ "en/learn/tool-hooks"
+ ]
+ },
+ {
+ "group": "Telemetry",
+ "pages": [
+ "en/telemetry"
+ ]
+ }
+ ]
+ },
+ {
+ "tab": "AMP",
+ "icon": "briefcase",
+ "groups": [
+ {
+ "group": "Getting Started",
+ "pages": [
+ "en/enterprise/introduction"
+ ]
+ },
+ {
+ "group": "Build",
+ "pages": [
+ "en/enterprise/features/automations",
+ "en/enterprise/features/crew-studio",
+ "en/enterprise/features/marketplace",
+ "en/enterprise/features/agent-repositories",
+ "en/enterprise/features/tools-and-integrations",
+ "en/enterprise/features/pii-trace-redactions",
+ "en/enterprise/features/a2a"
+ ]
+ },
+ {
+ "group": "Operate",
+ "pages": [
+ "en/enterprise/features/traces",
+ "en/enterprise/features/webhook-streaming",
+ "en/enterprise/features/hallucination-guardrail",
+ "en/enterprise/features/flow-hitl-management"
+ ]
+ },
+ {
+ "group": "Manage",
+ "pages": [
+ "en/enterprise/features/sso",
+ "en/enterprise/features/rbac"
+ ]
+ },
+ {
+ "group": "Integration Docs",
+ "pages": [
+ "en/enterprise/integrations/asana",
+ "en/enterprise/integrations/box",
+ "en/enterprise/integrations/clickup",
+ "en/enterprise/integrations/github",
+ "en/enterprise/integrations/gmail",
+ "en/enterprise/integrations/google_calendar",
+ "en/enterprise/integrations/google_contacts",
+ "en/enterprise/integrations/google_docs",
+ "en/enterprise/integrations/google_drive",
+ "en/enterprise/integrations/google_sheets",
+ "en/enterprise/integrations/google_slides",
+ "en/enterprise/integrations/hubspot",
+ "en/enterprise/integrations/jira",
+ "en/enterprise/integrations/linear",
+ "en/enterprise/integrations/microsoft_excel",
+ "en/enterprise/integrations/microsoft_onedrive",
+ "en/enterprise/integrations/microsoft_outlook",
+ "en/enterprise/integrations/microsoft_sharepoint",
+ "en/enterprise/integrations/microsoft_teams",
+ "en/enterprise/integrations/microsoft_word",
+ "en/enterprise/integrations/notion",
+ "en/enterprise/integrations/salesforce",
+ "en/enterprise/integrations/shopify",
+ "en/enterprise/integrations/slack",
+ "en/enterprise/integrations/stripe",
+ "en/enterprise/integrations/zendesk"
+ ]
+ },
+ {
+ "group": "Triggers",
+ "pages": [
+ "en/enterprise/guides/automation-triggers",
+ "en/enterprise/guides/gmail-trigger",
+ "en/enterprise/guides/google-calendar-trigger",
+ "en/enterprise/guides/google-drive-trigger",
+ "en/enterprise/guides/outlook-trigger",
+ "en/enterprise/guides/onedrive-trigger",
+ "en/enterprise/guides/microsoft-teams-trigger",
+ "en/enterprise/guides/slack-trigger",
+ "en/enterprise/guides/hubspot-trigger",
+ "en/enterprise/guides/salesforce-trigger",
+ "en/enterprise/guides/zapier-trigger"
+ ]
+ },
+ {
+ "group": "How-To Guides",
+ "pages": [
+ "en/enterprise/guides/build-crew",
+ "en/enterprise/guides/prepare-for-deployment",
+ "en/enterprise/guides/deploy-to-amp",
+ "en/enterprise/guides/private-package-registry",
+ "en/enterprise/guides/kickoff-crew",
+ "en/enterprise/guides/update-crew",
+ "en/enterprise/guides/enable-crew-studio",
+ "en/enterprise/guides/capture_telemetry_logs",
+ "en/enterprise/guides/azure-openai-setup",
+ "en/enterprise/guides/tool-repository",
+ "en/enterprise/guides/custom-mcp-server",
+ "en/enterprise/guides/react-component-export",
+ "en/enterprise/guides/team-management",
+ "en/enterprise/guides/human-in-the-loop",
+ "en/enterprise/guides/webhook-automation"
+ ]
+ },
+ {
+ "group": "Resources",
+ "pages": [
+ "en/enterprise/resources/frequently-asked-questions"
+ ]
+ }
+ ]
+ },
+ {
+ "tab": "API Reference",
+ "icon": "magnifying-glass",
+ "groups": [
+ {
+ "group": "Getting Started",
+ "pages": [
+ "en/api-reference/introduction",
+ "en/api-reference/inputs",
+ "en/api-reference/kickoff",
+ "en/api-reference/resume",
+ "en/api-reference/status"
+ ]
+ }
+ ]
+ },
+ {
+ "tab": "Examples",
+ "icon": "code",
+ "groups": [
+ {
+ "group": "Examples",
+ "pages": [
+ "en/examples/example",
+ "en/examples/cookbooks"
+ ]
+ }
+ ]
+ },
+ {
+ "tab": "Changelog",
+ "icon": "clock",
+ "groups": [
+ {
+ "group": "Release Notes",
+ "pages": [
+ "en/changelog"
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "version": "v1.14.1",
+ "tabs": [
+ {
+ "tab": "Home",
+ "icon": "house",
+ "groups": [
+ {
+ "group": "Welcome",
+ "pages": [
+ "index"
+ ]
+ }
+ ]
+ },
+ {
+ "tab": "Documentation",
+ "icon": "book-open",
+ "groups": [
+ {
+ "group": "Get Started",
+ "pages": [
+ "en/introduction",
+ "en/guides/coding-tools/build-with-ai",
+ "en/skills",
+ "en/installation",
+ "en/quickstart"
+ ]
+ },
+ {
+ "group": "Guides",
+ "pages": [
+ {
+ "group": "Strategy",
+ "icon": "compass",
+ "pages": [
+ "en/guides/concepts/evaluating-use-cases"
+ ]
+ },
+ {
+ "group": "Agents",
+ "icon": "user",
+ "pages": [
+ "en/guides/agents/crafting-effective-agents"
+ ]
+ },
+ {
+ "group": "Crews",
+ "icon": "users",
+ "pages": [
+ "en/guides/crews/first-crew"
+ ]
+ },
+ {
+ "group": "Flows",
+ "icon": "code-branch",
+ "pages": [
+ "en/guides/flows/first-flow",
+ "en/guides/flows/mastering-flow-state"
+ ]
+ },
+ {
+ "group": "Tools",
+ "icon": "wrench",
+ "pages": [
+ "en/guides/tools/publish-custom-tools"
+ ]
+ },
+ {
+ "group": "Coding Tools",
+ "icon": "terminal",
+ "pages": [
+ "en/guides/coding-tools/agents-md",
+ "en/guides/coding-tools/build-with-ai"
]
},
{
@@ -553,6 +1031,7 @@
"group": "Get Started",
"pages": [
"en/introduction",
+ "en/guides/coding-tools/build-with-ai",
"en/skills",
"en/installation",
"en/quickstart"
@@ -601,7 +1080,8 @@
"group": "Coding Tools",
"icon": "terminal",
"pages": [
- "en/guides/coding-tools/agents-md"
+ "en/guides/coding-tools/agents-md",
+ "en/guides/coding-tools/build-with-ai"
]
},
{
@@ -1027,6 +1507,7 @@
"group": "Get Started",
"pages": [
"en/introduction",
+ "en/guides/coding-tools/build-with-ai",
"en/skills",
"en/installation",
"en/quickstart"
@@ -1075,7 +1556,8 @@
"group": "Coding Tools",
"icon": "terminal",
"pages": [
- "en/guides/coding-tools/agents-md"
+ "en/guides/coding-tools/agents-md",
+ "en/guides/coding-tools/build-with-ai"
]
},
{
@@ -1501,6 +1983,7 @@
"group": "Get Started",
"pages": [
"en/introduction",
+ "en/guides/coding-tools/build-with-ai",
"en/skills",
"en/installation",
"en/quickstart"
@@ -1549,7 +2032,8 @@
"group": "Coding Tools",
"icon": "terminal",
"pages": [
- "en/guides/coding-tools/agents-md"
+ "en/guides/coding-tools/agents-md",
+ "en/guides/coding-tools/build-with-ai"
]
},
{
@@ -1975,6 +2459,7 @@
"group": "Get Started",
"pages": [
"en/introduction",
+ "en/guides/coding-tools/build-with-ai",
"en/skills",
"en/installation",
"en/quickstart"
@@ -2023,7 +2508,8 @@
"group": "Coding Tools",
"icon": "terminal",
"pages": [
- "en/guides/coding-tools/agents-md"
+ "en/guides/coding-tools/agents-md",
+ "en/guides/coding-tools/build-with-ai"
]
},
{
@@ -2447,6 +2933,7 @@
"group": "Get Started",
"pages": [
"en/introduction",
+ "en/guides/coding-tools/build-with-ai",
"en/skills",
"en/installation",
"en/quickstart"
@@ -2495,7 +2982,8 @@
"group": "Coding Tools",
"icon": "terminal",
"pages": [
- "en/guides/coding-tools/agents-md"
+ "en/guides/coding-tools/agents-md",
+ "en/guides/coding-tools/build-with-ai"
]
},
{
@@ -2919,6 +3407,7 @@
"group": "Get Started",
"pages": [
"en/introduction",
+ "en/guides/coding-tools/build-with-ai",
"en/skills",
"en/installation",
"en/quickstart"
@@ -2967,7 +3456,8 @@
"group": "Coding Tools",
"icon": "terminal",
"pages": [
- "en/guides/coding-tools/agents-md"
+ "en/guides/coding-tools/agents-md",
+ "en/guides/coding-tools/build-with-ai"
]
},
{
@@ -3392,6 +3882,7 @@
"group": "Get Started",
"pages": [
"en/introduction",
+ "en/guides/coding-tools/build-with-ai",
"en/skills",
"en/installation",
"en/quickstart"
@@ -3440,7 +3931,8 @@
"group": "Coding Tools",
"icon": "terminal",
"pages": [
- "en/guides/coding-tools/agents-md"
+ "en/guides/coding-tools/agents-md",
+ "en/guides/coding-tools/build-with-ai"
]
},
{
@@ -3866,6 +4358,7 @@
"group": "Get Started",
"pages": [
"en/introduction",
+ "en/guides/coding-tools/build-with-ai",
"en/skills",
"en/installation",
"en/quickstart"
@@ -3914,7 +4407,8 @@
"group": "Coding Tools",
"icon": "terminal",
"pages": [
- "en/guides/coding-tools/agents-md"
+ "en/guides/coding-tools/agents-md",
+ "en/guides/coding-tools/build-with-ai"
]
},
{
@@ -4338,6 +4832,7 @@
"group": "Get Started",
"pages": [
"en/introduction",
+ "en/guides/coding-tools/build-with-ai",
"en/skills",
"en/installation",
"en/quickstart"
@@ -4386,7 +4881,8 @@
"group": "Coding Tools",
"icon": "terminal",
"pages": [
- "en/guides/coding-tools/agents-md"
+ "en/guides/coding-tools/agents-md",
+ "en/guides/coding-tools/build-with-ai"
]
},
{
@@ -4820,7 +5316,7 @@
},
"versions": [
{
- "version": "v1.14.1",
+ "version": "v1.14.2",
"default": true,
"tabs": [
{
@@ -4843,6 +5339,466 @@
"group": "Começando",
"pages": [
"pt-BR/introduction",
+ "pt-BR/guides/coding-tools/build-with-ai",
+ "pt-BR/skills",
+ "pt-BR/installation",
+ "pt-BR/quickstart"
+ ]
+ },
+ {
+ "group": "Guias",
+ "pages": [
+ {
+ "group": "Estratégia",
+ "icon": "compass",
+ "pages": [
+ "pt-BR/guides/concepts/evaluating-use-cases"
+ ]
+ },
+ {
+ "group": "Agentes",
+ "icon": "user",
+ "pages": [
+ "pt-BR/guides/agents/crafting-effective-agents"
+ ]
+ },
+ {
+ "group": "Crews",
+ "icon": "users",
+ "pages": [
+ "pt-BR/guides/crews/first-crew"
+ ]
+ },
+ {
+ "group": "Flows",
+ "icon": "code-branch",
+ "pages": [
+ "pt-BR/guides/flows/first-flow",
+ "pt-BR/guides/flows/mastering-flow-state"
+ ]
+ },
+ {
+ "group": "Ferramentas",
+ "icon": "wrench",
+ "pages": [
+ "pt-BR/guides/tools/publish-custom-tools"
+ ]
+ },
+ {
+ "group": "Ferramentas de Codificação",
+ "icon": "terminal",
+ "pages": [
+ "pt-BR/guides/coding-tools/agents-md"
+ ]
+ },
+ {
+ "group": "Avançado",
+ "icon": "gear",
+ "pages": [
+ "pt-BR/guides/advanced/customizing-prompts",
+ "pt-BR/guides/advanced/fingerprinting"
+ ]
+ },
+ {
+ "group": "Migração",
+ "icon": "shuffle",
+ "pages": [
+ "pt-BR/guides/migration/migrating-from-langgraph"
+ ]
+ }
+ ]
+ },
+ {
+ "group": "Conceitos-Chave",
+ "pages": [
+ "pt-BR/concepts/agents",
+ "pt-BR/concepts/agent-capabilities",
+ "pt-BR/concepts/tasks",
+ "pt-BR/concepts/crews",
+ "pt-BR/concepts/flows",
+ "pt-BR/concepts/production-architecture",
+ "pt-BR/concepts/knowledge",
+ "pt-BR/concepts/skills",
+ "pt-BR/concepts/llms",
+ "pt-BR/concepts/files",
+ "pt-BR/concepts/processes",
+ "pt-BR/concepts/collaboration",
+ "pt-BR/concepts/training",
+ "pt-BR/concepts/memory",
+ "pt-BR/concepts/reasoning",
+ "pt-BR/concepts/planning",
+ "pt-BR/concepts/testing",
+ "pt-BR/concepts/cli",
+ "pt-BR/concepts/tools",
+ "pt-BR/concepts/event-listener",
+ "pt-BR/concepts/checkpointing"
+ ]
+ },
+ {
+ "group": "Integração MCP",
+ "pages": [
+ "pt-BR/mcp/overview",
+ "pt-BR/mcp/dsl-integration",
+ "pt-BR/mcp/stdio",
+ "pt-BR/mcp/sse",
+ "pt-BR/mcp/streamable-http",
+ "pt-BR/mcp/multiple-servers",
+ "pt-BR/mcp/security"
+ ]
+ },
+ {
+ "group": "Ferramentas",
+ "pages": [
+ "pt-BR/tools/overview",
+ {
+ "group": "Arquivo & Documento",
+ "icon": "folder-open",
+ "pages": [
+ "pt-BR/tools/file-document/overview",
+ "pt-BR/tools/file-document/filereadtool",
+ "pt-BR/tools/file-document/filewritetool",
+ "pt-BR/tools/file-document/pdfsearchtool",
+ "pt-BR/tools/file-document/docxsearchtool",
+ "pt-BR/tools/file-document/mdxsearchtool",
+ "pt-BR/tools/file-document/xmlsearchtool",
+ "pt-BR/tools/file-document/txtsearchtool",
+ "pt-BR/tools/file-document/jsonsearchtool",
+ "pt-BR/tools/file-document/csvsearchtool",
+ "pt-BR/tools/file-document/directorysearchtool",
+ "pt-BR/tools/file-document/directoryreadtool"
+ ]
+ },
+ {
+ "group": "Web Scraping & Navegação",
+ "icon": "globe",
+ "pages": [
+ "pt-BR/tools/web-scraping/overview",
+ "pt-BR/tools/web-scraping/scrapewebsitetool",
+ "pt-BR/tools/web-scraping/scrapeelementfromwebsitetool",
+ "pt-BR/tools/web-scraping/scrapflyscrapetool",
+ "pt-BR/tools/web-scraping/seleniumscrapingtool",
+ "pt-BR/tools/web-scraping/scrapegraphscrapetool",
+ "pt-BR/tools/web-scraping/spidertool",
+ "pt-BR/tools/web-scraping/browserbaseloadtool",
+ "pt-BR/tools/web-scraping/hyperbrowserloadtool",
+ "pt-BR/tools/web-scraping/stagehandtool",
+ "pt-BR/tools/web-scraping/firecrawlcrawlwebsitetool",
+ "pt-BR/tools/web-scraping/firecrawlscrapewebsitetool",
+ "pt-BR/tools/web-scraping/oxylabsscraperstool"
+ ]
+ },
+ {
+ "group": "Pesquisa",
+ "icon": "magnifying-glass",
+ "pages": [
+ "pt-BR/tools/search-research/overview",
+ "pt-BR/tools/search-research/serperdevtool",
+ "pt-BR/tools/search-research/bravesearchtool",
+ "pt-BR/tools/search-research/exasearchtool",
+ "pt-BR/tools/search-research/linkupsearchtool",
+ "pt-BR/tools/search-research/githubsearchtool",
+ "pt-BR/tools/search-research/websitesearchtool",
+ "pt-BR/tools/search-research/codedocssearchtool",
+ "pt-BR/tools/search-research/youtubechannelsearchtool",
+ "pt-BR/tools/search-research/youtubevideosearchtool"
+ ]
+ },
+ {
+ "group": "Dados",
+ "icon": "database",
+ "pages": [
+ "pt-BR/tools/database-data/overview",
+ "pt-BR/tools/database-data/mysqltool",
+ "pt-BR/tools/database-data/pgsearchtool",
+ "pt-BR/tools/database-data/snowflakesearchtool",
+ "pt-BR/tools/database-data/nl2sqltool",
+ "pt-BR/tools/database-data/qdrantvectorsearchtool",
+ "pt-BR/tools/database-data/weaviatevectorsearchtool"
+ ]
+ },
+ {
+ "group": "IA & Machine Learning",
+ "icon": "brain",
+ "pages": [
+ "pt-BR/tools/ai-ml/overview",
+ "pt-BR/tools/ai-ml/dalletool",
+ "pt-BR/tools/ai-ml/visiontool",
+ "pt-BR/tools/ai-ml/aimindtool",
+ "pt-BR/tools/ai-ml/llamaindextool",
+ "pt-BR/tools/ai-ml/langchaintool",
+ "pt-BR/tools/ai-ml/ragtool",
+ "pt-BR/tools/ai-ml/codeinterpretertool"
+ ]
+ },
+ {
+ "group": "Cloud & Armazenamento",
+ "icon": "cloud",
+ "pages": [
+ "pt-BR/tools/cloud-storage/overview",
+ "pt-BR/tools/cloud-storage/s3readertool",
+ "pt-BR/tools/cloud-storage/s3writertool",
+ "pt-BR/tools/cloud-storage/bedrockkbretriever"
+ ]
+ },
+ {
+ "group": "Integrations",
+ "icon": "plug",
+ "pages": [
+ "pt-BR/tools/integration/overview",
+ "pt-BR/tools/integration/bedrockinvokeagenttool",
+ "pt-BR/tools/integration/crewaiautomationtool"
+ ]
+ },
+ {
+ "group": "Automação",
+ "icon": "bolt",
+ "pages": [
+ "pt-BR/tools/automation/overview",
+ "pt-BR/tools/automation/apifyactorstool",
+ "pt-BR/tools/automation/composiotool",
+ "pt-BR/tools/automation/multiontool"
+ ]
+ }
+ ]
+ },
+ {
+ "group": "Observabilidade",
+ "pages": [
+ "pt-BR/observability/tracing",
+ "pt-BR/observability/overview",
+ "pt-BR/observability/arize-phoenix",
+ "pt-BR/observability/braintrust",
+ "pt-BR/observability/datadog",
+ "pt-BR/observability/galileo",
+ "pt-BR/observability/langdb",
+ "pt-BR/observability/langfuse",
+ "pt-BR/observability/langtrace",
+ "pt-BR/observability/maxim",
+ "pt-BR/observability/mlflow",
+ "pt-BR/observability/openlit",
+ "pt-BR/observability/opik",
+ "pt-BR/observability/patronus-evaluation",
+ "pt-BR/observability/portkey",
+ "pt-BR/observability/weave",
+ "pt-BR/observability/truefoundry"
+ ]
+ },
+ {
+ "group": "Aprenda",
+ "pages": [
+ "pt-BR/learn/overview",
+ "pt-BR/learn/llm-selection-guide",
+ "pt-BR/learn/conditional-tasks",
+ "pt-BR/learn/coding-agents",
+ "pt-BR/learn/create-custom-tools",
+ "pt-BR/learn/custom-llm",
+ "pt-BR/learn/custom-manager-agent",
+ "pt-BR/learn/customizing-agents",
+ "pt-BR/learn/dalle-image-generation",
+ "pt-BR/learn/force-tool-output-as-result",
+ "pt-BR/learn/hierarchical-process",
+ "pt-BR/learn/human-input-on-execution",
+ "pt-BR/learn/human-in-the-loop",
+ "pt-BR/learn/human-feedback-in-flows",
+ "pt-BR/learn/kickoff-async",
+ "pt-BR/learn/kickoff-for-each",
+ "pt-BR/learn/llm-connections",
+ "pt-BR/learn/multimodal-agents",
+ "pt-BR/learn/replay-tasks-from-latest-crew-kickoff",
+ "pt-BR/learn/sequential-process",
+ "pt-BR/learn/using-annotations",
+ "pt-BR/learn/execution-hooks",
+ "pt-BR/learn/llm-hooks",
+ "pt-BR/learn/tool-hooks"
+ ]
+ },
+ {
+ "group": "Telemetria",
+ "pages": [
+ "pt-BR/telemetry"
+ ]
+ }
+ ]
+ },
+ {
+ "tab": "AMP",
+ "icon": "briefcase",
+ "groups": [
+ {
+ "group": "Começando",
+ "pages": [
+ "pt-BR/enterprise/introduction"
+ ]
+ },
+ {
+ "group": "Construir",
+ "pages": [
+ "pt-BR/enterprise/features/automations",
+ "pt-BR/enterprise/features/crew-studio",
+ "pt-BR/enterprise/features/marketplace",
+ "pt-BR/enterprise/features/agent-repositories",
+ "pt-BR/enterprise/features/tools-and-integrations",
+ "pt-BR/enterprise/features/pii-trace-redactions"
+ ]
+ },
+ {
+ "group": "Operar",
+ "pages": [
+ "pt-BR/enterprise/features/traces",
+ "pt-BR/enterprise/features/webhook-streaming",
+ "pt-BR/enterprise/features/hallucination-guardrail",
+ "pt-BR/enterprise/features/flow-hitl-management"
+ ]
+ },
+ {
+ "group": "Gerenciar",
+ "pages": [
+ "pt-BR/enterprise/features/rbac"
+ ]
+ },
+ {
+ "group": "Documentação de Integração",
+ "pages": [
+ "pt-BR/enterprise/integrations/asana",
+ "pt-BR/enterprise/integrations/box",
+ "pt-BR/enterprise/integrations/clickup",
+ "pt-BR/enterprise/integrations/github",
+ "pt-BR/enterprise/integrations/gmail",
+ "pt-BR/enterprise/integrations/google_calendar",
+ "pt-BR/enterprise/integrations/google_contacts",
+ "pt-BR/enterprise/integrations/google_docs",
+ "pt-BR/enterprise/integrations/google_drive",
+ "pt-BR/enterprise/integrations/google_sheets",
+ "pt-BR/enterprise/integrations/google_slides",
+ "pt-BR/enterprise/integrations/hubspot",
+ "pt-BR/enterprise/integrations/jira",
+ "pt-BR/enterprise/integrations/linear",
+ "pt-BR/enterprise/integrations/microsoft_excel",
+ "pt-BR/enterprise/integrations/microsoft_onedrive",
+ "pt-BR/enterprise/integrations/microsoft_outlook",
+ "pt-BR/enterprise/integrations/microsoft_sharepoint",
+ "pt-BR/enterprise/integrations/microsoft_teams",
+ "pt-BR/enterprise/integrations/microsoft_word",
+ "pt-BR/enterprise/integrations/notion",
+ "pt-BR/enterprise/integrations/salesforce",
+ "pt-BR/enterprise/integrations/shopify",
+ "pt-BR/enterprise/integrations/slack",
+ "pt-BR/enterprise/integrations/stripe",
+ "pt-BR/enterprise/integrations/zendesk"
+ ]
+ },
+ {
+ "group": "Guias",
+ "pages": [
+ "pt-BR/enterprise/guides/build-crew",
+ "pt-BR/enterprise/guides/prepare-for-deployment",
+ "pt-BR/enterprise/guides/deploy-to-amp",
+ "pt-BR/enterprise/guides/private-package-registry",
+ "pt-BR/enterprise/guides/kickoff-crew",
+ "pt-BR/enterprise/guides/training-crews",
+ "pt-BR/enterprise/guides/update-crew",
+ "pt-BR/enterprise/guides/enable-crew-studio",
+ "pt-BR/enterprise/guides/capture_telemetry_logs",
+ "pt-BR/enterprise/guides/azure-openai-setup",
+ "pt-BR/enterprise/guides/tool-repository",
+ "pt-BR/enterprise/guides/custom-mcp-server",
+ "pt-BR/enterprise/guides/react-component-export",
+ "pt-BR/enterprise/guides/team-management",
+ "pt-BR/enterprise/guides/human-in-the-loop",
+ "pt-BR/enterprise/guides/webhook-automation"
+ ]
+ },
+ {
+ "group": "Triggers",
+ "pages": [
+ "pt-BR/enterprise/guides/automation-triggers",
+ "pt-BR/enterprise/guides/gmail-trigger",
+ "pt-BR/enterprise/guides/google-calendar-trigger",
+ "pt-BR/enterprise/guides/google-drive-trigger",
+ "pt-BR/enterprise/guides/outlook-trigger",
+ "pt-BR/enterprise/guides/onedrive-trigger",
+ "pt-BR/enterprise/guides/microsoft-teams-trigger",
+ "pt-BR/enterprise/guides/slack-trigger",
+ "pt-BR/enterprise/guides/hubspot-trigger",
+ "pt-BR/enterprise/guides/salesforce-trigger",
+ "pt-BR/enterprise/guides/zapier-trigger"
+ ]
+ },
+ {
+ "group": "Recursos",
+ "pages": [
+ "pt-BR/enterprise/resources/frequently-asked-questions"
+ ]
+ }
+ ]
+ },
+ {
+ "tab": "Referência da API",
+ "icon": "magnifying-glass",
+ "groups": [
+ {
+ "group": "Começando",
+ "pages": [
+ "pt-BR/api-reference/introduction",
+ "pt-BR/api-reference/inputs",
+ "pt-BR/api-reference/kickoff",
+ "pt-BR/api-reference/resume",
+ "pt-BR/api-reference/status"
+ ]
+ }
+ ]
+ },
+ {
+ "tab": "Exemplos",
+ "icon": "code",
+ "groups": [
+ {
+ "group": "Exemplos",
+ "pages": [
+ "pt-BR/examples/example",
+ "pt-BR/examples/cookbooks"
+ ]
+ }
+ ]
+ },
+ {
+ "tab": "Notas de Versão",
+ "icon": "clock",
+ "groups": [
+ {
+ "group": "Notas de Versão",
+ "pages": [
+ "pt-BR/changelog"
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "version": "v1.14.1",
+ "tabs": [
+ {
+ "tab": "Início",
+ "icon": "house",
+ "groups": [
+ {
+ "group": "Bem-vindo",
+ "pages": [
+ "pt-BR/index"
+ ]
+ }
+ ]
+ },
+ {
+ "tab": "Documentação",
+ "icon": "book-open",
+ "groups": [
+ {
+ "group": "Começando",
+ "pages": [
+ "pt-BR/introduction",
+ "pt-BR/guides/coding-tools/build-with-ai",
"pt-BR/skills",
"pt-BR/installation",
"pt-BR/quickstart"
@@ -5301,6 +6257,7 @@
"group": "Começando",
"pages": [
"pt-BR/introduction",
+ "pt-BR/guides/coding-tools/build-with-ai",
"pt-BR/skills",
"pt-BR/installation",
"pt-BR/quickstart"
@@ -5759,6 +6716,7 @@
"group": "Começando",
"pages": [
"pt-BR/introduction",
+ "pt-BR/guides/coding-tools/build-with-ai",
"pt-BR/skills",
"pt-BR/installation",
"pt-BR/quickstart"
@@ -6217,6 +7175,7 @@
"group": "Começando",
"pages": [
"pt-BR/introduction",
+ "pt-BR/guides/coding-tools/build-with-ai",
"pt-BR/skills",
"pt-BR/installation",
"pt-BR/quickstart"
@@ -6675,6 +7634,7 @@
"group": "Começando",
"pages": [
"pt-BR/introduction",
+ "pt-BR/guides/coding-tools/build-with-ai",
"pt-BR/skills",
"pt-BR/installation",
"pt-BR/quickstart"
@@ -7132,6 +8092,7 @@
"group": "Começando",
"pages": [
"pt-BR/introduction",
+ "pt-BR/guides/coding-tools/build-with-ai",
"pt-BR/skills",
"pt-BR/installation",
"pt-BR/quickstart"
@@ -7589,6 +8550,7 @@
"group": "Começando",
"pages": [
"pt-BR/introduction",
+ "pt-BR/guides/coding-tools/build-with-ai",
"pt-BR/skills",
"pt-BR/installation",
"pt-BR/quickstart"
@@ -8046,6 +9008,7 @@
"group": "Começando",
"pages": [
"pt-BR/introduction",
+ "pt-BR/guides/coding-tools/build-with-ai",
"pt-BR/skills",
"pt-BR/installation",
"pt-BR/quickstart"
@@ -8502,6 +9465,7 @@
"group": "Começando",
"pages": [
"pt-BR/introduction",
+ "pt-BR/guides/coding-tools/build-with-ai",
"pt-BR/skills",
"pt-BR/installation",
"pt-BR/quickstart"
@@ -8958,6 +9922,7 @@
"group": "Começando",
"pages": [
"pt-BR/introduction",
+ "pt-BR/guides/coding-tools/build-with-ai",
"pt-BR/skills",
"pt-BR/installation",
"pt-BR/quickstart"
@@ -9422,7 +10387,7 @@
},
"versions": [
{
- "version": "v1.14.1",
+ "version": "v1.14.2",
"default": true,
"tabs": [
{
@@ -9445,6 +10410,478 @@
"group": "시작 안내",
"pages": [
"ko/introduction",
+ "ko/guides/coding-tools/build-with-ai",
+ "ko/skills",
+ "ko/installation",
+ "ko/quickstart"
+ ]
+ },
+ {
+ "group": "가이드",
+ "pages": [
+ {
+ "group": "전략",
+ "icon": "compass",
+ "pages": [
+ "ko/guides/concepts/evaluating-use-cases"
+ ]
+ },
+ {
+ "group": "에이전트 (Agents)",
+ "icon": "user",
+ "pages": [
+ "ko/guides/agents/crafting-effective-agents"
+ ]
+ },
+ {
+ "group": "크루 (Crews)",
+ "icon": "users",
+ "pages": [
+ "ko/guides/crews/first-crew"
+ ]
+ },
+ {
+ "group": "플로우 (Flows)",
+ "icon": "code-branch",
+ "pages": [
+ "ko/guides/flows/first-flow",
+ "ko/guides/flows/mastering-flow-state"
+ ]
+ },
+ {
+ "group": "도구",
+ "icon": "wrench",
+ "pages": [
+ "ko/guides/tools/publish-custom-tools"
+ ]
+ },
+ {
+ "group": "코딩 도구",
+ "icon": "terminal",
+ "pages": [
+ "ko/guides/coding-tools/agents-md"
+ ]
+ },
+ {
+ "group": "고급",
+ "icon": "gear",
+ "pages": [
+ "ko/guides/advanced/customizing-prompts",
+ "ko/guides/advanced/fingerprinting"
+ ]
+ },
+ {
+ "group": "마이그레이션",
+ "icon": "shuffle",
+ "pages": [
+ "ko/guides/migration/migrating-from-langgraph"
+ ]
+ }
+ ]
+ },
+ {
+ "group": "핵심 개념",
+ "pages": [
+ "ko/concepts/agents",
+ "ko/concepts/tasks",
+ "ko/concepts/agent-capabilities",
+ "ko/concepts/crews",
+ "ko/concepts/flows",
+ "ko/concepts/production-architecture",
+ "ko/concepts/knowledge",
+ "ko/concepts/skills",
+ "ko/concepts/llms",
+ "ko/concepts/files",
+ "ko/concepts/processes",
+ "ko/concepts/collaboration",
+ "ko/concepts/training",
+ "ko/concepts/memory",
+ "ko/concepts/reasoning",
+ "ko/concepts/planning",
+ "ko/concepts/testing",
+ "ko/concepts/cli",
+ "ko/concepts/tools",
+ "ko/concepts/event-listener",
+ "ko/concepts/checkpointing"
+ ]
+ },
+ {
+ "group": "MCP 통합",
+ "pages": [
+ "ko/mcp/overview",
+ "ko/mcp/dsl-integration",
+ "ko/mcp/stdio",
+ "ko/mcp/sse",
+ "ko/mcp/streamable-http",
+ "ko/mcp/multiple-servers",
+ "ko/mcp/security"
+ ]
+ },
+ {
+ "group": "도구 (Tools)",
+ "pages": [
+ "ko/tools/overview",
+ {
+ "group": "파일 & 문서",
+ "icon": "folder-open",
+ "pages": [
+ "ko/tools/file-document/overview",
+ "ko/tools/file-document/filereadtool",
+ "ko/tools/file-document/filewritetool",
+ "ko/tools/file-document/pdfsearchtool",
+ "ko/tools/file-document/docxsearchtool",
+ "ko/tools/file-document/mdxsearchtool",
+ "ko/tools/file-document/xmlsearchtool",
+ "ko/tools/file-document/txtsearchtool",
+ "ko/tools/file-document/jsonsearchtool",
+ "ko/tools/file-document/csvsearchtool",
+ "ko/tools/file-document/directorysearchtool",
+ "ko/tools/file-document/directoryreadtool",
+ "ko/tools/file-document/ocrtool",
+ "ko/tools/file-document/pdf-text-writing-tool"
+ ]
+ },
+ {
+ "group": "웹 스크래핑 & 브라우징",
+ "icon": "globe",
+ "pages": [
+ "ko/tools/web-scraping/overview",
+ "ko/tools/web-scraping/scrapewebsitetool",
+ "ko/tools/web-scraping/scrapeelementfromwebsitetool",
+ "ko/tools/web-scraping/scrapflyscrapetool",
+ "ko/tools/web-scraping/seleniumscrapingtool",
+ "ko/tools/web-scraping/scrapegraphscrapetool",
+ "ko/tools/web-scraping/spidertool",
+ "ko/tools/web-scraping/browserbaseloadtool",
+ "ko/tools/web-scraping/hyperbrowserloadtool",
+ "ko/tools/web-scraping/stagehandtool",
+ "ko/tools/web-scraping/firecrawlcrawlwebsitetool",
+ "ko/tools/web-scraping/firecrawlscrapewebsitetool",
+ "ko/tools/web-scraping/oxylabsscraperstool",
+ "ko/tools/web-scraping/brightdata-tools"
+ ]
+ },
+ {
+ "group": "검색 및 연구",
+ "icon": "magnifying-glass",
+ "pages": [
+ "ko/tools/search-research/overview",
+ "ko/tools/search-research/serperdevtool",
+ "ko/tools/search-research/bravesearchtool",
+ "ko/tools/search-research/exasearchtool",
+ "ko/tools/search-research/linkupsearchtool",
+ "ko/tools/search-research/githubsearchtool",
+ "ko/tools/search-research/websitesearchtool",
+ "ko/tools/search-research/codedocssearchtool",
+ "ko/tools/search-research/youtubechannelsearchtool",
+ "ko/tools/search-research/youtubevideosearchtool",
+ "ko/tools/search-research/tavilysearchtool",
+ "ko/tools/search-research/tavilyextractortool",
+ "ko/tools/search-research/arxivpapertool",
+ "ko/tools/search-research/serpapi-googlesearchtool",
+ "ko/tools/search-research/serpapi-googleshoppingtool",
+ "ko/tools/search-research/databricks-query-tool"
+ ]
+ },
+ {
+ "group": "데이터베이스 & 데이터",
+ "icon": "database",
+ "pages": [
+ "ko/tools/database-data/overview",
+ "ko/tools/database-data/mysqltool",
+ "ko/tools/database-data/pgsearchtool",
+ "ko/tools/database-data/snowflakesearchtool",
+ "ko/tools/database-data/nl2sqltool",
+ "ko/tools/database-data/qdrantvectorsearchtool",
+ "ko/tools/database-data/weaviatevectorsearchtool",
+ "ko/tools/database-data/mongodbvectorsearchtool",
+ "ko/tools/database-data/singlestoresearchtool"
+ ]
+ },
+ {
+ "group": "인공지능 & 머신러닝",
+ "icon": "brain",
+ "pages": [
+ "ko/tools/ai-ml/overview",
+ "ko/tools/ai-ml/dalletool",
+ "ko/tools/ai-ml/visiontool",
+ "ko/tools/ai-ml/aimindtool",
+ "ko/tools/ai-ml/llamaindextool",
+ "ko/tools/ai-ml/langchaintool",
+ "ko/tools/ai-ml/ragtool",
+ "ko/tools/ai-ml/codeinterpretertool"
+ ]
+ },
+ {
+ "group": "클라우드 & 스토리지",
+ "icon": "cloud",
+ "pages": [
+ "ko/tools/cloud-storage/overview",
+ "ko/tools/cloud-storage/s3readertool",
+ "ko/tools/cloud-storage/s3writertool",
+ "ko/tools/cloud-storage/bedrockkbretriever"
+ ]
+ },
+ {
+ "group": "Integrations",
+ "icon": "plug",
+ "pages": [
+ "ko/tools/integration/overview",
+ "ko/tools/integration/bedrockinvokeagenttool",
+ "ko/tools/integration/crewaiautomationtool"
+ ]
+ },
+ {
+ "group": "자동화",
+ "icon": "bolt",
+ "pages": [
+ "ko/tools/automation/overview",
+ "ko/tools/automation/apifyactorstool",
+ "ko/tools/automation/composiotool",
+ "ko/tools/automation/multiontool",
+ "ko/tools/automation/zapieractionstool"
+ ]
+ }
+ ]
+ },
+ {
+ "group": "Observability",
+ "pages": [
+ "ko/observability/tracing",
+ "ko/observability/overview",
+ "ko/observability/arize-phoenix",
+ "ko/observability/braintrust",
+ "ko/observability/datadog",
+ "ko/observability/galileo",
+ "ko/observability/langdb",
+ "ko/observability/langfuse",
+ "ko/observability/langtrace",
+ "ko/observability/maxim",
+ "ko/observability/mlflow",
+ "ko/observability/neatlogs",
+ "ko/observability/openlit",
+ "ko/observability/opik",
+ "ko/observability/patronus-evaluation",
+ "ko/observability/portkey",
+ "ko/observability/weave"
+ ]
+ },
+ {
+ "group": "학습",
+ "pages": [
+ "ko/learn/overview",
+ "ko/learn/llm-selection-guide",
+ "ko/learn/conditional-tasks",
+ "ko/learn/coding-agents",
+ "ko/learn/create-custom-tools",
+ "ko/learn/custom-llm",
+ "ko/learn/custom-manager-agent",
+ "ko/learn/customizing-agents",
+ "ko/learn/dalle-image-generation",
+ "ko/learn/force-tool-output-as-result",
+ "ko/learn/hierarchical-process",
+ "ko/learn/human-input-on-execution",
+ "ko/learn/human-in-the-loop",
+ "ko/learn/human-feedback-in-flows",
+ "ko/learn/kickoff-async",
+ "ko/learn/kickoff-for-each",
+ "ko/learn/llm-connections",
+ "ko/learn/multimodal-agents",
+ "ko/learn/replay-tasks-from-latest-crew-kickoff",
+ "ko/learn/sequential-process",
+ "ko/learn/using-annotations",
+ "ko/learn/execution-hooks",
+ "ko/learn/llm-hooks",
+ "ko/learn/tool-hooks"
+ ]
+ },
+ {
+ "group": "Telemetry",
+ "pages": [
+ "ko/telemetry"
+ ]
+ }
+ ]
+ },
+ {
+ "tab": "엔터프라이즈",
+ "icon": "briefcase",
+ "groups": [
+ {
+ "group": "시작 안내",
+ "pages": [
+ "ko/enterprise/introduction"
+ ]
+ },
+ {
+ "group": "빌드",
+ "pages": [
+ "ko/enterprise/features/automations",
+ "ko/enterprise/features/crew-studio",
+ "ko/enterprise/features/marketplace",
+ "ko/enterprise/features/agent-repositories",
+ "ko/enterprise/features/tools-and-integrations",
+ "ko/enterprise/features/pii-trace-redactions"
+ ]
+ },
+ {
+ "group": "운영",
+ "pages": [
+ "ko/enterprise/features/traces",
+ "ko/enterprise/features/webhook-streaming",
+ "ko/enterprise/features/hallucination-guardrail",
+ "ko/enterprise/features/flow-hitl-management"
+ ]
+ },
+ {
+ "group": "관리",
+ "pages": [
+ "ko/enterprise/features/rbac"
+ ]
+ },
+ {
+ "group": "통합 문서",
+ "pages": [
+ "ko/enterprise/integrations/asana",
+ "ko/enterprise/integrations/box",
+ "ko/enterprise/integrations/clickup",
+ "ko/enterprise/integrations/github",
+ "ko/enterprise/integrations/gmail",
+ "ko/enterprise/integrations/google_calendar",
+ "ko/enterprise/integrations/google_contacts",
+ "ko/enterprise/integrations/google_docs",
+ "ko/enterprise/integrations/google_drive",
+ "ko/enterprise/integrations/google_sheets",
+ "ko/enterprise/integrations/google_slides",
+ "ko/enterprise/integrations/hubspot",
+ "ko/enterprise/integrations/jira",
+ "ko/enterprise/integrations/linear",
+ "ko/enterprise/integrations/microsoft_excel",
+ "ko/enterprise/integrations/microsoft_onedrive",
+ "ko/enterprise/integrations/microsoft_outlook",
+ "ko/enterprise/integrations/microsoft_sharepoint",
+ "ko/enterprise/integrations/microsoft_teams",
+ "ko/enterprise/integrations/microsoft_word",
+ "ko/enterprise/integrations/notion",
+ "ko/enterprise/integrations/salesforce",
+ "ko/enterprise/integrations/shopify",
+ "ko/enterprise/integrations/slack",
+ "ko/enterprise/integrations/stripe",
+ "ko/enterprise/integrations/zendesk"
+ ]
+ },
+ {
+ "group": "How-To Guides",
+ "pages": [
+ "ko/enterprise/guides/build-crew",
+ "ko/enterprise/guides/prepare-for-deployment",
+ "ko/enterprise/guides/deploy-to-amp",
+ "ko/enterprise/guides/private-package-registry",
+ "ko/enterprise/guides/kickoff-crew",
+ "ko/enterprise/guides/training-crews",
+ "ko/enterprise/guides/update-crew",
+ "ko/enterprise/guides/enable-crew-studio",
+ "ko/enterprise/guides/capture_telemetry_logs",
+ "ko/enterprise/guides/azure-openai-setup",
+ "ko/enterprise/guides/tool-repository",
+ "ko/enterprise/guides/custom-mcp-server",
+ "ko/enterprise/guides/react-component-export",
+ "ko/enterprise/guides/team-management",
+ "ko/enterprise/guides/human-in-the-loop",
+ "ko/enterprise/guides/webhook-automation"
+ ]
+ },
+ {
+ "group": "트리거",
+ "pages": [
+ "ko/enterprise/guides/automation-triggers",
+ "ko/enterprise/guides/gmail-trigger",
+ "ko/enterprise/guides/google-calendar-trigger",
+ "ko/enterprise/guides/google-drive-trigger",
+ "ko/enterprise/guides/outlook-trigger",
+ "ko/enterprise/guides/onedrive-trigger",
+ "ko/enterprise/guides/microsoft-teams-trigger",
+ "ko/enterprise/guides/slack-trigger",
+ "ko/enterprise/guides/hubspot-trigger",
+ "ko/enterprise/guides/salesforce-trigger",
+ "ko/enterprise/guides/zapier-trigger"
+ ]
+ },
+ {
+ "group": "학습 자원",
+ "pages": [
+ "ko/enterprise/resources/frequently-asked-questions"
+ ]
+ }
+ ]
+ },
+ {
+ "tab": "API 레퍼런스",
+ "icon": "magnifying-glass",
+ "groups": [
+ {
+ "group": "시작 안내",
+ "pages": [
+ "ko/api-reference/introduction",
+ "ko/api-reference/inputs",
+ "ko/api-reference/kickoff",
+ "ko/api-reference/resume",
+ "ko/api-reference/status"
+ ]
+ }
+ ]
+ },
+ {
+ "tab": "예시",
+ "icon": "code",
+ "groups": [
+ {
+ "group": "예시",
+ "pages": [
+ "ko/examples/example",
+ "ko/examples/cookbooks"
+ ]
+ }
+ ]
+ },
+ {
+ "tab": "변경 로그",
+ "icon": "clock",
+ "groups": [
+ {
+ "group": "릴리스 노트",
+ "pages": [
+ "ko/changelog"
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "version": "v1.14.1",
+ "tabs": [
+ {
+ "tab": "홈",
+ "icon": "house",
+ "groups": [
+ {
+ "group": "환영합니다",
+ "pages": [
+ "ko/index"
+ ]
+ }
+ ]
+ },
+ {
+ "tab": "기술 문서",
+ "icon": "book-open",
+ "groups": [
+ {
+ "group": "시작 안내",
+ "pages": [
+ "ko/introduction",
+ "ko/guides/coding-tools/build-with-ai",
"ko/skills",
"ko/installation",
"ko/quickstart"
@@ -9915,6 +11352,7 @@
"group": "시작 안내",
"pages": [
"ko/introduction",
+ "ko/guides/coding-tools/build-with-ai",
"ko/skills",
"ko/installation",
"ko/quickstart"
@@ -10385,6 +11823,7 @@
"group": "시작 안내",
"pages": [
"ko/introduction",
+ "ko/guides/coding-tools/build-with-ai",
"ko/skills",
"ko/installation",
"ko/quickstart"
@@ -10855,6 +12294,7 @@
"group": "시작 안내",
"pages": [
"ko/introduction",
+ "ko/guides/coding-tools/build-with-ai",
"ko/skills",
"ko/installation",
"ko/quickstart"
@@ -11325,6 +12765,7 @@
"group": "시작 안내",
"pages": [
"ko/introduction",
+ "ko/guides/coding-tools/build-with-ai",
"ko/skills",
"ko/installation",
"ko/quickstart"
@@ -11794,6 +13235,7 @@
"group": "시작 안내",
"pages": [
"ko/introduction",
+ "ko/guides/coding-tools/build-with-ai",
"ko/skills",
"ko/installation",
"ko/quickstart"
@@ -12263,6 +13705,7 @@
"group": "시작 안내",
"pages": [
"ko/introduction",
+ "ko/guides/coding-tools/build-with-ai",
"ko/skills",
"ko/installation",
"ko/quickstart"
@@ -12732,6 +14175,7 @@
"group": "시작 안내",
"pages": [
"ko/introduction",
+ "ko/guides/coding-tools/build-with-ai",
"ko/skills",
"ko/installation",
"ko/quickstart"
@@ -13200,6 +14644,7 @@
"group": "시작 안내",
"pages": [
"ko/introduction",
+ "ko/guides/coding-tools/build-with-ai",
"ko/skills",
"ko/installation",
"ko/quickstart"
@@ -13668,6 +15113,7 @@
"group": "시작 안내",
"pages": [
"ko/introduction",
+ "ko/guides/coding-tools/build-with-ai",
"ko/skills",
"ko/installation",
"ko/quickstart"
@@ -14144,7 +15590,7 @@
},
"versions": [
{
- "version": "v1.14.1",
+ "version": "v1.14.2",
"default": true,
"tabs": [
{
@@ -14167,6 +15613,478 @@
"group": "البدء",
"pages": [
"ar/introduction",
+ "ar/guides/coding-tools/build-with-ai",
+ "ar/skills",
+ "ar/installation",
+ "ar/quickstart"
+ ]
+ },
+ {
+ "group": "الأدلّة",
+ "pages": [
+ {
+ "group": "الاستراتيجية",
+ "icon": "compass",
+ "pages": [
+ "ar/guides/concepts/evaluating-use-cases"
+ ]
+ },
+ {
+ "group": "الوكلاء",
+ "icon": "user",
+ "pages": [
+ "ar/guides/agents/crafting-effective-agents"
+ ]
+ },
+ {
+ "group": "الطواقم",
+ "icon": "users",
+ "pages": [
+ "ar/guides/crews/first-crew"
+ ]
+ },
+ {
+ "group": "التدفقات",
+ "icon": "code-branch",
+ "pages": [
+ "ar/guides/flows/first-flow",
+ "ar/guides/flows/mastering-flow-state"
+ ]
+ },
+ {
+ "group": "الأدوات",
+ "icon": "wrench",
+ "pages": [
+ "ar/guides/tools/publish-custom-tools"
+ ]
+ },
+ {
+ "group": "أدوات البرمجة",
+ "icon": "terminal",
+ "pages": [
+ "ar/guides/coding-tools/agents-md"
+ ]
+ },
+ {
+ "group": "متقدّم",
+ "icon": "gear",
+ "pages": [
+ "ar/guides/advanced/customizing-prompts",
+ "ar/guides/advanced/fingerprinting"
+ ]
+ },
+ {
+ "group": "الترحيل",
+ "icon": "shuffle",
+ "pages": [
+ "ar/guides/migration/migrating-from-langgraph"
+ ]
+ }
+ ]
+ },
+ {
+ "group": "المفاهيم الأساسية",
+ "pages": [
+ "ar/concepts/agents",
+ "ar/concepts/agent-capabilities",
+ "ar/concepts/tasks",
+ "ar/concepts/crews",
+ "ar/concepts/flows",
+ "ar/concepts/production-architecture",
+ "ar/concepts/knowledge",
+ "ar/concepts/skills",
+ "ar/concepts/llms",
+ "ar/concepts/files",
+ "ar/concepts/processes",
+ "ar/concepts/collaboration",
+ "ar/concepts/training",
+ "ar/concepts/memory",
+ "ar/concepts/reasoning",
+ "ar/concepts/planning",
+ "ar/concepts/testing",
+ "ar/concepts/cli",
+ "ar/concepts/tools",
+ "ar/concepts/event-listener",
+ "ar/concepts/checkpointing"
+ ]
+ },
+ {
+ "group": "تكامل MCP",
+ "pages": [
+ "ar/mcp/overview",
+ "ar/mcp/dsl-integration",
+ "ar/mcp/stdio",
+ "ar/mcp/sse",
+ "ar/mcp/streamable-http",
+ "ar/mcp/multiple-servers",
+ "ar/mcp/security"
+ ]
+ },
+ {
+ "group": "الأدوات",
+ "pages": [
+ "ar/tools/overview",
+ {
+ "group": "الملفات والمستندات",
+ "icon": "folder-open",
+ "pages": [
+ "ar/tools/file-document/overview",
+ "ar/tools/file-document/filereadtool",
+ "ar/tools/file-document/filewritetool",
+ "ar/tools/file-document/pdfsearchtool",
+ "ar/tools/file-document/docxsearchtool",
+ "ar/tools/file-document/mdxsearchtool",
+ "ar/tools/file-document/xmlsearchtool",
+ "ar/tools/file-document/txtsearchtool",
+ "ar/tools/file-document/jsonsearchtool",
+ "ar/tools/file-document/csvsearchtool",
+ "ar/tools/file-document/directorysearchtool",
+ "ar/tools/file-document/directoryreadtool",
+ "ar/tools/file-document/ocrtool",
+ "ar/tools/file-document/pdf-text-writing-tool"
+ ]
+ },
+ {
+ "group": "استخراج بيانات الويب",
+ "icon": "globe",
+ "pages": [
+ "ar/tools/web-scraping/overview",
+ "ar/tools/web-scraping/scrapewebsitetool",
+ "ar/tools/web-scraping/scrapeelementfromwebsitetool",
+ "ar/tools/web-scraping/scrapflyscrapetool",
+ "ar/tools/web-scraping/seleniumscrapingtool",
+ "ar/tools/web-scraping/scrapegraphscrapetool",
+ "ar/tools/web-scraping/spidertool",
+ "ar/tools/web-scraping/browserbaseloadtool",
+ "ar/tools/web-scraping/hyperbrowserloadtool",
+ "ar/tools/web-scraping/stagehandtool",
+ "ar/tools/web-scraping/firecrawlcrawlwebsitetool",
+ "ar/tools/web-scraping/firecrawlscrapewebsitetool",
+ "ar/tools/web-scraping/oxylabsscraperstool",
+ "ar/tools/web-scraping/brightdata-tools"
+ ]
+ },
+ {
+ "group": "البحث والاستكشاف",
+ "icon": "magnifying-glass",
+ "pages": [
+ "ar/tools/search-research/overview",
+ "ar/tools/search-research/serperdevtool",
+ "ar/tools/search-research/bravesearchtool",
+ "ar/tools/search-research/exasearchtool",
+ "ar/tools/search-research/linkupsearchtool",
+ "ar/tools/search-research/githubsearchtool",
+ "ar/tools/search-research/websitesearchtool",
+ "ar/tools/search-research/codedocssearchtool",
+ "ar/tools/search-research/youtubechannelsearchtool",
+ "ar/tools/search-research/youtubevideosearchtool",
+ "ar/tools/search-research/tavilysearchtool",
+ "ar/tools/search-research/tavilyextractortool",
+ "ar/tools/search-research/arxivpapertool",
+ "ar/tools/search-research/serpapi-googlesearchtool",
+ "ar/tools/search-research/serpapi-googleshoppingtool",
+ "ar/tools/search-research/databricks-query-tool"
+ ]
+ },
+ {
+ "group": "قواعد البيانات",
+ "icon": "database",
+ "pages": [
+ "ar/tools/database-data/overview",
+ "ar/tools/database-data/mysqltool",
+ "ar/tools/database-data/pgsearchtool",
+ "ar/tools/database-data/snowflakesearchtool",
+ "ar/tools/database-data/nl2sqltool",
+ "ar/tools/database-data/qdrantvectorsearchtool",
+ "ar/tools/database-data/weaviatevectorsearchtool",
+ "ar/tools/database-data/mongodbvectorsearchtool",
+ "ar/tools/database-data/singlestoresearchtool"
+ ]
+ },
+ {
+ "group": "الذكاء الاصطناعي والتعلّم الآلي",
+ "icon": "brain",
+ "pages": [
+ "ar/tools/ai-ml/overview",
+ "ar/tools/ai-ml/dalletool",
+ "ar/tools/ai-ml/visiontool",
+ "ar/tools/ai-ml/aimindtool",
+ "ar/tools/ai-ml/llamaindextool",
+ "ar/tools/ai-ml/langchaintool",
+ "ar/tools/ai-ml/ragtool",
+ "ar/tools/ai-ml/codeinterpretertool"
+ ]
+ },
+ {
+ "group": "التخزين السحابي",
+ "icon": "cloud",
+ "pages": [
+ "ar/tools/cloud-storage/overview",
+ "ar/tools/cloud-storage/s3readertool",
+ "ar/tools/cloud-storage/s3writertool",
+ "ar/tools/cloud-storage/bedrockkbretriever"
+ ]
+ },
+ {
+ "group": "Integrations",
+ "icon": "plug",
+ "pages": [
+ "ar/tools/integration/overview",
+ "ar/tools/integration/bedrockinvokeagenttool",
+ "ar/tools/integration/crewaiautomationtool"
+ ]
+ },
+ {
+ "group": "الأتمتة",
+ "icon": "bolt",
+ "pages": [
+ "ar/tools/automation/overview",
+ "ar/tools/automation/apifyactorstool",
+ "ar/tools/automation/composiotool",
+ "ar/tools/automation/multiontool",
+ "ar/tools/automation/zapieractionstool"
+ ]
+ }
+ ]
+ },
+ {
+ "group": "Observability",
+ "pages": [
+ "ar/observability/tracing",
+ "ar/observability/overview",
+ "ar/observability/arize-phoenix",
+ "ar/observability/braintrust",
+ "ar/observability/datadog",
+ "ar/observability/galileo",
+ "ar/observability/langdb",
+ "ar/observability/langfuse",
+ "ar/observability/langtrace",
+ "ar/observability/maxim",
+ "ar/observability/mlflow",
+ "ar/observability/neatlogs",
+ "ar/observability/openlit",
+ "ar/observability/opik",
+ "ar/observability/patronus-evaluation",
+ "ar/observability/portkey",
+ "ar/observability/weave"
+ ]
+ },
+ {
+ "group": "التعلّم",
+ "pages": [
+ "ar/learn/overview",
+ "ar/learn/llm-selection-guide",
+ "ar/learn/conditional-tasks",
+ "ar/learn/coding-agents",
+ "ar/learn/create-custom-tools",
+ "ar/learn/custom-llm",
+ "ar/learn/custom-manager-agent",
+ "ar/learn/customizing-agents",
+ "ar/learn/dalle-image-generation",
+ "ar/learn/force-tool-output-as-result",
+ "ar/learn/hierarchical-process",
+ "ar/learn/human-input-on-execution",
+ "ar/learn/human-in-the-loop",
+ "ar/learn/human-feedback-in-flows",
+ "ar/learn/kickoff-async",
+ "ar/learn/kickoff-for-each",
+ "ar/learn/llm-connections",
+ "ar/learn/multimodal-agents",
+ "ar/learn/replay-tasks-from-latest-crew-kickoff",
+ "ar/learn/sequential-process",
+ "ar/learn/using-annotations",
+ "ar/learn/execution-hooks",
+ "ar/learn/llm-hooks",
+ "ar/learn/tool-hooks"
+ ]
+ },
+ {
+ "group": "Telemetry",
+ "pages": [
+ "ar/telemetry"
+ ]
+ }
+ ]
+ },
+ {
+ "tab": "المؤسسات",
+ "icon": "briefcase",
+ "groups": [
+ {
+ "group": "البدء",
+ "pages": [
+ "ar/enterprise/introduction"
+ ]
+ },
+ {
+ "group": "البناء",
+ "pages": [
+ "ar/enterprise/features/automations",
+ "ar/enterprise/features/crew-studio",
+ "ar/enterprise/features/marketplace",
+ "ar/enterprise/features/agent-repositories",
+ "ar/enterprise/features/tools-and-integrations",
+ "ar/enterprise/features/pii-trace-redactions"
+ ]
+ },
+ {
+ "group": "العمليات",
+ "pages": [
+ "ar/enterprise/features/traces",
+ "ar/enterprise/features/webhook-streaming",
+ "ar/enterprise/features/hallucination-guardrail",
+ "ar/enterprise/features/flow-hitl-management"
+ ]
+ },
+ {
+ "group": "الإدارة",
+ "pages": [
+ "ar/enterprise/features/rbac"
+ ]
+ },
+ {
+ "group": "التكاملات",
+ "pages": [
+ "ar/enterprise/integrations/asana",
+ "ar/enterprise/integrations/box",
+ "ar/enterprise/integrations/clickup",
+ "ar/enterprise/integrations/github",
+ "ar/enterprise/integrations/gmail",
+ "ar/enterprise/integrations/google_calendar",
+ "ar/enterprise/integrations/google_contacts",
+ "ar/enterprise/integrations/google_docs",
+ "ar/enterprise/integrations/google_drive",
+ "ar/enterprise/integrations/google_sheets",
+ "ar/enterprise/integrations/google_slides",
+ "ar/enterprise/integrations/hubspot",
+ "ar/enterprise/integrations/jira",
+ "ar/enterprise/integrations/linear",
+ "ar/enterprise/integrations/microsoft_excel",
+ "ar/enterprise/integrations/microsoft_onedrive",
+ "ar/enterprise/integrations/microsoft_outlook",
+ "ar/enterprise/integrations/microsoft_sharepoint",
+ "ar/enterprise/integrations/microsoft_teams",
+ "ar/enterprise/integrations/microsoft_word",
+ "ar/enterprise/integrations/notion",
+ "ar/enterprise/integrations/salesforce",
+ "ar/enterprise/integrations/shopify",
+ "ar/enterprise/integrations/slack",
+ "ar/enterprise/integrations/stripe",
+ "ar/enterprise/integrations/zendesk"
+ ]
+ },
+ {
+ "group": "How-To Guides",
+ "pages": [
+ "ar/enterprise/guides/build-crew",
+ "ar/enterprise/guides/prepare-for-deployment",
+ "ar/enterprise/guides/deploy-to-amp",
+ "ar/enterprise/guides/private-package-registry",
+ "ar/enterprise/guides/kickoff-crew",
+ "ar/enterprise/guides/training-crews",
+ "ar/enterprise/guides/update-crew",
+ "ar/enterprise/guides/enable-crew-studio",
+ "ar/enterprise/guides/capture_telemetry_logs",
+ "ar/enterprise/guides/azure-openai-setup",
+ "ar/enterprise/guides/tool-repository",
+ "ar/enterprise/guides/custom-mcp-server",
+ "ar/enterprise/guides/react-component-export",
+ "ar/enterprise/guides/team-management",
+ "ar/enterprise/guides/human-in-the-loop",
+ "ar/enterprise/guides/webhook-automation"
+ ]
+ },
+ {
+ "group": "المشغّلات",
+ "pages": [
+ "ar/enterprise/guides/automation-triggers",
+ "ar/enterprise/guides/gmail-trigger",
+ "ar/enterprise/guides/google-calendar-trigger",
+ "ar/enterprise/guides/google-drive-trigger",
+ "ar/enterprise/guides/outlook-trigger",
+ "ar/enterprise/guides/onedrive-trigger",
+ "ar/enterprise/guides/microsoft-teams-trigger",
+ "ar/enterprise/guides/slack-trigger",
+ "ar/enterprise/guides/hubspot-trigger",
+ "ar/enterprise/guides/salesforce-trigger",
+ "ar/enterprise/guides/zapier-trigger"
+ ]
+ },
+ {
+ "group": "موارد التعلّم",
+ "pages": [
+ "ar/enterprise/resources/frequently-asked-questions"
+ ]
+ }
+ ]
+ },
+ {
+ "tab": "API المرجع",
+ "icon": "magnifying-glass",
+ "groups": [
+ {
+ "group": "البدء",
+ "pages": [
+ "ar/api-reference/introduction",
+ "ar/api-reference/inputs",
+ "ar/api-reference/kickoff",
+ "ar/api-reference/resume",
+ "ar/api-reference/status"
+ ]
+ }
+ ]
+ },
+ {
+ "tab": "أمثلة",
+ "icon": "code",
+ "groups": [
+ {
+ "group": "أمثلة",
+ "pages": [
+ "ar/examples/example",
+ "ar/examples/cookbooks"
+ ]
+ }
+ ]
+ },
+ {
+ "tab": "التغييرات السجلات",
+ "icon": "clock",
+ "groups": [
+ {
+ "group": "سجل التغييرات",
+ "pages": [
+ "ar/changelog"
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "version": "v1.14.1",
+ "tabs": [
+ {
+ "tab": "الرئيسية",
+ "icon": "house",
+ "groups": [
+ {
+ "group": "مرحباً",
+ "pages": [
+ "ar/index"
+ ]
+ }
+ ]
+ },
+ {
+ "tab": "التقنية التوثيق",
+ "icon": "book-open",
+ "groups": [
+ {
+ "group": "البدء",
+ "pages": [
+ "ar/introduction",
+ "ar/guides/coding-tools/build-with-ai",
"ar/skills",
"ar/installation",
"ar/quickstart"
@@ -14637,6 +16555,7 @@
"group": "البدء",
"pages": [
"ar/introduction",
+ "ar/guides/coding-tools/build-with-ai",
"ar/skills",
"ar/installation",
"ar/quickstart"
@@ -15107,6 +17026,7 @@
"group": "البدء",
"pages": [
"ar/introduction",
+ "ar/guides/coding-tools/build-with-ai",
"ar/skills",
"ar/installation",
"ar/quickstart"
@@ -15577,6 +17497,7 @@
"group": "البدء",
"pages": [
"ar/introduction",
+ "ar/guides/coding-tools/build-with-ai",
"ar/skills",
"ar/installation",
"ar/quickstart"
@@ -16047,6 +17968,7 @@
"group": "البدء",
"pages": [
"ar/introduction",
+ "ar/guides/coding-tools/build-with-ai",
"ar/skills",
"ar/installation",
"ar/quickstart"
@@ -16516,6 +18438,7 @@
"group": "البدء",
"pages": [
"ar/introduction",
+ "ar/guides/coding-tools/build-with-ai",
"ar/skills",
"ar/installation",
"ar/quickstart"
@@ -16985,6 +18908,7 @@
"group": "البدء",
"pages": [
"ar/introduction",
+ "ar/guides/coding-tools/build-with-ai",
"ar/skills",
"ar/installation",
"ar/quickstart"
@@ -17454,6 +19378,7 @@
"group": "البدء",
"pages": [
"ar/introduction",
+ "ar/guides/coding-tools/build-with-ai",
"ar/skills",
"ar/installation",
"ar/quickstart"
@@ -17922,6 +19847,7 @@
"group": "البدء",
"pages": [
"ar/introduction",
+ "ar/guides/coding-tools/build-with-ai",
"ar/skills",
"ar/installation",
"ar/quickstart"
@@ -18390,6 +20316,7 @@
"group": "البدء",
"pages": [
"ar/introduction",
+ "ar/guides/coding-tools/build-with-ai",
"ar/skills",
"ar/installation",
"ar/quickstart"
diff --git a/docs/en/changelog.mdx b/docs/en/changelog.mdx
index d1a72c2ca..8fc991bbf 100644
--- a/docs/en/changelog.mdx
+++ b/docs/en/changelog.mdx
@@ -4,6 +4,126 @@ description: "Product updates, improvements, and bug fixes for CrewAI"
icon: "clock"
mode: "wide"
---
+
+ ## v1.14.3a3
+
+ [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.3a3)
+
+ ## What's Changed
+
+ ### Features
+ - Add support for e2b
+ - Implement fallback to DefaultAzureCredential when no API key is provided
+
+ ### Bug Fixes
+ - Upgrade lxml to >=6.1.0 to address security issue GHSA-vfmq-68hx-4jfw
+
+ ### Documentation
+ - Remove pricing FAQ from build-with-ai page across all locales
+
+ ### Performance
+ - Improve cold start time by ~29% through lazy-loading of MCP SDK and event types
+
+ ## Contributors
+
+ @alex-clawd, @github-advanced-security[bot], @greysonlalonde, @iris-clawd, @lorenzejay, @mattatcha
+
+
+
+
+ ## v1.14.3a2
+
+ [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.3a2)
+
+ ## What's Changed
+
+ ### Features
+ - Add support for bedrock V4
+ - Add Daytona sandbox tools for enhanced functionality
+ - Add 'Build with AI' page — AI-native docs for coding agents
+ - Add Build with AI to Get Started navigation and page files for all languages (en, ko, pt-BR, ar)
+
+ ### Bug Fixes
+ - Fix propagation of implicit @CrewBase names to crew events
+ - Resolve issue with duplicate batch initialization in execution metadata merge
+ - Fix serialization of Task class-reference fields for checkpointing
+ - Handle BaseModel result in guardrail retry loop
+ - Bump python-dotenv to version >=1.2.2 for security compliance
+
+ ### Documentation
+ - Update changelog and version for v1.14.3a1
+ - Update descriptions and apply actual translations
+
+ ## Contributors
+
+ @MatthiasHowellYopp, @github-actions[bot], @greysonlalonde, @iris-clawd, @lorenzejay, @renatonitta
+
+
+
+
+ ## v1.14.3a1
+
+ [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.3a1)
+
+ ## What's Changed
+
+ ### Features
+ - Add checkpoint and fork support to standalone agents
+
+ ### Bug Fixes
+ - Preserve thought_signature in Gemini streaming tool calls
+ - Emit task_started on fork resume and redesign checkpoint TUI
+ - Correct dry-run order and handle checked-out stale branch in devtools release
+ - Use future dates in checkpoint prune tests to prevent time-dependent failures (#5543)
+
+ ### Documentation
+ - Update changelog and version for v1.14.2
+
+ ## Contributors
+
+ @alex-clawd, @greysonlalonde
+
+
+
+
+ ## v1.14.2
+
+ [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.2)
+
+ ## What's Changed
+
+ ### Features
+ - Add checkpoint resume, diff, and prune commands with improved discoverability.
+ - Add `from_checkpoint` parameter to `Agent.kickoff` and related methods.
+ - Add template management commands for project templates.
+ - Add resume hints to devtools release on failure.
+ - Add deploy validation CLI and enhance LLM initialization ergonomics.
+ - Add checkpoint forking with lineage tracking.
+ - Enrich LLM token tracking with reasoning tokens and cache creation tokens.
+
+ ### Bug Fixes
+ - Fix prompt on stale branch conflicts in devtools release.
+ - Patch vulnerabilities in `authlib`, `langchain-text-splitters`, and `pypdf`.
+ - Scope streaming handlers to prevent cross-run chunk contamination.
+ - Dispatch Flow checkpoints through Flow APIs in TUI.
+ - Use recursive glob for JSON checkpoint discovery.
+ - Handle cyclic JSON schemas in MCP tool resolution.
+ - Preserve Bedrock tool call arguments by removing truthy default.
+ - Emit flow_finished event after HITL resume.
+ - Fix various vulnerabilities by updating dependencies, including `requests`, `cryptography`, and `pytest`.
+ - Fix to stop forwarding strict mode to Bedrock Converse API.
+
+ ### Documentation
+ - Document missing parameters and add Checkpointing section.
+ - Update changelog and version for v1.14.2 and previous release candidates.
+ - Add enterprise A2A feature documentation and update OSS A2A docs.
+
+ ## Contributors
+
+ @Yanhu007, @alex-clawd, @github-actions[bot], @greysonlalonde, @iris-clawd, @lorenzejay, @lucasgomide
+
+
+
## v1.14.2rc1
diff --git a/docs/en/concepts/crews.mdx b/docs/en/concepts/crews.mdx
index 07fcfd59d..aacf02e1e 100644
--- a/docs/en/concepts/crews.mdx
+++ b/docs/en/concepts/crews.mdx
@@ -33,7 +33,14 @@ A crew in crewAI represents a collaborative group of agents working together to
| **Planning** *(optional)* | `planning` | Adds planning ability to the Crew. When activated before each Crew iteration, all Crew data is sent to an AgentPlanner that will plan the tasks and this plan will be added to each task description. |
| **Planning LLM** *(optional)* | `planning_llm` | The language model used by the AgentPlanner in a planning process. |
| **Knowledge Sources** _(optional)_ | `knowledge_sources` | Knowledge sources available at the crew level, accessible to all the agents. |
-| **Stream** _(optional)_ | `stream` | Enable streaming output to receive real-time updates during crew execution. Returns a `CrewStreamingOutput` object that can be iterated for chunks. Defaults to `False`. |
+| **Stream** _(optional)_ | `stream` | Enable streaming output to receive real-time updates during crew execution. Returns a `CrewStreamingOutput` object that can be iterated for chunks. Defaults to `False`. |
+| **Chat LLM** _(optional)_ | `chat_llm` | The language model used to orchestrate `crewai chat` CLI interactions with the crew. Accepts a model name string or `LLM` instance. Defaults to `None`. |
+| **Before Kickoff Callbacks** _(optional)_ | `before_kickoff_callbacks` | A list of callable functions executed **before** the crew starts. Each callback receives and can modify the inputs dict. Distinct from the `@before_kickoff` decorator. Defaults to `[]`. |
+| **After Kickoff Callbacks** _(optional)_ | `after_kickoff_callbacks` | A list of callable functions executed **after** the crew finishes. Each callback receives and can modify the `CrewOutput`. Distinct from the `@after_kickoff` decorator. Defaults to `[]`. |
+| **Tracing** _(optional)_ | `tracing` | Controls OpenTelemetry tracing for the crew. `True` = always enable, `False` = always disable, `None` = inherit from environment / user settings. Defaults to `None`. |
+| **Skills** _(optional)_ | `skills` | A list of `Path` objects (skill search directories) or pre-loaded `Skill` objects applied to all agents in the crew. Defaults to `None`. |
+| **Security Config** _(optional)_ | `security_config` | A `SecurityConfig` instance managing crew fingerprinting and identity. Defaults to `SecurityConfig()`. |
+| **Checkpoint** _(optional)_ | `checkpoint` | Enables automatic checkpointing. Pass `True` for sensible defaults, a `CheckpointConfig` for full control, `False` to opt out, or `None` to inherit. See the [Checkpointing](#checkpointing) section below. Defaults to `None`. |
**Crew Max RPM**: The `max_rpm` attribute sets the maximum number of requests per minute the crew can perform to avoid rate limits and will override individual agents' `max_rpm` settings if you set it.
@@ -271,6 +278,72 @@ crew = Crew(output_log_file = file_name.json) # Logs will be saved as file_name
+## Checkpointing
+
+Checkpointing lets a crew automatically save its state after key events (e.g. task completion) so that long-running or interrupted runs can be resumed exactly where they left off without re-executing completed tasks.
+
+### Quick Start
+
+Pass `checkpoint=True` to enable checkpointing with sensible defaults (saves to `.checkpoints/` after every task):
+
+```python Code
+from crewai import Crew, Process
+
+crew = Crew(
+ agents=[researcher, writer],
+ tasks=[research_task, write_task],
+ process=Process.sequential,
+ checkpoint=True, # saves to .checkpoints/ after every task
+)
+
+crew.kickoff(inputs={"topic": "AI trends"})
+```
+
+### Full Control with `CheckpointConfig`
+
+Use `CheckpointConfig` for fine-grained control over location, trigger events, storage backend, and retention:
+
+```python Code
+from crewai import Crew, Process
+from crewai.state.checkpoint_config import CheckpointConfig
+
+crew = Crew(
+ agents=[researcher, writer],
+ tasks=[research_task, write_task],
+ process=Process.sequential,
+ checkpoint=CheckpointConfig(
+ location="./.checkpoints", # directory for JSON files (default)
+ on_events=["task_completed"], # trigger after each task (default)
+ max_checkpoints=5, # keep only the 5 most recent checkpoints
+ ),
+)
+
+crew.kickoff(inputs={"topic": "AI trends"})
+```
+
+### Resuming from a Checkpoint
+
+Use `Crew.from_checkpoint()` to restore a crew from a saved checkpoint file, then call `kickoff()` to resume:
+
+```python Code
+# Resume from the most recent checkpoint
+crew = Crew.from_checkpoint(".checkpoints/latest.json")
+crew.kickoff()
+```
+
+
+When restoring from a checkpoint, `checkpoint_inputs`, `checkpoint_train`, and `checkpoint_kickoff_event_id` are automatically reconstructed — you do not need to set these manually.
+
+
+### `CheckpointConfig` Attributes
+
+| Attribute | Type | Default | Description |
+| :----------------- | :------------------------------------- | :------------------- | :-------------------------------------------------------------------------------------------- |
+| `location` | `str` | `"./.checkpoints"` | Storage destination. For `JsonProvider` this is a directory path; for `SqliteProvider` a database file path. |
+| `on_events` | `list[str]` | `["task_completed"]` | Event types that trigger a checkpoint write. Use `["*"]` to checkpoint on every event. |
+| `provider` | `JsonProvider \| SqliteProvider` | `JsonProvider()` | Storage backend. Defaults to `JsonProvider` (plain JSON files). |
+| `max_checkpoints` | `int \| None` | `None` | Maximum checkpoints to keep. Oldest are pruned after each write. `None` keeps all. |
+
## Memory Utilization
Crews can utilize memory (short-term, long-term, and entity memory) to enhance their execution and learning over time. This feature allows crews to store and recall execution memories, aiding in decision-making and task execution strategies.
diff --git a/docs/en/guides/coding-tools/build-with-ai.mdx b/docs/en/guides/coding-tools/build-with-ai.mdx
new file mode 100644
index 000000000..8e6c2b3ea
--- /dev/null
+++ b/docs/en/guides/coding-tools/build-with-ai.mdx
@@ -0,0 +1,214 @@
+---
+title: "Build with AI"
+description: "Everything AI coding agents need to build, deploy, and scale with CrewAI — skills, machine-readable docs, deployment, and enterprise features."
+icon: robot
+mode: "wide"
+---
+
+# Build with AI
+
+CrewAI is AI-native. This page brings together everything an AI coding agent needs to build with CrewAI — whether you're Claude Code, Codex, Cursor, Gemini CLI, or any other assistant helping a developer ship crews and flows.
+
+### Supported Coding Agents
+
+
+
+
+
+
+
+
+
+
+ This page is designed to be consumed by both humans and AI assistants. If you're a coding agent, start with **Skills** to get CrewAI context, then use **llms.txt** for full docs access.
+
+
+---
+
+## 1. Skills — Teach Your Agent CrewAI
+
+**Skills** are instruction packs that give coding agents deep CrewAI knowledge — how to scaffold Flows, configure Crews, use tools, and follow framework conventions.
+
+
+
+
+ CrewAI skills are available in the **Claude Code plugin marketplace** — the same distribution channel used by top AI-native companies:
+ ```shell
+ /plugin marketplace add crewAIInc/skills
+ /plugin install crewai-skills@crewai-plugins
+ /reload-plugins
+ ```
+
+ Four skills activate automatically when you ask relevant CrewAI questions:
+
+ | Skill | When it runs |
+ |-------|--------------|
+ | `getting-started` | Scaffolding new projects, choosing between `LLM.call()` / `Agent` / `Crew` / `Flow`, wiring `crew.py` / `main.py` |
+ | `design-agent` | Configuring agents — role, goal, backstory, tools, LLMs, memory, guardrails |
+ | `design-task` | Writing task descriptions, dependencies, structured output (`output_pydantic`, `output_json`), human review |
+ | `ask-docs` | Querying the live [CrewAI docs MCP server](https://docs.crewai.com/mcp) for up-to-date API details |
+
+
+ Works with Claude Code, Codex, Cursor, Gemini CLI, or any coding agent:
+ ```shell
+ npx skills add crewaiinc/skills
+ ```
+ Pulls from the [skills.sh registry](https://skills.sh/crewaiinc/skills).
+
+
+
+
+
+ Use either method above — the Claude Code plugin marketplace or `npx skills add`. Both install the official [crewAIInc/skills](https://github.com/crewAIInc/skills) pack.
+
+
+ The skill pack teaches your agent:
+ - **Flows** — stateful apps, steps, and crew kickoffs
+ - **Crews & Agents** — YAML-first patterns, roles, tasks, delegation
+ - **Tools & Integrations** — search, APIs, MCP servers, and common CrewAI tools
+ - **Project layout** — CLI scaffolds and repo conventions
+ - **Up-to-date patterns** — tracks current CrewAI docs and best practices
+
+
+ Your agent can now scaffold and build CrewAI projects without you re-explaining the framework each session.
+
+
+
+
+
+ How skills work in CrewAI agents — injection, activation, and patterns.
+
+
+ Overview of the crewAIInc/skills pack and what it includes.
+
+
+ Set up AGENTS.md for Claude Code, Codex, Cursor, and Gemini CLI.
+
+
+ Official listing — skills, install stats, and audits.
+
+
+
+---
+
+## 2. llms.txt — Machine-Readable Docs
+
+CrewAI publishes an `llms.txt` file that gives AI assistants direct access to the full documentation in a machine-readable format.
+
+```
+https://docs.crewai.com/llms.txt
+```
+
+
+
+ [`llms.txt`](https://llmstxt.org/) is an emerging standard for making documentation consumable by large language models. Instead of scraping HTML, your agent can fetch a single structured text file with all the content it needs.
+
+ CrewAI's `llms.txt` is **already live** — your agent can use it right now.
+
+
+ Point your coding agent at the URL when it needs CrewAI reference docs:
+
+ ```
+ Fetch https://docs.crewai.com/llms.txt for CrewAI documentation.
+ ```
+
+ Many coding agents (Claude Code, Cursor, etc.) can fetch URLs directly. The file contains structured documentation covering all CrewAI concepts, APIs, and guides.
+
+
+ - **No scraping required** — clean, structured content in one request
+ - **Always up-to-date** — served directly from docs.crewai.com
+ - **Optimized for LLMs** — formatted for context windows, not browsers
+ - **Complements skills** — skills teach patterns, llms.txt provides reference
+
+
+
+---
+
+## 3. Deploy to Enterprise
+
+Go from a local crew to production on **CrewAI AMP** (Agent Management Platform) in minutes.
+
+
+
+ Scaffold and test your crew or flow:
+ ```bash
+ crewai create crew my_crew
+ cd my_crew
+ crewai run
+ ```
+
+
+ Ensure your project structure is ready:
+ ```bash
+ crewai deploy --prepare
+ ```
+ See the [preparation guide](/en/enterprise/guides/prepare-for-deployment) for details on project structure and requirements.
+
+
+ Push to the CrewAI AMP platform:
+ ```bash
+ crewai deploy
+ ```
+ You can also deploy via [GitHub integration](/en/enterprise/guides/deploy-to-amp) or [Crew Studio](/en/enterprise/guides/enable-crew-studio).
+
+
+ Your deployed crew gets a REST API endpoint. Integrate it into any application:
+ ```bash
+ curl -X POST https://app.crewai.com/api/v1/crews//kickoff \
+ -H "Authorization: Bearer $CREWAI_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{"inputs": {"topic": "AI agents"}}'
+ ```
+
+
+
+
+
+ Full deployment guide — CLI, GitHub, and Crew Studio methods.
+
+
+ Platform overview — what AMP provides for production crews.
+
+
+
+---
+
+## 4. Enterprise Features
+
+CrewAI AMP is built for production teams. Here's what you get beyond deployment.
+
+
+
+ Detailed execution traces, logs, and performance metrics for every crew run. Monitor agent decisions, tool calls, and task completion in real time.
+
+
+ No-code/low-code interface to create, customize, and deploy crews visually — then export to code or deploy directly.
+
+
+ Stream real-time events from crew executions to your systems. Integrate with Slack, Zapier, or any webhook consumer.
+
+
+ SSO, RBAC, and organization-level controls. Manage who can create, deploy, and access crews across your team.
+
+
+ Publish and share custom tools across your organization. Install community tools from the registry.
+
+
+ Run CrewAI AMP on your own infrastructure. Full platform capabilities with data residency and compliance controls.
+
+
+
+
+
+ AMP is for teams that need to move AI agent workflows from prototypes to production — with observability, access controls, and scalable infrastructure. Whether you're a startup or enterprise, AMP handles the operational complexity so you can focus on building agents.
+
+
+ - **Cloud (app.crewai.com)** — managed by CrewAI, fastest path to production
+ - **Factory (self-hosted)** — run on your own infrastructure for full data control
+ - **Hybrid** — mix cloud and self-hosted based on sensitivity requirements
+
+
+
+
+ Sign up and deploy your first crew to production.
+
diff --git a/docs/ko/changelog.mdx b/docs/ko/changelog.mdx
index 5cb685f3c..26c63cad6 100644
--- a/docs/ko/changelog.mdx
+++ b/docs/ko/changelog.mdx
@@ -4,6 +4,126 @@ description: "CrewAI의 제품 업데이트, 개선 사항 및 버그 수정"
icon: "clock"
mode: "wide"
---
+
+ ## v1.14.3a3
+
+ [GitHub 릴리스 보기](https://github.com/crewAIInc/crewAI/releases/tag/1.14.3a3)
+
+ ## 변경 사항
+
+ ### 기능
+ - e2b 지원 추가
+ - API 키가 제공되지 않을 경우 DefaultAzureCredential로 대체 구현
+
+ ### 버그 수정
+ - 보안 문제 GHSA-vfmq-68hx-4jfw를 해결하기 위해 lxml을 >=6.1.0으로 업그레이드
+
+ ### 문서
+ - 모든 지역에서 build-with-ai 페이지의 가격 FAQ 제거
+
+ ### 성능
+ - MCP SDK 및 이벤트 유형의 지연 로딩을 통해 콜드 스타트 시간을 약 29% 개선
+
+ ## 기여자
+
+ @alex-clawd, @github-advanced-security[bot], @greysonlalonde, @iris-clawd, @lorenzejay, @mattatcha
+
+
+
+
+ ## v1.14.3a2
+
+ [GitHub 릴리스 보기](https://github.com/crewAIInc/crewAI/releases/tag/1.14.3a2)
+
+ ## 변경 사항
+
+ ### 기능
+ - 베드록 V4 지원 추가
+ - 향상된 기능을 위한 데이토나 샌드박스 도구 추가
+ - 'AI와 함께 빌드' 페이지 추가 — 코딩 에이전트를 위한 AI 네이티브 문서
+ - 모든 언어(en, ko, pt-BR, ar)에 대한 시작하기 탐색 및 페이지 파일에 AI와 함께 빌드 추가
+
+ ### 버그 수정
+ - 크루 이벤트에 대한 암묵적 @CrewBase 이름 전파 수정
+ - 실행 메타데이터 병합에서 중복 배치 초기화 문제 해결
+ - 체크포인트를 위한 Task 클래스 참조 필드 직렬화 수정
+ - 가드레일 재시도 루프에서 BaseModel 결과 처리
+ - 보안 준수를 위해 python-dotenv를 버전 >=1.2.2로 업데이트
+
+ ### 문서
+ - v1.14.3a1에 대한 변경 로그 및 버전 업데이트
+ - 설명 업데이트 및 실제 번역 적용
+
+ ## 기여자
+
+ @MatthiasHowellYopp, @github-actions[bot], @greysonlalonde, @iris-clawd, @lorenzejay, @renatonitta
+
+
+
+
+ ## v1.14.3a1
+
+ [GitHub 릴리스 보기](https://github.com/crewAIInc/crewAI/releases/tag/1.14.3a1)
+
+ ## 변경 사항
+
+ ### 기능
+ - 독립형 에이전트에 체크포인트 및 포크 지원 추가
+
+ ### 버그 수정
+ - Gemini 스트리밍 도구 호출에서 thought_signature 보존
+ - 포크 재개 시 task_started 방출 및 체크포인트 TUI 재설계
+ - dry-run 순서 수정 및 devtools 릴리스에서 체크아웃된 오래된 브랜치 처리
+ - 체크포인트 가지치기 테스트에서 미래 날짜 사용하여 시간 의존성 실패 방지 (#5543)
+
+ ### 문서
+ - v1.14.2에 대한 변경 로그 및 버전 업데이트
+
+ ## 기여자
+
+ @alex-clawd, @greysonlalonde
+
+
+
+
+ ## v1.14.2
+
+ [GitHub 릴리스 보기](https://github.com/crewAIInc/crewAI/releases/tag/1.14.2)
+
+ ## 변경 사항
+
+ ### 기능
+ - 체크포인트 재개, 차이(diff), 및 가지치기(prune) 명령을 추가하여 가시성을 개선했습니다.
+ - `Agent.kickoff` 및 관련 메서드에 `from_checkpoint` 매개변수를 추가했습니다.
+ - 프로젝트 템플릿을 위한 템플릿 관리 명령을 추가했습니다.
+ - 실패 시 개발 도구 릴리스에 재개 힌트를 추가했습니다.
+ - 배포 검증 CLI를 추가하고 LLM 초기화의 사용 편의성을 향상시켰습니다.
+ - 계보 추적이 가능한 체크포인트 포킹을 추가했습니다.
+ - 추론 토큰 및 캐시 생성 토큰으로 LLM 토큰 추적을 풍부하게 했습니다.
+
+ ### 버그 수정
+ - 개발 도구 릴리스에서 오래된 브랜치 충돌에 대한 프롬프트를 수정했습니다.
+ - `authlib`, `langchain-text-splitters`, 및 `pypdf`의 취약점을 패치했습니다.
+ - 스트리밍 핸들러의 범위를 설정하여 교차 실행 청크 오염을 방지했습니다.
+ - TUI에서 Flow API를 통해 Flow 체크포인트를 전송했습니다.
+ - JSON 체크포인트 발견을 위해 재귀적 글로브를 사용했습니다.
+ - MCP 도구 해상도에서 순환 JSON 스키마를 처리했습니다.
+ - 진리값이 있는 기본값을 제거하여 Bedrock 도구 호출 인수를 보존했습니다.
+ - HITL 재개 후 flow_finished 이벤트를 발생시켰습니다.
+ - `requests`, `cryptography`, 및 `pytest`를 포함한 종속성을 업데이트하여 다양한 취약점을 수정했습니다.
+ - Bedrock Converse API에 엄격 모드를 전달하지 않도록 수정했습니다.
+
+ ### 문서
+ - 누락된 매개변수를 문서화하고 체크포인팅 섹션을 추가했습니다.
+ - v1.14.2 및 이전 릴리스 후보에 대한 변경 로그 및 버전을 업데이트했습니다.
+ - 기업 A2A 기능 문서를 추가하고 OSS A2A 문서를 업데이트했습니다.
+
+ ## 기여자
+
+ @Yanhu007, @alex-clawd, @github-actions[bot], @greysonlalonde, @iris-clawd, @lorenzejay, @lucasgomide
+
+
+
## v1.14.2rc1
diff --git a/docs/ko/guides/coding-tools/build-with-ai.mdx b/docs/ko/guides/coding-tools/build-with-ai.mdx
new file mode 100644
index 000000000..0e56a06cc
--- /dev/null
+++ b/docs/ko/guides/coding-tools/build-with-ai.mdx
@@ -0,0 +1,214 @@
+---
+title: "AI와 함께 빌드하기"
+description: "CrewAI로 빌드·배포·확장하는 데 필요한 모든 것 — 스킬, 기계가 읽을 수 있는 문서, 배포, 엔터프라이즈 기능을 AI 코딩 에이전트용으로 정리했습니다."
+icon: robot
+mode: "wide"
+---
+
+# AI와 함께 빌드하기
+
+CrewAI는 AI 네이티브입니다. 이 페이지는 Claude Code, Codex, Cursor, Gemini CLI 등 개발자가 crew와 flow를 배포하도록 돕는 코딩 에이전트가 CrewAI로 빌드할 때 필요한 내용을 한곳에 모았습니다.
+
+### 지원 코딩 에이전트
+
+
+
+
+
+
+
+
+
+
+ 이 페이지는 사람과 AI 어시스턴트 모두를 위해 작성되었습니다. 코딩 에이전트라면 CrewAI 맥락은 **Skills**부터, 전체 문서 접근은 **llms.txt**를 사용하세요.
+
+
+---
+
+## 1. Skills — 에이전트에게 CrewAI 가르치기
+
+**Skills**는 코딩 에이전트에게 Flow 스캐폴딩, Crew 구성, 도구 사용, 프레임워크 관례 등 CrewAI에 대한 깊은 지식을 담은 지침 묶음입니다.
+
+
+
+
+ CrewAI 스킬은 **Claude Code 플러그인 마켓플레이스**에서 제공됩니다. AI 네이티브 기업들이 쓰는 것과 같은 배포 채널입니다.
+ ```shell
+ /plugin marketplace add crewAIInc/skills
+ /plugin install crewai-skills@crewai-plugins
+ /reload-plugins
+ ```
+
+ CrewAI와 관련된 질문을 하면 다음 네 가지 스킬이 자동으로 활성화됩니다.
+
+ | 스킬 | 실행 시점 |
+ |------|-------------|
+ | `getting-started` | 새 프로젝트 스캐폴딩, `LLM.call()` / `Agent` / `Crew` / `Flow` 선택, `crew.py` / `main.py` 연결 |
+ | `design-agent` | 에이전트 구성 — 역할, 목표, 배경 이야기, 도구, LLM, 메모리, 가드레일 |
+ | `design-task` | 태스크 설명, 의존성, 구조화된 출력(`output_pydantic`, `output_json`), 사람 검토 |
+ | `ask-docs` | 최신 API 정보를 위해 [CrewAI 문서 MCP 서버](https://docs.crewai.com/mcp) 조회 |
+
+
+ Claude Code, Codex, Cursor, Gemini CLI 등 모든 코딩 에이전트에서 사용할 수 있습니다.
+ ```shell
+ npx skills add crewaiinc/skills
+ ```
+ [skills.sh 레지스트리](https://skills.sh/crewaiinc/skills)에서 가져옵니다.
+
+
+
+
+
+ 위 방법 중 하나를 사용하세요 — Claude Code 플러그인 마켓플레이스 또는 `npx skills add`. 둘 다 공식 [crewAIInc/skills](https://github.com/crewAIInc/skills) 팩을 설치합니다.
+
+
+ 스킬 팩이 에이전트에게 알려 주는 내용:
+ - **Flow** — 상태ful 앱, 단계, crew 킥오프
+ - **Crew 및 에이전트** — YAML 우선 패턴, 역할, 태스크, 위임
+ - **도구 및 통합** — 검색, API, MCP 서버, 일반적인 CrewAI 도구
+ - **프로젝트 레이아웃** — CLI 스캐폴드와 저장소 관례
+ - **최신 패턴** — 현재 CrewAI 문서와 모범 사례 반영
+
+
+ 매 세션마다 프레임워크를 다시 설명하지 않아도 에이전트가 CrewAI 프로젝트를 스캐폴딩하고 빌드할 수 있습니다.
+
+
+
+
+
+ CrewAI 에이전트에서 스킬이 동작하는 방식 — 주입, 활성화, 패턴.
+
+
+ crewAIInc/skills 팩 개요와 포함 내용.
+
+
+ Claude Code, Codex, Cursor, Gemini CLI용 AGENTS.md 설정.
+
+
+ 공식 목록 — 스킬, 설치 통계, 감사 정보.
+
+
+
+---
+
+## 2. llms.txt — 기계가 읽을 수 있는 문서
+
+CrewAI는 AI 어시스턴트가 전체 문서에 기계가 읽을 수 있는 형태로 바로 접근할 수 있도록 `llms.txt` 파일을 제공합니다.
+
+```
+https://docs.crewai.com/llms.txt
+```
+
+
+
+ [`llms.txt`](https://llmstxt.org/)는 문서를 대규모 언어 모델이 소비하기 쉽게 만드는 새로운 표준입니다. HTML을 스크래핑하는 대신, 필요한 내용이 담긴 하나의 구조화된 텍스트 파일을 가져올 수 있습니다.
+
+ CrewAI의 `llms.txt`는 **이미 제공 중**이며, 에이전트가 바로 사용할 수 있습니다.
+
+
+ CrewAI 참고 문서가 필요할 때 코딩 에이전트에 URL을 알려 주세요.
+
+ ```
+ Fetch https://docs.crewai.com/llms.txt for CrewAI documentation.
+ ```
+
+ Claude Code, Cursor 등 많은 코딩 에이전트가 URL을 직접 가져올 수 있습니다. 파일에는 CrewAI 개념, API, 가이드를 아우르는 구조화된 문서가 포함되어 있습니다.
+
+
+ - **스크래핑 불필요** — 한 번의 요청으로 깔끔한 구조화 콘텐츠
+ - **항상 최신** — docs.crewai.com에서 직접 제공
+ - **LLM에 최적화** — 브라우저가 아니라 컨텍스트 윈도우에 맞게 포맷
+ - **스킬과 상호 보완** — 스킬은 패턴을, llms.txt는 참조를 제공
+
+
+
+---
+
+## 3. 엔터프라이즈에 배포
+
+로컬 crew를 몇 분 안에 **CrewAI AMP**(Agent Management Platform) 프로덕션으로 가져가세요.
+
+
+
+ crew 또는 flow를 스캐폴딩하고 테스트합니다.
+ ```bash
+ crewai create crew my_crew
+ cd my_crew
+ crewai run
+ ```
+
+
+ 프로젝트 구조가 준비되었는지 확인합니다.
+ ```bash
+ crewai deploy --prepare
+ ```
+ 구조와 요구 사항은 [준비 가이드](/ko/enterprise/guides/prepare-for-deployment)를 참고하세요.
+
+
+ CrewAI AMP 플랫폼으로 푸시합니다.
+ ```bash
+ crewai deploy
+ ```
+ [GitHub 연동](/ko/enterprise/guides/deploy-to-amp) 또는 [Crew Studio](/ko/enterprise/guides/enable-crew-studio)로도 배포할 수 있습니다.
+
+
+ 배포된 crew는 REST API 엔드포인트를 받습니다. 모든 애플리케이션에 통합할 수 있습니다.
+ ```bash
+ curl -X POST https://app.crewai.com/api/v1/crews//kickoff \
+ -H "Authorization: Bearer $CREWAI_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{"inputs": {"topic": "AI agents"}}'
+ ```
+
+
+
+
+
+ 전체 배포 가이드 — CLI, GitHub, Crew Studio 방법.
+
+
+ 플랫폼 개요 — 프로덕션 crew에 AMP가 제공하는 것.
+
+
+
+---
+
+## 4. 엔터프라이즈 기능
+
+CrewAI AMP는 프로덕션 팀을 위해 만들어졌습니다. 배포 외에 제공되는 것은 다음과 같습니다.
+
+
+
+ 모든 crew 실행에 대한 상세 실행 추적, 로그, 성능 지표. 에이전트 결정, 도구 호출, 태스크 완료를 실시간으로 모니터링합니다.
+
+
+ 시각적으로 crew를 만들고, 맞춤 설정하고, 배포하는 노코드/로코드 인터페이스 — 코드로 보내거나 바로 배포할 수 있습니다.
+
+
+ crew 실행에서 실시간 이벤트를 시스템으로 스트리밍합니다. Slack, Zapier 등 웹훅 소비자와 연동할 수 있습니다.
+
+
+ SSO, RBAC, 조직 단위 제어. 팀 전체에서 crew 생성·배포·접근 권한을 관리합니다.
+
+
+ 조직 전체에 맞춤 도구를 게시하고 공유합니다. 레지스트리에서 커뮤니티 도구를 설치합니다.
+
+
+ 자체 인프라에서 CrewAI AMP를 실행합니다. 데이터 상주와 규정 준수 제어와 함께 플랫폼 전체 기능을 사용할 수 있습니다.
+
+
+
+
+
+ AI 에이전트 워크플로를 프로토타입에서 프로덕션으로 옮겨야 하는 팀을 위한 제품입니다. 관측 가능성, 접근 제어, 확장 가능한 인프라를 제공합니다. 스타트업이든 대기업이든 운영 복잡도는 AMP가 맡고, 에이전트 구축에 집중할 수 있습니다.
+
+
+ - **클라우드 (app.crewai.com)** — CrewAI가 관리, 프로덕션까지 가장 빠른 경로
+ - **Factory(셀프 호스팅)** — 데이터 통제를 위해 자체 인프라에서 실행
+ - **하이브리드** — 민감도에 따라 클라우드와 셀프 호스팅을 혼합
+
+
+
+
+ 가입하고 첫 crew를 프로덕션에 배포해 보세요.
+
diff --git a/docs/pt-BR/changelog.mdx b/docs/pt-BR/changelog.mdx
index 02ab715fb..4c7a0234c 100644
--- a/docs/pt-BR/changelog.mdx
+++ b/docs/pt-BR/changelog.mdx
@@ -4,6 +4,126 @@ description: "Atualizações de produto, melhorias e correções do CrewAI"
icon: "clock"
mode: "wide"
---
+
+ ## v1.14.3a3
+
+ [Ver release no GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.3a3)
+
+ ## O que Mudou
+
+ ### Recursos
+ - Adicionar suporte para e2b
+ - Implementar fallback para DefaultAzureCredential quando nenhuma chave de API for fornecida
+
+ ### Correções de Bugs
+ - Atualizar lxml para >=6.1.0 para resolver problema de segurança GHSA-vfmq-68hx-4jfw
+
+ ### Documentação
+ - Remover FAQ de preços da página build-with-ai em todos os locais
+
+ ### Desempenho
+ - Melhorar o tempo de inicialização a frio em ~29% através do carregamento preguiçoso do SDK MCP e tipos de eventos
+
+ ## Contributors
+
+ @alex-clawd, @github-advanced-security[bot], @greysonlalonde, @iris-clawd, @lorenzejay, @mattatcha
+
+
+
+
+ ## v1.14.3a2
+
+ [Ver release no GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.3a2)
+
+ ## O que mudou
+
+ ### Recursos
+ - Adicionar suporte para bedrock V4
+ - Adicionar ferramentas de sandbox Daytona para funcionalidade aprimorada
+ - Adicionar página 'Construir com IA' — documentação nativa de IA para agentes de codificação
+ - Adicionar Construir com IA à navegação Começar e arquivos de página para todos os idiomas (en, ko, pt-BR, ar)
+
+ ### Correções de Bugs
+ - Corrigir a propagação de nomes implícitos @CrewBase para eventos da equipe
+ - Resolver problema com inicialização de lote duplicada na mesclagem de metadados de execução
+ - Corrigir a serialização de campos de referência de classe Task para checkpointing
+ - Lidar com o resultado BaseModel no loop de repetição de guardrail
+ - Atualizar python-dotenv para a versão >=1.2.2 para conformidade de segurança
+
+ ### Documentação
+ - Atualizar changelog e versão para v1.14.3a1
+ - Atualizar descrições e aplicar traduções reais
+
+ ## Contributors
+
+ @MatthiasHowellYopp, @github-actions[bot], @greysonlalonde, @iris-clawd, @lorenzejay, @renatonitta
+
+
+
+
+ ## v1.14.3a1
+
+ [Ver release no GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.3a1)
+
+ ## O que Mudou
+
+ ### Funcionalidades
+ - Adicionar suporte a checkpoint e fork para agentes autônomos
+
+ ### Correções de Bugs
+ - Preservar thought_signature nas chamadas da ferramenta de streaming Gemini
+ - Emitir task_started na retomada do fork e redesenhar a TUI de checkpoint
+ - Corrigir a ordem do dry-run e lidar com branch desatualizada em release do devtools
+ - Usar datas futuras nos testes de poda de checkpoint para evitar falhas dependentes do tempo (#5543)
+
+ ### Documentação
+ - Atualizar changelog e versão para v1.14.2
+
+ ## Contribuidores
+
+ @alex-clawd, @greysonlalonde
+
+
+
+
+ ## v1.14.2
+
+ [Ver release no GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.2)
+
+ ## O que Mudou
+
+ ### Recursos
+ - Adicionar comandos de retomar, diferenciar e podar checkpoints com melhor descobribilidade.
+ - Adicionar o parâmetro `from_checkpoint` ao `Agent.kickoff` e métodos relacionados.
+ - Adicionar comandos de gerenciamento de templates para templates de projeto.
+ - Adicionar dicas de retomar na liberação de devtools em caso de falha.
+ - Adicionar CLI de validação de implantação e melhorar a ergonomia da inicialização do LLM.
+ - Adicionar bifurcação de checkpoints com rastreamento de linhagem.
+ - Enriquecer o rastreamento de tokens do LLM com tokens de raciocínio e tokens de criação de cache.
+
+ ### Correções de Bugs
+ - Corrigir prompt em conflitos de branch obsoletos na liberação de devtools.
+ - Corrigir vulnerabilidades em `authlib`, `langchain-text-splitters` e `pypdf`.
+ - Restringir manipuladores de streaming para evitar contaminação de chunks entre execuções.
+ - Despachar checkpoints de Flow através das APIs de Flow na TUI.
+ - Usar glob recursivo para descoberta de checkpoints JSON.
+ - Lidar com esquemas JSON cíclicos na resolução de ferramentas MCP.
+ - Preservar os argumentos de chamada da ferramenta Bedrock removendo o padrão truthy.
+ - Emitir evento flow_finished após retomar HITL.
+ - Corrigir várias vulnerabilidades atualizando dependências, incluindo `requests`, `cryptography` e `pytest`.
+ - Corrigir para parar de encaminhar o modo estrito para a API Bedrock Converse.
+
+ ### Documentação
+ - Documentar parâmetros ausentes e adicionar seção de Checkpointing.
+ - Atualizar changelog e versão para v1.14.2 e candidatos a liberação anteriores.
+ - Adicionar documentação da funcionalidade A2A empresarial e atualizar a documentação A2A OSS.
+
+ ## Contribuidores
+
+ @Yanhu007, @alex-clawd, @github-actions[bot], @greysonlalonde, @iris-clawd, @lorenzejay, @lucasgomide
+
+
+
## v1.14.2rc1
diff --git a/docs/pt-BR/guides/coding-tools/build-with-ai.mdx b/docs/pt-BR/guides/coding-tools/build-with-ai.mdx
new file mode 100644
index 000000000..57704aac9
--- /dev/null
+++ b/docs/pt-BR/guides/coding-tools/build-with-ai.mdx
@@ -0,0 +1,214 @@
+---
+title: "Construa com IA"
+description: "Tudo o que agentes de codificação com IA precisam para criar, implantar e escalar com CrewAI — skills, documentação legível por máquina, implantação e recursos enterprise."
+icon: robot
+mode: "wide"
+---
+
+# Construa com IA
+
+O CrewAI é nativo de IA. Esta página reúne o que um agente de codificação com IA precisa para construir com CrewAI — seja Claude Code, Codex, Cursor, Gemini CLI ou qualquer outro assistente que ajude um desenvolvedor a entregar crews e flows.
+
+### Agentes de codificação compatíveis
+
+
+
+
+
+
+
+
+
+
+ Esta página serve para humanos e para assistentes de IA. Se você é um agente de codificação, comece por **Skills** para obter contexto do CrewAI e depois use **llms.txt** para acesso completo à documentação.
+
+
+---
+
+## 1. Skills — ensine CrewAI ao seu agente
+
+**Skills** são pacotes de instruções que dão aos agentes de codificação conhecimento profundo do CrewAI — como estruturar Flows, configurar Crews, usar ferramentas e seguir convenções do framework.
+
+
+
+
+ As skills do CrewAI estão no **plugin marketplace do Claude Code** — o mesmo canal usado por empresas líderes em IA:
+ ```shell
+ /plugin marketplace add crewAIInc/skills
+ /plugin install crewai-skills@crewai-plugins
+ /reload-plugins
+ ```
+
+ Quatro skills são ativadas automaticamente quando você faz perguntas relevantes sobre CrewAI:
+
+ | Skill | Quando é usada |
+ |-------|----------------|
+ | `getting-started` | Novos projetos, escolha entre `LLM.call()` / `Agent` / `Crew` / `Flow`, arquivos `crew.py` / `main.py` |
+ | `design-agent` | Configurar agentes — papel, objetivo, história, ferramentas, LLMs, memória, guardrails |
+ | `design-task` | Descrever tarefas, dependências, saída estruturada (`output_pydantic`, `output_json`), revisão humana |
+ | `ask-docs` | Consultar o [servidor MCP da documentação CrewAI](https://docs.crewai.com/mcp) em tempo real para detalhes de API |
+
+
+ Funciona com Claude Code, Codex, Cursor, Gemini CLI ou qualquer agente de codificação:
+ ```shell
+ npx skills add crewaiinc/skills
+ ```
+ Obtido do [registro skills.sh](https://skills.sh/crewaiinc/skills).
+
+
+
+
+
+ Use um dos métodos acima — o plugin marketplace do Claude Code ou `npx skills add`. Ambos instalam o pacote oficial [crewAIInc/skills](https://github.com/crewAIInc/skills).
+
+
+ O pacote ensina ao seu agente:
+ - **Flows** — apps com estado, passos e disparo de crews
+ - **Crews e agentes** — padrões YAML-first, papéis, tarefas, delegação
+ - **Ferramentas e integrações** — busca, APIs, servidores MCP e ferramentas comuns do CrewAI
+ - **Estrutura do projeto** — scaffolds da CLI e convenções de repositório
+ - **Padrões atualizados** — alinhado à documentação e às melhores práticas atuais do CrewAI
+
+
+ Seu agente pode estruturar e construir projetos CrewAI sem você precisar reexplicar o framework a cada sessão.
+
+
+
+
+
+ Como skills funcionam em agentes CrewAI — injeção, ativação e padrões.
+
+
+ Visão geral do pacote crewAIInc/skills e do que ele inclui.
+
+
+ Configure o AGENTS.md para Claude Code, Codex, Cursor e Gemini CLI.
+
+
+ Listagem oficial — skills, estatísticas de instalação e auditorias.
+
+
+
+---
+
+## 2. llms.txt — documentação legível por máquina
+
+O CrewAI publica um arquivo `llms.txt` que dá aos assistentes de IA acesso direto à documentação completa em formato legível por máquinas.
+
+```
+https://docs.crewai.com/llms.txt
+```
+
+
+
+ [`llms.txt`](https://llmstxt.org/) é um padrão emergente para tornar a documentação consumível por grandes modelos de linguagem. Em vez de fazer scraping de HTML, seu agente pode buscar um único arquivo de texto estruturado com o conteúdo necessário.
+
+ O `llms.txt` do CrewAI **já está no ar** — seu agente pode usar agora.
+
+
+ Indique ao agente de codificação a URL quando precisar da referência do CrewAI:
+
+ ```
+ Fetch https://docs.crewai.com/llms.txt for CrewAI documentation.
+ ```
+
+ Muitos agentes (Claude Code, Cursor etc.) conseguem buscar URLs diretamente. O arquivo contém documentação estruturada sobre conceitos, APIs e guias do CrewAI.
+
+
+ - **Sem scraping** — conteúdo limpo e estruturado em uma requisição
+ - **Sempre atualizado** — servido diretamente de docs.crewai.com
+ - **Otimizado para LLMs** — formatado para janelas de contexto, não para navegadores
+ - **Complementa as skills** — skills ensinam padrões; llms.txt fornece referência
+
+
+
+---
+
+## 3. Implantação enterprise
+
+Do crew local à produção no **CrewAI AMP** (Agent Management Platform) em minutos.
+
+
+
+ Estruture e teste seu crew ou flow:
+ ```bash
+ crewai create crew my_crew
+ cd my_crew
+ crewai run
+ ```
+
+
+ Garanta que a estrutura do projeto está pronta:
+ ```bash
+ crewai deploy --prepare
+ ```
+ Veja o [guia de preparação](/pt-BR/enterprise/guides/prepare-for-deployment) para detalhes de estrutura e requisitos.
+
+
+ Envie para a plataforma CrewAI AMP:
+ ```bash
+ crewai deploy
+ ```
+ Também é possível implantar pela [integração com GitHub](/pt-BR/enterprise/guides/deploy-to-amp) ou pelo [Crew Studio](/pt-BR/enterprise/guides/enable-crew-studio).
+
+
+ O crew implantado recebe um endpoint REST. Integre em qualquer aplicação:
+ ```bash
+ curl -X POST https://app.crewai.com/api/v1/crews//kickoff \
+ -H "Authorization: Bearer $CREWAI_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{"inputs": {"topic": "AI agents"}}'
+ ```
+
+
+
+
+
+ Guia completo de implantação — CLI, GitHub e Crew Studio.
+
+
+ Visão da plataforma — o que o AMP oferece para crews em produção.
+
+
+
+---
+
+## 4. Recursos enterprise
+
+O CrewAI AMP foi feito para equipes em produção. Além da implantação, você obtém:
+
+
+
+ Traces de execução, logs e métricas de desempenho para cada execução de crew. Monitore decisões de agentes, chamadas de ferramentas e conclusão de tarefas em tempo real.
+
+
+ Interface no-code/low-code para criar, personalizar e implantar crews visualmente — exporte para código ou implante direto.
+
+
+ Transmita eventos em tempo real das execuções para seus sistemas. Integre com Slack, Zapier ou qualquer consumidor de webhook.
+
+
+ SSO, RBAC e controles em nível de organização. Gerencie quem pode criar, implantar e acessar crews.
+
+
+ Publique e compartilhe ferramentas customizadas na organização. Instale ferramentas da comunidade a partir do registro.
+
+
+ Execute o CrewAI AMP na sua infraestrutura. Capacidades completas da plataforma com residência de dados e controles de conformidade.
+
+
+
+
+
+ Para equipes que precisam levar fluxos de agentes de IA do protótipo à produção — com observabilidade, controles de acesso e infraestrutura escalável. De startups a grandes empresas, o AMP cuida da complexidade operacional para você focar nos agentes.
+
+
+ - **Nuvem (app.crewai.com)** — gerenciada pela CrewAI, caminho mais rápido para produção
+ - **Factory (self-hosted)** — na sua infraestrutura para controle total dos dados
+ - **Híbrido** — combine nuvem e self-hosted conforme a sensibilidade dos dados
+
+
+
+
+ Cadastre-se e leve seu primeiro crew à produção.
+
diff --git a/lib/crewai-files/src/crewai_files/__init__.py b/lib/crewai-files/src/crewai_files/__init__.py
index 9cfa885c2..8ed8d0053 100644
--- a/lib/crewai-files/src/crewai_files/__init__.py
+++ b/lib/crewai-files/src/crewai_files/__init__.py
@@ -152,4 +152,4 @@ __all__ = [
"wrap_file_source",
]
-__version__ = "1.14.2rc1"
+__version__ = "1.14.3a3"
diff --git a/lib/crewai-tools/pyproject.toml b/lib/crewai-tools/pyproject.toml
index 5547d96ef..40e0fb951 100644
--- a/lib/crewai-tools/pyproject.toml
+++ b/lib/crewai-tools/pyproject.toml
@@ -10,7 +10,7 @@ requires-python = ">=3.10, <3.14"
dependencies = [
"pytube~=15.0.0",
"requests>=2.33.0,<3",
- "crewai==1.14.2rc1",
+ "crewai==1.14.3a3",
"tiktoken~=0.8.0",
"beautifulsoup4~=4.13.4",
"python-docx~=1.2.0",
@@ -112,7 +112,7 @@ github = [
]
rag = [
"python-docx>=1.1.0",
- "lxml>=5.3.0,<5.4.0", # Pin to avoid etree import issues in 5.4.0
+ "lxml>=6.1.0,<7", # 6.1.0+ required for GHSA-vfmq-68hx-4jfw (XXE in iterparse)
]
xml = [
"unstructured[local-inference, all-docs]>=0.17.2"
@@ -139,6 +139,14 @@ contextual = [
"contextual-client>=0.1.0",
"nest-asyncio>=1.6.0",
]
+daytona = [
+ "daytona~=0.140.0",
+]
+
+e2b = [
+ "e2b~=2.20.0",
+ "e2b-code-interpreter~=2.6.0",
+]
[tool.uv]
diff --git a/lib/crewai-tools/src/crewai_tools/__init__.py b/lib/crewai-tools/src/crewai_tools/__init__.py
index d9ce4e9c2..af9de2437 100644
--- a/lib/crewai-tools/src/crewai_tools/__init__.py
+++ b/lib/crewai-tools/src/crewai_tools/__init__.py
@@ -59,6 +59,11 @@ from crewai_tools.tools.dalle_tool.dalle_tool import DallETool
from crewai_tools.tools.databricks_query_tool.databricks_query_tool import (
DatabricksQueryTool,
)
+from crewai_tools.tools.daytona_sandbox_tool import (
+ DaytonaExecTool,
+ DaytonaFileTool,
+ DaytonaPythonTool,
+)
from crewai_tools.tools.directory_read_tool.directory_read_tool import (
DirectoryReadTool,
)
@@ -66,6 +71,11 @@ from crewai_tools.tools.directory_search_tool.directory_search_tool import (
DirectorySearchTool,
)
from crewai_tools.tools.docx_search_tool.docx_search_tool import DOCXSearchTool
+from crewai_tools.tools.e2b_sandbox_tool import (
+ E2BExecTool,
+ E2BFileTool,
+ E2BPythonTool,
+)
from crewai_tools.tools.exa_tools.exa_search_tool import EXASearchTool
from crewai_tools.tools.file_read_tool.file_read_tool import FileReadTool
from crewai_tools.tools.file_writer_tool.file_writer_tool import FileWriterTool
@@ -232,8 +242,14 @@ __all__ = [
"DOCXSearchTool",
"DallETool",
"DatabricksQueryTool",
+ "DaytonaExecTool",
+ "DaytonaFileTool",
+ "DaytonaPythonTool",
"DirectoryReadTool",
"DirectorySearchTool",
+ "E2BExecTool",
+ "E2BFileTool",
+ "E2BPythonTool",
"EXASearchTool",
"EnterpriseActionTool",
"FileCompressorTool",
@@ -305,4 +321,4 @@ __all__ = [
"ZapierActionTools",
]
-__version__ = "1.14.2rc1"
+__version__ = "1.14.3a3"
diff --git a/lib/crewai-tools/src/crewai_tools/tools/__init__.py b/lib/crewai-tools/src/crewai_tools/tools/__init__.py
index d3c1da664..7cf61c7a3 100644
--- a/lib/crewai-tools/src/crewai_tools/tools/__init__.py
+++ b/lib/crewai-tools/src/crewai_tools/tools/__init__.py
@@ -48,6 +48,11 @@ from crewai_tools.tools.dalle_tool.dalle_tool import DallETool
from crewai_tools.tools.databricks_query_tool.databricks_query_tool import (
DatabricksQueryTool,
)
+from crewai_tools.tools.daytona_sandbox_tool import (
+ DaytonaExecTool,
+ DaytonaFileTool,
+ DaytonaPythonTool,
+)
from crewai_tools.tools.directory_read_tool.directory_read_tool import (
DirectoryReadTool,
)
@@ -55,6 +60,11 @@ from crewai_tools.tools.directory_search_tool.directory_search_tool import (
DirectorySearchTool,
)
from crewai_tools.tools.docx_search_tool.docx_search_tool import DOCXSearchTool
+from crewai_tools.tools.e2b_sandbox_tool import (
+ E2BExecTool,
+ E2BFileTool,
+ E2BPythonTool,
+)
from crewai_tools.tools.exa_tools.exa_search_tool import EXASearchTool
from crewai_tools.tools.file_read_tool.file_read_tool import FileReadTool
from crewai_tools.tools.file_writer_tool.file_writer_tool import FileWriterTool
@@ -217,8 +227,14 @@ __all__ = [
"DOCXSearchTool",
"DallETool",
"DatabricksQueryTool",
+ "DaytonaExecTool",
+ "DaytonaFileTool",
+ "DaytonaPythonTool",
"DirectoryReadTool",
"DirectorySearchTool",
+ "E2BExecTool",
+ "E2BFileTool",
+ "E2BPythonTool",
"EXASearchTool",
"FileCompressorTool",
"FileReadTool",
diff --git a/lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/README.md b/lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/README.md
new file mode 100644
index 000000000..a2365049e
--- /dev/null
+++ b/lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/README.md
@@ -0,0 +1,107 @@
+# Daytona Sandbox Tools
+
+Run shell commands, execute Python, and manage files inside a [Daytona](https://www.daytona.io/) sandbox. Daytona provides isolated, ephemeral compute environments suitable for agent-driven code execution.
+
+Three tools are provided so you can pick what the agent actually needs:
+
+- **`DaytonaExecTool`** — run a shell command (`sandbox.process.exec`).
+- **`DaytonaPythonTool`** — run a Python script (`sandbox.process.code_run`).
+- **`DaytonaFileTool`** — read / write / list / delete files (`sandbox.fs.*`).
+
+## Installation
+
+```shell
+uv add "crewai-tools[daytona]"
+# or
+pip install "crewai-tools[daytona]"
+```
+
+Set the API key:
+
+```shell
+export DAYTONA_API_KEY="..."
+```
+
+`DAYTONA_API_URL` and `DAYTONA_TARGET` are also respected if set.
+
+## Sandbox lifecycle
+
+All three tools share the same lifecycle controls from `DaytonaBaseTool`:
+
+| Mode | When the sandbox is created | When it is deleted |
+| --- | --- | --- |
+| **Ephemeral** (default, `persistent=False`) | On every `_run` call | At the end of that same call |
+| **Persistent** (`persistent=True`) | Lazily on first use | At process exit (via `atexit`), or manually via `tool.close()` |
+| **Attach** (`sandbox_id="…"`) | Never — the tool attaches to an existing sandbox | Never — the tool will not delete a sandbox it did not create |
+
+Ephemeral mode is the safe default: nothing leaks if the agent forgets to clean up. Use persistent mode when you want filesystem state or installed packages to carry across steps — this is typical when pairing `DaytonaFileTool` with `DaytonaExecTool`.
+
+## Examples
+
+### One-shot Python execution (ephemeral)
+
+```python
+from crewai_tools import DaytonaPythonTool
+
+tool = DaytonaPythonTool()
+result = tool.run(code="print(sum(range(10)))")
+```
+
+### Multi-step shell session (persistent)
+
+```python
+from crewai_tools import DaytonaExecTool, DaytonaFileTool
+
+exec_tool = DaytonaExecTool(persistent=True)
+file_tool = DaytonaFileTool(persistent=True)
+
+# Agent writes a script, then runs it — both share the same sandbox instance
+# because they each keep their own persistent sandbox. If you need the *same*
+# sandbox across two tools, create one tool, grab the sandbox id via
+# `tool._persistent_sandbox.id`, and pass it to the other via `sandbox_id=...`.
+```
+
+### Attach to an existing sandbox
+
+```python
+from crewai_tools import DaytonaExecTool
+
+tool = DaytonaExecTool(sandbox_id="my-long-lived-sandbox")
+```
+
+### Custom create params
+
+Pass Daytona's `CreateSandboxFromSnapshotParams` kwargs via `create_params`:
+
+```python
+tool = DaytonaExecTool(
+ persistent=True,
+ create_params={
+ "language": "python",
+ "env_vars": {"MY_FLAG": "1"},
+ "labels": {"owner": "crewai-agent"},
+ },
+)
+```
+
+## Tool arguments
+
+### `DaytonaExecTool`
+- `command: str` — shell command to run.
+- `cwd: str | None` — working directory.
+- `env: dict[str, str] | None` — extra env vars for this command.
+- `timeout: int | None` — seconds.
+
+### `DaytonaPythonTool`
+- `code: str` — Python source to execute.
+- `argv: list[str] | None` — argv forwarded via `CodeRunParams`.
+- `env: dict[str, str] | None` — env vars forwarded via `CodeRunParams`.
+- `timeout: int | None` — seconds.
+
+### `DaytonaFileTool`
+- `action: "read" | "write" | "list" | "delete" | "mkdir" | "info"`
+- `path: str` — absolute path inside the sandbox.
+- `content: str | None` — required for `write`.
+- `binary: bool` — if `True`, `content` is base64 on write / returned as base64 on read.
+- `recursive: bool` — for `delete`, removes directories recursively.
+- `mode: str` — for `mkdir`, octal permission string (default `"0755"`).
diff --git a/lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/__init__.py b/lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/__init__.py
new file mode 100644
index 000000000..e04396bfb
--- /dev/null
+++ b/lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/__init__.py
@@ -0,0 +1,13 @@
+from crewai_tools.tools.daytona_sandbox_tool.daytona_base_tool import DaytonaBaseTool
+from crewai_tools.tools.daytona_sandbox_tool.daytona_exec_tool import DaytonaExecTool
+from crewai_tools.tools.daytona_sandbox_tool.daytona_file_tool import DaytonaFileTool
+from crewai_tools.tools.daytona_sandbox_tool.daytona_python_tool import (
+ DaytonaPythonTool,
+)
+
+__all__ = [
+ "DaytonaBaseTool",
+ "DaytonaExecTool",
+ "DaytonaFileTool",
+ "DaytonaPythonTool",
+]
diff --git a/lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/daytona_base_tool.py b/lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/daytona_base_tool.py
new file mode 100644
index 000000000..b601e4309
--- /dev/null
+++ b/lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/daytona_base_tool.py
@@ -0,0 +1,198 @@
+from __future__ import annotations
+
+import atexit
+import logging
+import os
+import threading
+from typing import Any, ClassVar
+
+from crewai.tools import BaseTool, EnvVar
+from pydantic import ConfigDict, Field, PrivateAttr
+
+
+logger = logging.getLogger(__name__)
+
+
+class DaytonaBaseTool(BaseTool):
+ """Shared base for tools that act on a Daytona sandbox.
+
+ Lifecycle modes:
+ - persistent=False (default): create a fresh sandbox per `_run` call and
+ delete it when the call returns. Safer and stateless — nothing leaks if
+ the agent forgets cleanup.
+ - persistent=True: lazily create a single sandbox on first use, cache it
+ on the instance, and register an atexit hook to delete it at process
+ exit. Cheaper across many calls and lets files/state carry over.
+ - sandbox_id=: attach to a sandbox the caller already owns.
+ Never deleted by the tool.
+ """
+
+ model_config = ConfigDict(arbitrary_types_allowed=True)
+
+ package_dependencies: list[str] = Field(default_factory=lambda: ["daytona"])
+
+ api_key: str | None = Field(
+ default_factory=lambda: os.getenv("DAYTONA_API_KEY"),
+ description="Daytona API key. Falls back to DAYTONA_API_KEY env var.",
+ json_schema_extra={"required": False},
+ )
+ api_url: str | None = Field(
+ default_factory=lambda: os.getenv("DAYTONA_API_URL"),
+ description="Daytona API URL override. Falls back to DAYTONA_API_URL env var.",
+ json_schema_extra={"required": False},
+ )
+ target: str | None = Field(
+ default_factory=lambda: os.getenv("DAYTONA_TARGET"),
+ description="Daytona target region. Falls back to DAYTONA_TARGET env var.",
+ json_schema_extra={"required": False},
+ )
+
+ persistent: bool = Field(
+ default=False,
+ description=(
+ "If True, reuse one sandbox across all calls to this tool instance "
+ "and delete it at process exit. Default False creates and deletes a "
+ "fresh sandbox per call."
+ ),
+ )
+ sandbox_id: str | None = Field(
+ default=None,
+ description=(
+ "Attach to an existing sandbox by id or name instead of creating a "
+ "new one. The tool will never delete a sandbox it did not create."
+ ),
+ )
+ create_params: dict[str, Any] | None = Field(
+ default=None,
+ description=(
+ "Optional kwargs forwarded to CreateSandboxFromSnapshotParams when "
+ "creating a sandbox (e.g. language, snapshot, env_vars, labels)."
+ ),
+ )
+ sandbox_timeout: float = Field(
+ default=60.0,
+ description="Timeout in seconds for sandbox create/delete operations.",
+ )
+
+ env_vars: list[EnvVar] = Field(
+ default_factory=lambda: [
+ EnvVar(
+ name="DAYTONA_API_KEY",
+ description="API key for Daytona sandbox service",
+ required=False,
+ ),
+ EnvVar(
+ name="DAYTONA_API_URL",
+ description="Daytona API base URL (optional)",
+ required=False,
+ ),
+ EnvVar(
+ name="DAYTONA_TARGET",
+ description="Daytona target region (optional)",
+ required=False,
+ ),
+ ]
+ )
+
+ _client: Any | None = PrivateAttr(default=None)
+ _persistent_sandbox: Any | None = PrivateAttr(default=None)
+ _lock: threading.Lock = PrivateAttr(default_factory=threading.Lock)
+ _cleanup_registered: bool = PrivateAttr(default=False)
+
+ _sdk_cache: ClassVar[dict[str, Any]] = {}
+
+ @classmethod
+ def _import_sdk(cls) -> dict[str, Any]:
+ if cls._sdk_cache:
+ return cls._sdk_cache
+ try:
+ from daytona import (
+ CreateSandboxFromSnapshotParams,
+ Daytona,
+ DaytonaConfig,
+ )
+ except ImportError as exc:
+ raise ImportError(
+ "The 'daytona' package is required for Daytona sandbox tools. "
+ "Install it with: uv add daytona (or) pip install daytona"
+ ) from exc
+ cls._sdk_cache = {
+ "Daytona": Daytona,
+ "DaytonaConfig": DaytonaConfig,
+ "CreateSandboxFromSnapshotParams": CreateSandboxFromSnapshotParams,
+ }
+ return cls._sdk_cache
+
+ def _get_client(self) -> Any:
+ if self._client is not None:
+ return self._client
+ sdk = self._import_sdk()
+ config_kwargs: dict[str, Any] = {}
+ if self.api_key:
+ config_kwargs["api_key"] = self.api_key
+ if self.api_url:
+ config_kwargs["api_url"] = self.api_url
+ if self.target:
+ config_kwargs["target"] = self.target
+ config = sdk["DaytonaConfig"](**config_kwargs) if config_kwargs else None
+ self._client = sdk["Daytona"](config) if config else sdk["Daytona"]()
+ return self._client
+
+ def _build_create_params(self) -> Any | None:
+ if not self.create_params:
+ return None
+ sdk = self._import_sdk()
+ return sdk["CreateSandboxFromSnapshotParams"](**self.create_params)
+
+ def _acquire_sandbox(self) -> tuple[Any, bool]:
+ """Return (sandbox, should_delete_after_use)."""
+ client = self._get_client()
+
+ if self.sandbox_id:
+ return client.get(self.sandbox_id), False
+
+ if self.persistent:
+ with self._lock:
+ if self._persistent_sandbox is None:
+ self._persistent_sandbox = client.create(
+ self._build_create_params(),
+ timeout=self.sandbox_timeout,
+ )
+ if not self._cleanup_registered:
+ atexit.register(self.close)
+ self._cleanup_registered = True
+ return self._persistent_sandbox, False
+
+ sandbox = client.create(
+ self._build_create_params(),
+ timeout=self.sandbox_timeout,
+ )
+ return sandbox, True
+
+ def _release_sandbox(self, sandbox: Any, should_delete: bool) -> None:
+ if not should_delete:
+ return
+ try:
+ sandbox.delete(timeout=self.sandbox_timeout)
+ except Exception:
+ logger.debug(
+ "Best-effort sandbox cleanup failed after ephemeral use; "
+ "the sandbox may need manual deletion.",
+ exc_info=True,
+ )
+
+ def close(self) -> None:
+ """Delete the cached persistent sandbox if one exists."""
+ with self._lock:
+ sandbox = self._persistent_sandbox
+ self._persistent_sandbox = None
+ if sandbox is None:
+ return
+ try:
+ sandbox.delete(timeout=self.sandbox_timeout)
+ except Exception:
+ logger.debug(
+ "Best-effort persistent sandbox cleanup failed at close(); "
+ "the sandbox may need manual deletion.",
+ exc_info=True,
+ )
diff --git a/lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/daytona_exec_tool.py b/lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/daytona_exec_tool.py
new file mode 100644
index 000000000..cffcab220
--- /dev/null
+++ b/lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/daytona_exec_tool.py
@@ -0,0 +1,59 @@
+from __future__ import annotations
+
+from builtins import type as type_
+from typing import Any
+
+from pydantic import BaseModel, Field
+
+from crewai_tools.tools.daytona_sandbox_tool.daytona_base_tool import DaytonaBaseTool
+
+
+class DaytonaExecToolSchema(BaseModel):
+ command: str = Field(..., description="Shell command to execute in the sandbox.")
+ cwd: str | None = Field(
+ default=None,
+ description="Working directory to run the command in. Defaults to the sandbox work dir.",
+ )
+ env: dict[str, str] | None = Field(
+ default=None,
+ description="Optional environment variables to set for this command.",
+ )
+ timeout: int | None = Field(
+ default=None,
+ description="Maximum seconds to wait for the command to finish.",
+ )
+
+
+class DaytonaExecTool(DaytonaBaseTool):
+ """Run a shell command inside a Daytona sandbox."""
+
+ name: str = "Daytona Sandbox Exec"
+ description: str = (
+ "Execute a shell command inside a Daytona sandbox and return the exit "
+ "code and combined output. Use this to run builds, package installs, "
+ "git operations, or any one-off shell command."
+ )
+ args_schema: type_[BaseModel] = DaytonaExecToolSchema
+
+ def _run(
+ self,
+ command: str,
+ cwd: str | None = None,
+ env: dict[str, str] | None = None,
+ timeout: int | None = None,
+ ) -> Any:
+ sandbox, should_delete = self._acquire_sandbox()
+ try:
+ response = sandbox.process.exec(
+ command,
+ cwd=cwd,
+ env=env,
+ timeout=timeout,
+ )
+ return {
+ "exit_code": getattr(response, "exit_code", None),
+ "result": getattr(response, "result", None),
+ "artifacts": getattr(response, "artifacts", None),
+ }
+ finally:
+ self._release_sandbox(sandbox, should_delete)
diff --git a/lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/daytona_file_tool.py b/lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/daytona_file_tool.py
new file mode 100644
index 000000000..e019419b3
--- /dev/null
+++ b/lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/daytona_file_tool.py
@@ -0,0 +1,205 @@
+from __future__ import annotations
+
+import base64
+from builtins import type as type_
+import logging
+import posixpath
+from typing import Any, Literal
+
+from pydantic import BaseModel, Field, model_validator
+
+from crewai_tools.tools.daytona_sandbox_tool.daytona_base_tool import DaytonaBaseTool
+
+
+logger = logging.getLogger(__name__)
+
+
+FileAction = Literal["read", "write", "append", "list", "delete", "mkdir", "info"]
+
+
+class DaytonaFileToolSchema(BaseModel):
+ action: FileAction = Field(
+ ...,
+ description=(
+ "The filesystem action to perform: 'read' (returns file contents), "
+ "'write' (create or replace a file with content), 'append' (append "
+ "content to an existing file — use this for writing large files in "
+ "chunks to avoid hitting tool-call size limits), 'list' (lists a "
+ "directory), 'delete' (removes a file/dir), 'mkdir' (creates a "
+ "directory), 'info' (returns file metadata)."
+ ),
+ )
+ path: str = Field(..., description="Absolute path inside the sandbox.")
+ content: str | None = Field(
+ default=None,
+ description=(
+ "Content to write or append. If omitted for 'write', an empty file "
+ "is created. For files larger than a few KB, prefer one 'write' "
+ "with empty content followed by multiple 'append' calls of ~4KB "
+ "each to stay within tool-call payload limits."
+ ),
+ )
+ binary: bool = Field(
+ default=False,
+ description=(
+ "For 'write': treat content as base64 and upload raw bytes. "
+ "For 'read': return contents as base64 instead of decoded utf-8."
+ ),
+ )
+ recursive: bool = Field(
+ default=False,
+ description="For action='delete': remove directories recursively.",
+ )
+ mode: str = Field(
+ default="0755",
+ description="For action='mkdir': octal permission string (default 0755).",
+ )
+
+ @model_validator(mode="after")
+ def _validate_action_args(self) -> DaytonaFileToolSchema:
+ if self.action == "append" and self.content is None:
+ raise ValueError(
+ "action='append' requires 'content'. Pass the chunk to append "
+ "in the 'content' field."
+ )
+ return self
+
+
+class DaytonaFileTool(DaytonaBaseTool):
+ """Read, write, and manage files inside a Daytona sandbox.
+
+ Notes:
+ - Most useful with `persistent=True` or an explicit `sandbox_id`. With the
+ default ephemeral mode, files disappear when this tool call finishes.
+ """
+
+ name: str = "Daytona Sandbox Files"
+ description: str = (
+ "Perform filesystem operations inside a Daytona sandbox: read a file, "
+ "write content to a path, append content to an existing file, list a "
+ "directory, delete a path, make a directory, or fetch file metadata. "
+ "For files larger than a few KB, create the file with action='write' "
+ "and empty content, then send the body via multiple 'append' calls of "
+ "~4KB each to stay within tool-call payload limits."
+ )
+ args_schema: type_[BaseModel] = DaytonaFileToolSchema
+
+ def _run(
+ self,
+ action: FileAction,
+ path: str,
+ content: str | None = None,
+ binary: bool = False,
+ recursive: bool = False,
+ mode: str = "0755",
+ ) -> Any:
+ sandbox, should_delete = self._acquire_sandbox()
+ try:
+ if action == "read":
+ return self._read(sandbox, path, binary=binary)
+ if action == "write":
+ return self._write(sandbox, path, content or "", binary=binary)
+ if action == "append":
+ return self._append(sandbox, path, content or "", binary=binary)
+ if action == "list":
+ return self._list(sandbox, path)
+ if action == "delete":
+ sandbox.fs.delete_file(path, recursive=recursive)
+ return {"status": "deleted", "path": path}
+ if action == "mkdir":
+ sandbox.fs.create_folder(path, mode)
+ return {"status": "created", "path": path, "mode": mode}
+ if action == "info":
+ return self._info(sandbox, path)
+ raise ValueError(f"Unknown action: {action}")
+ finally:
+ self._release_sandbox(sandbox, should_delete)
+
+ def _read(self, sandbox: Any, path: str, *, binary: bool) -> dict[str, Any]:
+ data: bytes = sandbox.fs.download_file(path)
+ if binary:
+ return {
+ "path": path,
+ "encoding": "base64",
+ "content": base64.b64encode(data).decode("ascii"),
+ }
+ try:
+ return {"path": path, "encoding": "utf-8", "content": data.decode("utf-8")}
+ except UnicodeDecodeError:
+ return {
+ "path": path,
+ "encoding": "base64",
+ "content": base64.b64encode(data).decode("ascii"),
+ "note": "File was not valid utf-8; returned as base64.",
+ }
+
+ def _write(
+ self, sandbox: Any, path: str, content: str, *, binary: bool
+ ) -> dict[str, Any]:
+ payload = base64.b64decode(content) if binary else content.encode("utf-8")
+ self._ensure_parent_dir(sandbox, path)
+ sandbox.fs.upload_file(payload, path)
+ return {"status": "written", "path": path, "bytes": len(payload)}
+
+ def _append(
+ self, sandbox: Any, path: str, content: str, *, binary: bool
+ ) -> dict[str, Any]:
+ chunk = base64.b64decode(content) if binary else content.encode("utf-8")
+ self._ensure_parent_dir(sandbox, path)
+ try:
+ existing: bytes = sandbox.fs.download_file(path)
+ except Exception:
+ existing = b""
+ payload = existing + chunk
+ sandbox.fs.upload_file(payload, path)
+ return {
+ "status": "appended",
+ "path": path,
+ "appended_bytes": len(chunk),
+ "total_bytes": len(payload),
+ }
+
+ @staticmethod
+ def _ensure_parent_dir(sandbox: Any, path: str) -> None:
+ """Make sure the parent directory of `path` exists.
+
+ Daytona's upload returns 400 if the parent directory is missing. We
+ best-effort mkdir the parent; any error (e.g. already exists) is
+ swallowed because `create_folder` is not idempotent on the server.
+ """
+ parent = posixpath.dirname(path)
+ if not parent or parent in ("/", "."):
+ return
+ try:
+ sandbox.fs.create_folder(parent, "0755")
+ except Exception:
+ logger.debug(
+ "Best-effort parent-directory create failed for %s; "
+ "assuming it already exists and proceeding with the write.",
+ parent,
+ exc_info=True,
+ )
+
+ def _list(self, sandbox: Any, path: str) -> dict[str, Any]:
+ entries = sandbox.fs.list_files(path)
+ return {
+ "path": path,
+ "entries": [self._file_info_to_dict(entry) for entry in entries],
+ }
+
+ def _info(self, sandbox: Any, path: str) -> dict[str, Any]:
+ return self._file_info_to_dict(sandbox.fs.get_file_info(path))
+
+ @staticmethod
+ def _file_info_to_dict(info: Any) -> dict[str, Any]:
+ fields = (
+ "name",
+ "size",
+ "mode",
+ "permissions",
+ "is_dir",
+ "mod_time",
+ "owner",
+ "group",
+ )
+ return {field: getattr(info, field, None) for field in fields}
diff --git a/lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/daytona_python_tool.py b/lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/daytona_python_tool.py
new file mode 100644
index 000000000..c0bc9d405
--- /dev/null
+++ b/lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/daytona_python_tool.py
@@ -0,0 +1,82 @@
+from __future__ import annotations
+
+from builtins import type as type_
+from typing import Any
+
+from pydantic import BaseModel, Field
+
+from crewai_tools.tools.daytona_sandbox_tool.daytona_base_tool import DaytonaBaseTool
+
+
+class DaytonaPythonToolSchema(BaseModel):
+ code: str = Field(
+ ...,
+ description="Python source to execute inside the sandbox.",
+ )
+ argv: list[str] | None = Field(
+ default=None,
+ description="Optional argv passed to the script (forwarded as params.argv).",
+ )
+ env: dict[str, str] | None = Field(
+ default=None,
+ description="Optional environment variables for the run (forwarded as params.env).",
+ )
+ timeout: int | None = Field(
+ default=None,
+ description="Maximum seconds to wait for the code to finish.",
+ )
+
+
+class DaytonaPythonTool(DaytonaBaseTool):
+ """Run Python source inside a Daytona sandbox."""
+
+ name: str = "Daytona Sandbox Python"
+ description: str = (
+ "Execute a block of Python code inside a Daytona sandbox and return the "
+ "exit code, captured stdout, and any produced artifacts. Use this for "
+ "data processing, quick scripts, or analysis that should run in an "
+ "isolated environment."
+ )
+ args_schema: type_[BaseModel] = DaytonaPythonToolSchema
+
+ def _run(
+ self,
+ code: str,
+ argv: list[str] | None = None,
+ env: dict[str, str] | None = None,
+ timeout: int | None = None,
+ ) -> Any:
+ sandbox, should_delete = self._acquire_sandbox()
+ try:
+ params = self._build_code_run_params(argv=argv, env=env)
+ response = sandbox.process.code_run(code, params=params, timeout=timeout)
+ return {
+ "exit_code": getattr(response, "exit_code", None),
+ "result": getattr(response, "result", None),
+ "artifacts": getattr(response, "artifacts", None),
+ }
+ finally:
+ self._release_sandbox(sandbox, should_delete)
+
+ def _build_code_run_params(
+ self,
+ argv: list[str] | None,
+ env: dict[str, str] | None,
+ ) -> Any | None:
+ if argv is None and env is None:
+ return None
+ try:
+ from daytona import CodeRunParams
+ except ImportError as exc:
+ raise ImportError(
+ "Could not import daytona.CodeRunParams while building "
+ "argv/env for sandbox.process.code_run. This usually means the "
+ "installed 'daytona' SDK is too old or incompatible. Upgrade "
+ "with: pip install -U 'crewai-tools[daytona]'"
+ ) from exc
+ kwargs: dict[str, Any] = {}
+ if argv is not None:
+ kwargs["argv"] = argv
+ if env is not None:
+ kwargs["env"] = env
+ return CodeRunParams(**kwargs)
diff --git a/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/README.md b/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/README.md
new file mode 100644
index 000000000..81f30996d
--- /dev/null
+++ b/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/README.md
@@ -0,0 +1,120 @@
+# E2B Sandbox Tools
+
+Run shell commands, execute Python, and manage files inside an [E2B](https://e2b.dev/) sandbox. E2B provides isolated, ephemeral VMs suitable for agent-driven code execution, with a Jupyter-style code interpreter for rich Python results.
+
+Three tools are provided so you can pick what the agent actually needs:
+
+- **`E2BExecTool`** — run a shell command (`sandbox.commands.run`).
+- **`E2BPythonTool`** — run a Python cell in the E2B code interpreter (`sandbox.run_code`), returning stdout/stderr and rich results (charts, dataframes).
+- **`E2BFileTool`** — read / write / list / delete files (`sandbox.files.*`).
+
+## Installation
+
+```shell
+uv add "crewai-tools[e2b]"
+# or
+pip install "crewai-tools[e2b]"
+```
+
+Set the API key:
+
+```shell
+export E2B_API_KEY="..."
+```
+
+`E2B_DOMAIN` is also respected if set (for self-hosted or non-default deployments).
+
+## Sandbox lifecycle
+
+All three tools share the same lifecycle controls from `E2BBaseTool`:
+
+| Mode | When the sandbox is created | When it is killed |
+| --- | --- | --- |
+| **Ephemeral** (default, `persistent=False`) | On every `_run` call | At the end of that same call |
+| **Persistent** (`persistent=True`) | Lazily on first use | At process exit (via `atexit`), or manually via `tool.close()` |
+| **Attach** (`sandbox_id="…"`) | Never — the tool attaches to an existing sandbox | Never — the tool will not kill a sandbox it did not create |
+
+Ephemeral mode is the safe default: nothing leaks if the agent forgets to clean up. Use persistent mode when you want filesystem state or installed packages to carry across steps — this is typical when pairing `E2BFileTool` with `E2BExecTool`.
+
+E2B sandboxes also auto-expire after an idle timeout. Tune it via `sandbox_timeout` (seconds, default `300`).
+
+## Examples
+
+### One-shot Python execution (ephemeral)
+
+```python
+from crewai_tools import E2BPythonTool
+
+tool = E2BPythonTool()
+result = tool.run(code="print(sum(range(10)))")
+```
+
+### Multi-step shell session (persistent)
+
+```python
+from crewai_tools import E2BExecTool, E2BFileTool
+
+exec_tool = E2BExecTool(persistent=True)
+file_tool = E2BFileTool(persistent=True)
+
+# Each tool keeps its own persistent sandbox. If you need the *same* sandbox
+# across two tools, create one tool, grab the sandbox id via
+# `tool._persistent_sandbox.sandbox_id`, and pass it to the other via
+# `sandbox_id=...`.
+```
+
+### Attach to an existing sandbox
+
+```python
+from crewai_tools import E2BExecTool
+
+tool = E2BExecTool(sandbox_id="sbx_...")
+```
+
+### Custom create params
+
+```python
+tool = E2BExecTool(
+ persistent=True,
+ template="my-custom-template",
+ sandbox_timeout=600,
+ envs={"MY_FLAG": "1"},
+ metadata={"owner": "crewai-agent"},
+)
+```
+
+## Tool arguments
+
+### `E2BExecTool`
+- `command: str` — shell command to run.
+- `cwd: str | None` — working directory.
+- `envs: dict[str, str] | None` — extra env vars for this command.
+- `timeout: float | None` — seconds.
+
+### `E2BPythonTool`
+- `code: str` — source to execute.
+- `language: str | None` — override kernel language (default: Python).
+- `envs: dict[str, str] | None` — env vars for the run.
+- `timeout: float | None` — seconds.
+
+### `E2BFileTool`
+- `action: "read" | "write" | "append" | "list" | "delete" | "mkdir" | "info" | "exists"`
+- `path: str` — absolute path inside the sandbox.
+- `content: str | None` — required for `append`; optional for `write`.
+- `binary: bool` — if `True`, `content` is base64 on write / returned as base64 on read.
+- `depth: int` — for `list`, how many levels to recurse (default 1).
+
+## Security considerations
+
+These tools hand the LLM arbitrary shell, Python, and filesystem access inside a remote VM. The threat model to keep in mind:
+
+- **Prompt-injection is a code-execution vector.** If the agent ingests untrusted content (web pages, scraped documents, user-supplied files, emails, search results), a malicious instruction hidden in that content can coerce the agent into issuing commands to `E2BExecTool` / `E2BPythonTool`. Treat any pipeline that feeds untrusted text into an agent that also has these tools as equivalent to remote code execution — the LLM is the attacker's shell.
+- **Ephemeral mode (the default) is the main blast-radius control.** A fresh sandbox is created per call and killed at the end, so injected commands cannot persist state, exfiltrate long-lived secrets, or build up tooling across turns. Leave `persistent=False` unless you have a concrete reason to change it.
+- **Avoid this specific combination:**
+ - untrusted content in the agent's context, **plus**
+ - `persistent=True` or an explicit long-lived `sandbox_id`, **plus**
+ - a large `sandbox_timeout` or credentials/secrets seeded into the sandbox via `envs`.
+
+ That stack lets a single injection pivot into a long-running, credentialed shell that survives across turns. If you must run persistently, also keep `sandbox_timeout` short, scope `envs` to the minimum the task needs, and don't feed the same agent untrusted input.
+- **Don't mount production credentials.** Anything you put into `envs`, `metadata`, or files written to the sandbox is reachable from the LLM. Use per-task scoped keys, not your personal API tokens.
+- **E2B's VM isolation is the final backstop**, not a license to relax the above — isolation prevents escape to the host, but everything the sandbox can reach (the public internet, any service whose token you dropped in) is still fair game for an injected command.
diff --git a/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/__init__.py b/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/__init__.py
new file mode 100644
index 000000000..8bb3b26b3
--- /dev/null
+++ b/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/__init__.py
@@ -0,0 +1,12 @@
+from crewai_tools.tools.e2b_sandbox_tool.e2b_base_tool import E2BBaseTool
+from crewai_tools.tools.e2b_sandbox_tool.e2b_exec_tool import E2BExecTool
+from crewai_tools.tools.e2b_sandbox_tool.e2b_file_tool import E2BFileTool
+from crewai_tools.tools.e2b_sandbox_tool.e2b_python_tool import E2BPythonTool
+
+
+__all__ = [
+ "E2BBaseTool",
+ "E2BExecTool",
+ "E2BFileTool",
+ "E2BPythonTool",
+]
diff --git a/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_base_tool.py b/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_base_tool.py
new file mode 100644
index 000000000..e22680dfe
--- /dev/null
+++ b/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_base_tool.py
@@ -0,0 +1,197 @@
+from __future__ import annotations
+
+import atexit
+import logging
+import os
+import threading
+from typing import Any, ClassVar
+
+from crewai.tools import BaseTool, EnvVar
+from pydantic import ConfigDict, Field, PrivateAttr, SecretStr
+
+
+logger = logging.getLogger(__name__)
+
+
+class E2BBaseTool(BaseTool):
+ """Shared base for tools that act on an E2B sandbox.
+
+ Lifecycle modes:
+ - persistent=False (default): create a fresh sandbox per `_run` call and
+ kill it when the call returns. Safer and stateless — nothing leaks if
+ the agent forgets cleanup.
+ - persistent=True: lazily create a single sandbox on first use, cache it
+ on the instance, and register an atexit hook to kill it at process
+ exit. Cheaper across many calls and lets files/state carry over.
+ - sandbox_id=: attach to a sandbox the caller already owns.
+ Never killed by the tool.
+ """
+
+ model_config = ConfigDict(arbitrary_types_allowed=True)
+
+ package_dependencies: list[str] = Field(default_factory=lambda: ["e2b"])
+
+ api_key: SecretStr | None = Field(
+ default_factory=lambda: (
+ SecretStr(val) if (val := os.getenv("E2B_API_KEY")) else None
+ ),
+ description="E2B API key. Falls back to E2B_API_KEY env var.",
+ json_schema_extra={"required": False},
+ repr=False,
+ )
+ domain: str | None = Field(
+ default_factory=lambda: os.getenv("E2B_DOMAIN"),
+ description="E2B API domain override. Falls back to E2B_DOMAIN env var.",
+ json_schema_extra={"required": False},
+ )
+
+ template: str | None = Field(
+ default=None,
+ description=(
+ "Optional template/snapshot name or id to create the sandbox from. "
+ "Defaults to E2B's base template when omitted."
+ ),
+ )
+ persistent: bool = Field(
+ default=False,
+ description=(
+ "If True, reuse one sandbox across all calls to this tool instance "
+ "and kill it at process exit. Default False creates and kills a "
+ "fresh sandbox per call."
+ ),
+ )
+ sandbox_id: str | None = Field(
+ default=None,
+ description=(
+ "Attach to an existing sandbox by id instead of creating a new "
+ "one. The tool will never kill a sandbox it did not create."
+ ),
+ )
+ sandbox_timeout: int = Field(
+ default=300,
+ description=(
+ "Idle timeout in seconds after which E2B auto-kills the sandbox. "
+ "Applied at create time and when attaching via sandbox_id."
+ ),
+ )
+ envs: dict[str, str] | None = Field(
+ default=None,
+ description="Environment variables to set inside the sandbox at create time.",
+ )
+ metadata: dict[str, str] | None = Field(
+ default=None,
+ description="Metadata key-value pairs to attach to the sandbox at create time.",
+ )
+
+ env_vars: list[EnvVar] = Field(
+ default_factory=lambda: [
+ EnvVar(
+ name="E2B_API_KEY",
+ description="API key for E2B sandbox service",
+ required=False,
+ ),
+ EnvVar(
+ name="E2B_DOMAIN",
+ description="E2B API domain (optional)",
+ required=False,
+ ),
+ ]
+ )
+
+ _persistent_sandbox: Any | None = PrivateAttr(default=None)
+ _lock: threading.Lock = PrivateAttr(default_factory=threading.Lock)
+ _cleanup_registered: bool = PrivateAttr(default=False)
+
+ _sdk_cache: ClassVar[dict[str, Any]] = {}
+
+ @classmethod
+ def _import_sandbox_class(cls) -> Any:
+ """Return the Sandbox class used by this tool.
+
+ Subclasses override this to swap in a different SDK (e.g. the code
+ interpreter sandbox). The default uses plain `e2b.Sandbox`.
+ """
+ cached = cls._sdk_cache.get("e2b.Sandbox")
+ if cached is not None:
+ return cached
+ try:
+ from e2b import Sandbox # type: ignore[import-untyped]
+ except ImportError as exc:
+ raise ImportError(
+ "The 'e2b' package is required for E2B sandbox tools. "
+ "Install it with: uv add e2b (or) pip install e2b"
+ ) from exc
+ cls._sdk_cache["e2b.Sandbox"] = Sandbox
+ return Sandbox
+
+ def _connect_kwargs(self) -> dict[str, Any]:
+ kwargs: dict[str, Any] = {}
+ if self.api_key is not None:
+ kwargs["api_key"] = self.api_key.get_secret_value()
+ if self.domain:
+ kwargs["domain"] = self.domain
+ if self.sandbox_timeout is not None:
+ kwargs["timeout"] = self.sandbox_timeout
+ return kwargs
+
+ def _create_kwargs(self) -> dict[str, Any]:
+ kwargs: dict[str, Any] = self._connect_kwargs()
+ if self.template is not None:
+ kwargs["template"] = self.template
+ if self.envs is not None:
+ kwargs["envs"] = self.envs
+ if self.metadata is not None:
+ kwargs["metadata"] = self.metadata
+ return kwargs
+
+ def _acquire_sandbox(self) -> tuple[Any, bool]:
+ """Return (sandbox, should_kill_after_use)."""
+ sandbox_cls = self._import_sandbox_class()
+
+ if self.sandbox_id:
+ return (
+ sandbox_cls.connect(self.sandbox_id, **self._connect_kwargs()),
+ False,
+ )
+
+ if self.persistent:
+ with self._lock:
+ if self._persistent_sandbox is None:
+ self._persistent_sandbox = sandbox_cls.create(
+ **self._create_kwargs()
+ )
+ if not self._cleanup_registered:
+ atexit.register(self.close)
+ self._cleanup_registered = True
+ return self._persistent_sandbox, False
+
+ sandbox = sandbox_cls.create(**self._create_kwargs())
+ return sandbox, True
+
+ def _release_sandbox(self, sandbox: Any, should_kill: bool) -> None:
+ if not should_kill:
+ return
+ try:
+ sandbox.kill()
+ except Exception:
+ logger.debug(
+ "Best-effort sandbox cleanup failed after ephemeral use; "
+ "the sandbox may need manual termination.",
+ exc_info=True,
+ )
+
+ def close(self) -> None:
+ """Kill the cached persistent sandbox if one exists."""
+ with self._lock:
+ sandbox = self._persistent_sandbox
+ self._persistent_sandbox = None
+ if sandbox is None:
+ return
+ try:
+ sandbox.kill()
+ except Exception:
+ logger.debug(
+ "Best-effort persistent sandbox cleanup failed at close(); "
+ "the sandbox may need manual termination.",
+ exc_info=True,
+ )
diff --git a/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_exec_tool.py b/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_exec_tool.py
new file mode 100644
index 000000000..571be3300
--- /dev/null
+++ b/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_exec_tool.py
@@ -0,0 +1,62 @@
+from __future__ import annotations
+
+from builtins import type as type_
+from typing import Any
+
+from pydantic import BaseModel, Field
+
+from crewai_tools.tools.e2b_sandbox_tool.e2b_base_tool import E2BBaseTool
+
+
+class E2BExecToolSchema(BaseModel):
+ command: str = Field(..., description="Shell command to execute in the sandbox.")
+ cwd: str | None = Field(
+ default=None,
+ description="Working directory to run the command in. Defaults to the sandbox home dir.",
+ )
+ envs: dict[str, str] | None = Field(
+ default=None,
+ description="Optional environment variables to set for this command.",
+ )
+ timeout: float | None = Field(
+ default=None,
+ description="Maximum seconds to wait for the command to finish.",
+ )
+
+
+class E2BExecTool(E2BBaseTool):
+ """Run a shell command inside an E2B sandbox."""
+
+ name: str = "E2B Sandbox Exec"
+ description: str = (
+ "Execute a shell command inside an E2B sandbox and return the exit "
+ "code, stdout, and stderr. Use this to run builds, package installs, "
+ "git operations, or any one-off shell command."
+ )
+ args_schema: type_[BaseModel] = E2BExecToolSchema
+
+ def _run(
+ self,
+ command: str,
+ cwd: str | None = None,
+ envs: dict[str, str] | None = None,
+ timeout: float | None = None,
+ ) -> Any:
+ sandbox, should_kill = self._acquire_sandbox()
+ try:
+ run_kwargs: dict[str, Any] = {}
+ if cwd is not None:
+ run_kwargs["cwd"] = cwd
+ if envs is not None:
+ run_kwargs["envs"] = envs
+ if timeout is not None:
+ run_kwargs["timeout"] = timeout
+ result = sandbox.commands.run(command, **run_kwargs)
+ return {
+ "exit_code": getattr(result, "exit_code", None),
+ "stdout": getattr(result, "stdout", None),
+ "stderr": getattr(result, "stderr", None),
+ "error": getattr(result, "error", None),
+ }
+ finally:
+ self._release_sandbox(sandbox, should_kill)
diff --git a/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_file_tool.py b/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_file_tool.py
new file mode 100644
index 000000000..e39d348c2
--- /dev/null
+++ b/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_file_tool.py
@@ -0,0 +1,220 @@
+from __future__ import annotations
+
+import base64
+from builtins import type as type_
+import logging
+import posixpath
+from typing import Any, Literal
+
+from pydantic import BaseModel, Field, model_validator
+
+from crewai_tools.tools.e2b_sandbox_tool.e2b_base_tool import E2BBaseTool
+
+
+logger = logging.getLogger(__name__)
+
+
+FileAction = Literal[
+ "read", "write", "append", "list", "delete", "mkdir", "info", "exists"
+]
+
+
+class E2BFileToolSchema(BaseModel):
+ action: FileAction = Field(
+ ...,
+ description=(
+ "The filesystem action to perform: 'read' (returns file contents), "
+ "'write' (create or replace a file with content), 'append' (append "
+ "content to an existing file — use this for writing large files in "
+ "chunks to avoid hitting tool-call size limits), 'list' (lists a "
+ "directory), 'delete' (removes a file/dir), 'mkdir' (creates a "
+ "directory), 'info' (returns file metadata), 'exists' (returns a "
+ "boolean for whether the path exists)."
+ ),
+ )
+ path: str = Field(..., description="Absolute path inside the sandbox.")
+ content: str | None = Field(
+ default=None,
+ description=(
+ "Content to write or append. If omitted for 'write', an empty file "
+ "is created. For files larger than a few KB, prefer one 'write' "
+ "with empty content followed by multiple 'append' calls of ~4KB "
+ "each to stay within tool-call payload limits."
+ ),
+ )
+ binary: bool = Field(
+ default=False,
+ description=(
+ "For 'write'/'append': treat content as base64 and upload raw "
+ "bytes. For 'read': return contents as base64 instead of decoded "
+ "utf-8."
+ ),
+ )
+ depth: int = Field(
+ default=1,
+ description="For action='list': how many levels deep to recurse (default 1).",
+ )
+
+ @model_validator(mode="after")
+ def _validate_action_args(self) -> E2BFileToolSchema:
+ if self.action == "append" and self.content is None:
+ raise ValueError(
+ "action='append' requires 'content'. Pass the chunk to append "
+ "in the 'content' field."
+ )
+ return self
+
+
+class E2BFileTool(E2BBaseTool):
+ """Read, write, and manage files inside an E2B sandbox.
+
+ Notes:
+ - Most useful with `persistent=True` or an explicit `sandbox_id`. With
+ the default ephemeral mode, files disappear when this tool call
+ finishes.
+ """
+
+ name: str = "E2B Sandbox Files"
+ description: str = (
+ "Perform filesystem operations inside an E2B sandbox: read a file, "
+ "write content to a path, append content to an existing file, list a "
+ "directory, delete a path, make a directory, fetch file metadata, or "
+ "check whether a path exists. For files larger than a few KB, create "
+ "the file with action='write' and empty content, then send the body "
+ "via multiple 'append' calls of ~4KB each to stay within tool-call "
+ "payload limits."
+ )
+ args_schema: type_[BaseModel] = E2BFileToolSchema
+
+ def _run(
+ self,
+ action: FileAction,
+ path: str,
+ content: str | None = None,
+ binary: bool = False,
+ depth: int = 1,
+ ) -> Any:
+ sandbox, should_kill = self._acquire_sandbox()
+ try:
+ if action == "read":
+ return self._read(sandbox, path, binary=binary)
+ if action == "write":
+ return self._write(sandbox, path, content or "", binary=binary)
+ if action == "append":
+ return self._append(sandbox, path, content or "", binary=binary)
+ if action == "list":
+ return self._list(sandbox, path, depth=depth)
+ if action == "delete":
+ sandbox.files.remove(path)
+ return {"status": "deleted", "path": path}
+ if action == "mkdir":
+ created = sandbox.files.make_dir(path)
+ return {"status": "created", "path": path, "created": bool(created)}
+ if action == "info":
+ return self._info(sandbox, path)
+ if action == "exists":
+ return {"path": path, "exists": bool(sandbox.files.exists(path))}
+ raise ValueError(f"Unknown action: {action}")
+ finally:
+ self._release_sandbox(sandbox, should_kill)
+
+ def _read(self, sandbox: Any, path: str, *, binary: bool) -> dict[str, Any]:
+ if binary:
+ data: bytes = sandbox.files.read(path, format="bytes")
+ return {
+ "path": path,
+ "encoding": "base64",
+ "content": base64.b64encode(data).decode("ascii"),
+ }
+ try:
+ content: str = sandbox.files.read(path)
+ return {"path": path, "encoding": "utf-8", "content": content}
+ except UnicodeDecodeError:
+ data = sandbox.files.read(path, format="bytes")
+ return {
+ "path": path,
+ "encoding": "base64",
+ "content": base64.b64encode(data).decode("ascii"),
+ "note": "File was not valid utf-8; returned as base64.",
+ }
+
+ def _write(
+ self, sandbox: Any, path: str, content: str, *, binary: bool
+ ) -> dict[str, Any]:
+ payload: str | bytes = base64.b64decode(content) if binary else content
+ self._ensure_parent_dir(sandbox, path)
+ sandbox.files.write(path, payload)
+ size = (
+ len(payload)
+ if isinstance(payload, (bytes, bytearray))
+ else len(payload.encode("utf-8"))
+ )
+ return {"status": "written", "path": path, "bytes": size}
+
+ def _append(
+ self, sandbox: Any, path: str, content: str, *, binary: bool
+ ) -> dict[str, Any]:
+ chunk: bytes = base64.b64decode(content) if binary else content.encode("utf-8")
+ self._ensure_parent_dir(sandbox, path)
+ try:
+ existing: bytes = sandbox.files.read(path, format="bytes")
+ except Exception:
+ existing = b""
+ payload = existing + chunk
+ sandbox.files.write(path, payload)
+ return {
+ "status": "appended",
+ "path": path,
+ "appended_bytes": len(chunk),
+ "total_bytes": len(payload),
+ }
+
+ @staticmethod
+ def _ensure_parent_dir(sandbox: Any, path: str) -> None:
+ parent = posixpath.dirname(path)
+ if not parent or parent in ("/", "."):
+ return
+ try:
+ sandbox.files.make_dir(parent)
+ except Exception:
+ logger.debug(
+ "Best-effort parent-directory create failed for %s; "
+ "assuming it already exists and proceeding with the write.",
+ parent,
+ exc_info=True,
+ )
+
+ def _list(self, sandbox: Any, path: str, *, depth: int) -> dict[str, Any]:
+ entries = sandbox.files.list(path, depth=depth)
+ return {
+ "path": path,
+ "entries": [self._entry_to_dict(e) for e in entries],
+ }
+
+ def _info(self, sandbox: Any, path: str) -> dict[str, Any]:
+ return self._entry_to_dict(sandbox.files.get_info(path))
+
+ @staticmethod
+ def _entry_to_dict(entry: Any) -> dict[str, Any]:
+ fields = (
+ "name",
+ "path",
+ "type",
+ "size",
+ "mode",
+ "permissions",
+ "owner",
+ "group",
+ "modified_time",
+ "symlink_target",
+ )
+ result: dict[str, Any] = {}
+ for field in fields:
+ value = getattr(entry, field, None)
+ if value is not None and field == "modified_time":
+ result[field] = (
+ value.isoformat() if hasattr(value, "isoformat") else str(value)
+ )
+ else:
+ result[field] = value
+ return result
diff --git a/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_python_tool.py b/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_python_tool.py
new file mode 100644
index 000000000..724e92454
--- /dev/null
+++ b/lib/crewai-tools/src/crewai_tools/tools/e2b_sandbox_tool/e2b_python_tool.py
@@ -0,0 +1,133 @@
+from __future__ import annotations
+
+from builtins import type as type_
+from typing import Any, ClassVar
+
+from pydantic import BaseModel, Field
+
+from crewai_tools.tools.e2b_sandbox_tool.e2b_base_tool import E2BBaseTool
+
+
+class E2BPythonToolSchema(BaseModel):
+ code: str = Field(
+ ...,
+ description="Python source to execute inside the sandbox.",
+ )
+ language: str | None = Field(
+ default=None,
+ description=(
+ "Override the execution language (e.g. 'python', 'r', 'javascript'). "
+ "Defaults to Python when omitted."
+ ),
+ )
+ envs: dict[str, str] | None = Field(
+ default=None,
+ description="Optional environment variables for the run.",
+ )
+ timeout: float | None = Field(
+ default=None,
+ description="Maximum seconds to wait for the code to finish.",
+ )
+
+
+class E2BPythonTool(E2BBaseTool):
+ """Run Python code inside an E2B code interpreter sandbox.
+
+ Uses `e2b_code_interpreter`, which runs cells in a persistent Jupyter-style
+ kernel so state (imports, variables) carries across calls when
+ `persistent=True`.
+ """
+
+ name: str = "E2B Sandbox Python"
+ description: str = (
+ "Execute a block of Python code inside an E2B code interpreter sandbox "
+ "and return captured stdout, stderr, the final expression value, and "
+ "any rich results (charts, dataframes). Use this for data processing, "
+ "quick scripts, or analysis that should run in an isolated environment."
+ )
+ args_schema: type_[BaseModel] = E2BPythonToolSchema
+
+ package_dependencies: list[str] = Field(
+ default_factory=lambda: ["e2b_code_interpreter"],
+ )
+
+ _ci_cache: ClassVar[dict[str, Any]] = {}
+
+ @classmethod
+ def _import_sandbox_class(cls) -> Any:
+ cached = cls._ci_cache.get("Sandbox")
+ if cached is not None:
+ return cached
+ try:
+ from e2b_code_interpreter import Sandbox # type: ignore[import-untyped]
+ except ImportError as exc:
+ raise ImportError(
+ "The 'e2b_code_interpreter' package is required for the E2B "
+ "Python tool. Install it with: "
+ "uv add e2b-code-interpreter (or) "
+ "pip install e2b-code-interpreter"
+ ) from exc
+ cls._ci_cache["Sandbox"] = Sandbox
+ return Sandbox
+
+ def _run(
+ self,
+ code: str,
+ language: str | None = None,
+ envs: dict[str, str] | None = None,
+ timeout: float | None = None,
+ ) -> Any:
+ sandbox, should_kill = self._acquire_sandbox()
+ try:
+ run_kwargs: dict[str, Any] = {}
+ if language is not None:
+ run_kwargs["language"] = language
+ if envs is not None:
+ run_kwargs["envs"] = envs
+ if timeout is not None:
+ run_kwargs["timeout"] = timeout
+ execution = sandbox.run_code(code, **run_kwargs)
+ return self._serialize_execution(execution)
+ finally:
+ self._release_sandbox(sandbox, should_kill)
+
+ @staticmethod
+ def _serialize_execution(execution: Any) -> dict[str, Any]:
+ logs = getattr(execution, "logs", None)
+ error = getattr(execution, "error", None)
+ results = getattr(execution, "results", None) or []
+ return {
+ "text": getattr(execution, "text", None),
+ "stdout": list(getattr(logs, "stdout", []) or []) if logs else [],
+ "stderr": list(getattr(logs, "stderr", []) or []) if logs else [],
+ "error": (
+ {
+ "name": getattr(error, "name", None),
+ "value": getattr(error, "value", None),
+ "traceback": getattr(error, "traceback", None),
+ }
+ if error
+ else None
+ ),
+ "results": [E2BPythonTool._serialize_result(r) for r in results],
+ "execution_count": getattr(execution, "execution_count", None),
+ }
+
+ @staticmethod
+ def _serialize_result(result: Any) -> dict[str, Any]:
+ fields = (
+ "text",
+ "html",
+ "markdown",
+ "svg",
+ "png",
+ "jpeg",
+ "pdf",
+ "latex",
+ "json",
+ "javascript",
+ "data",
+ "is_main_result",
+ "extra",
+ )
+ return {field: getattr(result, field, None) for field in fields}
diff --git a/lib/crewai-tools/tool.specs.json b/lib/crewai-tools/tool.specs.json
index a00501503..c78dc2c1f 100644
--- a/lib/crewai-tools/tool.specs.json
+++ b/lib/crewai-tools/tool.specs.json
@@ -6976,6 +6976,634 @@
"type": "object"
}
},
+ {
+ "description": "Execute a shell command inside a Daytona sandbox and return the exit code and combined output. Use this to run builds, package installs, git operations, or any one-off shell command.",
+ "env_vars": [
+ {
+ "default": null,
+ "description": "API key for Daytona sandbox service",
+ "name": "DAYTONA_API_KEY",
+ "required": false
+ },
+ {
+ "default": null,
+ "description": "Daytona API base URL (optional)",
+ "name": "DAYTONA_API_URL",
+ "required": false
+ },
+ {
+ "default": null,
+ "description": "Daytona target region (optional)",
+ "name": "DAYTONA_TARGET",
+ "required": false
+ }
+ ],
+ "humanized_name": "Daytona Sandbox Exec",
+ "init_params_schema": {
+ "$defs": {
+ "EnvVar": {
+ "properties": {
+ "default": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "title": "Default"
+ },
+ "description": {
+ "title": "Description",
+ "type": "string"
+ },
+ "name": {
+ "title": "Name",
+ "type": "string"
+ },
+ "required": {
+ "default": true,
+ "title": "Required",
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "name",
+ "description"
+ ],
+ "title": "EnvVar",
+ "type": "object"
+ }
+ },
+ "description": "Run a shell command inside a Daytona sandbox.",
+ "properties": {
+ "api_key": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Daytona API key. Falls back to DAYTONA_API_KEY env var.",
+ "required": false,
+ "title": "Api Key"
+ },
+ "api_url": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Daytona API URL override. Falls back to DAYTONA_API_URL env var.",
+ "required": false,
+ "title": "Api Url"
+ },
+ "create_params": {
+ "anyOf": [
+ {
+ "additionalProperties": true,
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Optional kwargs forwarded to CreateSandboxFromSnapshotParams when creating a sandbox (e.g. language, snapshot, env_vars, labels).",
+ "title": "Create Params"
+ },
+ "persistent": {
+ "default": false,
+ "description": "If True, reuse one sandbox across all calls to this tool instance and delete it at process exit. Default False creates and deletes a fresh sandbox per call.",
+ "title": "Persistent",
+ "type": "boolean"
+ },
+ "sandbox_id": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Attach to an existing sandbox by id or name instead of creating a new one. The tool will never delete a sandbox it did not create.",
+ "title": "Sandbox Id"
+ },
+ "sandbox_timeout": {
+ "default": 60.0,
+ "description": "Timeout in seconds for sandbox create/delete operations.",
+ "title": "Sandbox Timeout",
+ "type": "number"
+ },
+ "target": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Daytona target region. Falls back to DAYTONA_TARGET env var.",
+ "required": false,
+ "title": "Target"
+ }
+ },
+ "required": [],
+ "title": "DaytonaExecTool",
+ "type": "object"
+ },
+ "name": "DaytonaExecTool",
+ "package_dependencies": [
+ "daytona"
+ ],
+ "run_params_schema": {
+ "properties": {
+ "command": {
+ "description": "Shell command to execute in the sandbox.",
+ "title": "Command",
+ "type": "string"
+ },
+ "cwd": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Working directory to run the command in. Defaults to the sandbox work dir.",
+ "title": "Cwd"
+ },
+ "env": {
+ "anyOf": [
+ {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Optional environment variables to set for this command.",
+ "title": "Env"
+ },
+ "timeout": {
+ "anyOf": [
+ {
+ "type": "integer"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Maximum seconds to wait for the command to finish.",
+ "title": "Timeout"
+ }
+ },
+ "required": [
+ "command"
+ ],
+ "title": "DaytonaExecToolSchema",
+ "type": "object"
+ }
+ },
+ {
+ "description": "Perform filesystem operations inside a Daytona sandbox: read a file, write content to a path, append content to an existing file, list a directory, delete a path, make a directory, or fetch file metadata. For files larger than a few KB, create the file with action='write' and empty content, then send the body via multiple 'append' calls of ~4KB each to stay within tool-call payload limits.",
+ "env_vars": [
+ {
+ "default": null,
+ "description": "API key for Daytona sandbox service",
+ "name": "DAYTONA_API_KEY",
+ "required": false
+ },
+ {
+ "default": null,
+ "description": "Daytona API base URL (optional)",
+ "name": "DAYTONA_API_URL",
+ "required": false
+ },
+ {
+ "default": null,
+ "description": "Daytona target region (optional)",
+ "name": "DAYTONA_TARGET",
+ "required": false
+ }
+ ],
+ "humanized_name": "Daytona Sandbox Files",
+ "init_params_schema": {
+ "$defs": {
+ "EnvVar": {
+ "properties": {
+ "default": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "title": "Default"
+ },
+ "description": {
+ "title": "Description",
+ "type": "string"
+ },
+ "name": {
+ "title": "Name",
+ "type": "string"
+ },
+ "required": {
+ "default": true,
+ "title": "Required",
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "name",
+ "description"
+ ],
+ "title": "EnvVar",
+ "type": "object"
+ }
+ },
+ "description": "Read, write, and manage files inside a Daytona sandbox.\n\nNotes:\n - Most useful with `persistent=True` or an explicit `sandbox_id`. With the\n default ephemeral mode, files disappear when this tool call finishes.",
+ "properties": {
+ "api_key": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Daytona API key. Falls back to DAYTONA_API_KEY env var.",
+ "required": false,
+ "title": "Api Key"
+ },
+ "api_url": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Daytona API URL override. Falls back to DAYTONA_API_URL env var.",
+ "required": false,
+ "title": "Api Url"
+ },
+ "create_params": {
+ "anyOf": [
+ {
+ "additionalProperties": true,
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Optional kwargs forwarded to CreateSandboxFromSnapshotParams when creating a sandbox (e.g. language, snapshot, env_vars, labels).",
+ "title": "Create Params"
+ },
+ "persistent": {
+ "default": false,
+ "description": "If True, reuse one sandbox across all calls to this tool instance and delete it at process exit. Default False creates and deletes a fresh sandbox per call.",
+ "title": "Persistent",
+ "type": "boolean"
+ },
+ "sandbox_id": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Attach to an existing sandbox by id or name instead of creating a new one. The tool will never delete a sandbox it did not create.",
+ "title": "Sandbox Id"
+ },
+ "sandbox_timeout": {
+ "default": 60.0,
+ "description": "Timeout in seconds for sandbox create/delete operations.",
+ "title": "Sandbox Timeout",
+ "type": "number"
+ },
+ "target": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Daytona target region. Falls back to DAYTONA_TARGET env var.",
+ "required": false,
+ "title": "Target"
+ }
+ },
+ "required": [],
+ "title": "DaytonaFileTool",
+ "type": "object"
+ },
+ "name": "DaytonaFileTool",
+ "package_dependencies": [
+ "daytona"
+ ],
+ "run_params_schema": {
+ "properties": {
+ "action": {
+ "description": "The filesystem action to perform: 'read' (returns file contents), 'write' (create or replace a file with content), 'append' (append content to an existing file \u2014 use this for writing large files in chunks to avoid hitting tool-call size limits), 'list' (lists a directory), 'delete' (removes a file/dir), 'mkdir' (creates a directory), 'info' (returns file metadata).",
+ "enum": [
+ "read",
+ "write",
+ "append",
+ "list",
+ "delete",
+ "mkdir",
+ "info"
+ ],
+ "title": "Action",
+ "type": "string"
+ },
+ "binary": {
+ "default": false,
+ "description": "For 'write': treat content as base64 and upload raw bytes. For 'read': return contents as base64 instead of decoded utf-8.",
+ "title": "Binary",
+ "type": "boolean"
+ },
+ "content": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Content to write or append. If omitted for 'write', an empty file is created. For files larger than a few KB, prefer one 'write' with empty content followed by multiple 'append' calls of ~4KB each to stay within tool-call payload limits.",
+ "title": "Content"
+ },
+ "mode": {
+ "default": "0755",
+ "description": "For action='mkdir': octal permission string (default 0755).",
+ "title": "Mode",
+ "type": "string"
+ },
+ "path": {
+ "description": "Absolute path inside the sandbox.",
+ "title": "Path",
+ "type": "string"
+ },
+ "recursive": {
+ "default": false,
+ "description": "For action='delete': remove directories recursively.",
+ "title": "Recursive",
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "action",
+ "path"
+ ],
+ "title": "DaytonaFileToolSchema",
+ "type": "object"
+ }
+ },
+ {
+ "description": "Execute a block of Python code inside a Daytona sandbox and return the exit code, captured stdout, and any produced artifacts. Use this for data processing, quick scripts, or analysis that should run in an isolated environment.",
+ "env_vars": [
+ {
+ "default": null,
+ "description": "API key for Daytona sandbox service",
+ "name": "DAYTONA_API_KEY",
+ "required": false
+ },
+ {
+ "default": null,
+ "description": "Daytona API base URL (optional)",
+ "name": "DAYTONA_API_URL",
+ "required": false
+ },
+ {
+ "default": null,
+ "description": "Daytona target region (optional)",
+ "name": "DAYTONA_TARGET",
+ "required": false
+ }
+ ],
+ "humanized_name": "Daytona Sandbox Python",
+ "init_params_schema": {
+ "$defs": {
+ "EnvVar": {
+ "properties": {
+ "default": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "title": "Default"
+ },
+ "description": {
+ "title": "Description",
+ "type": "string"
+ },
+ "name": {
+ "title": "Name",
+ "type": "string"
+ },
+ "required": {
+ "default": true,
+ "title": "Required",
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "name",
+ "description"
+ ],
+ "title": "EnvVar",
+ "type": "object"
+ }
+ },
+ "description": "Run Python source inside a Daytona sandbox.",
+ "properties": {
+ "api_key": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Daytona API key. Falls back to DAYTONA_API_KEY env var.",
+ "required": false,
+ "title": "Api Key"
+ },
+ "api_url": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Daytona API URL override. Falls back to DAYTONA_API_URL env var.",
+ "required": false,
+ "title": "Api Url"
+ },
+ "create_params": {
+ "anyOf": [
+ {
+ "additionalProperties": true,
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Optional kwargs forwarded to CreateSandboxFromSnapshotParams when creating a sandbox (e.g. language, snapshot, env_vars, labels).",
+ "title": "Create Params"
+ },
+ "persistent": {
+ "default": false,
+ "description": "If True, reuse one sandbox across all calls to this tool instance and delete it at process exit. Default False creates and deletes a fresh sandbox per call.",
+ "title": "Persistent",
+ "type": "boolean"
+ },
+ "sandbox_id": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Attach to an existing sandbox by id or name instead of creating a new one. The tool will never delete a sandbox it did not create.",
+ "title": "Sandbox Id"
+ },
+ "sandbox_timeout": {
+ "default": 60.0,
+ "description": "Timeout in seconds for sandbox create/delete operations.",
+ "title": "Sandbox Timeout",
+ "type": "number"
+ },
+ "target": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Daytona target region. Falls back to DAYTONA_TARGET env var.",
+ "required": false,
+ "title": "Target"
+ }
+ },
+ "required": [],
+ "title": "DaytonaPythonTool",
+ "type": "object"
+ },
+ "name": "DaytonaPythonTool",
+ "package_dependencies": [
+ "daytona"
+ ],
+ "run_params_schema": {
+ "properties": {
+ "argv": {
+ "anyOf": [
+ {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Optional argv passed to the script (forwarded as params.argv).",
+ "title": "Argv"
+ },
+ "code": {
+ "description": "Python source to execute inside the sandbox.",
+ "title": "Code",
+ "type": "string"
+ },
+ "env": {
+ "anyOf": [
+ {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Optional environment variables for the run (forwarded as params.env).",
+ "title": "Env"
+ },
+ "timeout": {
+ "anyOf": [
+ {
+ "type": "integer"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Maximum seconds to wait for the code to finish.",
+ "title": "Timeout"
+ }
+ },
+ "required": [
+ "code"
+ ],
+ "title": "DaytonaPythonToolSchema",
+ "type": "object"
+ }
+ },
{
"description": "A tool that can be used to recursively list a directory's content.",
"env_vars": [],
@@ -8106,6 +8734,668 @@
"type": "object"
}
},
+ {
+ "description": "Execute a shell command inside an E2B sandbox and return the exit code, stdout, and stderr. Use this to run builds, package installs, git operations, or any one-off shell command.",
+ "env_vars": [
+ {
+ "default": null,
+ "description": "API key for E2B sandbox service",
+ "name": "E2B_API_KEY",
+ "required": false
+ },
+ {
+ "default": null,
+ "description": "E2B API domain (optional)",
+ "name": "E2B_DOMAIN",
+ "required": false
+ }
+ ],
+ "humanized_name": "E2B Sandbox Exec",
+ "init_params_schema": {
+ "$defs": {
+ "EnvVar": {
+ "properties": {
+ "default": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "title": "Default"
+ },
+ "description": {
+ "title": "Description",
+ "type": "string"
+ },
+ "name": {
+ "title": "Name",
+ "type": "string"
+ },
+ "required": {
+ "default": true,
+ "title": "Required",
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "name",
+ "description"
+ ],
+ "title": "EnvVar",
+ "type": "object"
+ }
+ },
+ "description": "Run a shell command inside an E2B sandbox.",
+ "properties": {
+ "api_key": {
+ "anyOf": [
+ {
+ "format": "password",
+ "type": "string",
+ "writeOnly": true
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "E2B API key. Falls back to E2B_API_KEY env var.",
+ "required": false,
+ "title": "Api Key"
+ },
+ "domain": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "E2B API domain override. Falls back to E2B_DOMAIN env var.",
+ "required": false,
+ "title": "Domain"
+ },
+ "envs": {
+ "anyOf": [
+ {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Environment variables to set inside the sandbox at create time.",
+ "title": "Envs"
+ },
+ "metadata": {
+ "anyOf": [
+ {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Metadata key-value pairs to attach to the sandbox at create time.",
+ "title": "Metadata"
+ },
+ "persistent": {
+ "default": false,
+ "description": "If True, reuse one sandbox across all calls to this tool instance and kill it at process exit. Default False creates and kills a fresh sandbox per call.",
+ "title": "Persistent",
+ "type": "boolean"
+ },
+ "sandbox_id": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Attach to an existing sandbox by id instead of creating a new one. The tool will never kill a sandbox it did not create.",
+ "title": "Sandbox Id"
+ },
+ "sandbox_timeout": {
+ "default": 300,
+ "description": "Idle timeout in seconds after which E2B auto-kills the sandbox. Applied at create time and when attaching via sandbox_id.",
+ "title": "Sandbox Timeout",
+ "type": "integer"
+ },
+ "template": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Optional template/snapshot name or id to create the sandbox from. Defaults to E2B's base template when omitted.",
+ "title": "Template"
+ }
+ },
+ "required": [],
+ "title": "E2BExecTool",
+ "type": "object"
+ },
+ "name": "E2BExecTool",
+ "package_dependencies": [
+ "e2b"
+ ],
+ "run_params_schema": {
+ "properties": {
+ "command": {
+ "description": "Shell command to execute in the sandbox.",
+ "title": "Command",
+ "type": "string"
+ },
+ "cwd": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Working directory to run the command in. Defaults to the sandbox home dir.",
+ "title": "Cwd"
+ },
+ "envs": {
+ "anyOf": [
+ {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Optional environment variables to set for this command.",
+ "title": "Envs"
+ },
+ "timeout": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Maximum seconds to wait for the command to finish.",
+ "title": "Timeout"
+ }
+ },
+ "required": [
+ "command"
+ ],
+ "title": "E2BExecToolSchema",
+ "type": "object"
+ }
+ },
+ {
+ "description": "Perform filesystem operations inside an E2B sandbox: read a file, write content to a path, append content to an existing file, list a directory, delete a path, make a directory, fetch file metadata, or check whether a path exists. For files larger than a few KB, create the file with action='write' and empty content, then send the body via multiple 'append' calls of ~4KB each to stay within tool-call payload limits.",
+ "env_vars": [
+ {
+ "default": null,
+ "description": "API key for E2B sandbox service",
+ "name": "E2B_API_KEY",
+ "required": false
+ },
+ {
+ "default": null,
+ "description": "E2B API domain (optional)",
+ "name": "E2B_DOMAIN",
+ "required": false
+ }
+ ],
+ "humanized_name": "E2B Sandbox Files",
+ "init_params_schema": {
+ "$defs": {
+ "EnvVar": {
+ "properties": {
+ "default": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "title": "Default"
+ },
+ "description": {
+ "title": "Description",
+ "type": "string"
+ },
+ "name": {
+ "title": "Name",
+ "type": "string"
+ },
+ "required": {
+ "default": true,
+ "title": "Required",
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "name",
+ "description"
+ ],
+ "title": "EnvVar",
+ "type": "object"
+ }
+ },
+ "description": "Read, write, and manage files inside an E2B sandbox.\n\nNotes:\n - Most useful with `persistent=True` or an explicit `sandbox_id`. With\n the default ephemeral mode, files disappear when this tool call\n finishes.",
+ "properties": {
+ "api_key": {
+ "anyOf": [
+ {
+ "format": "password",
+ "type": "string",
+ "writeOnly": true
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "E2B API key. Falls back to E2B_API_KEY env var.",
+ "required": false,
+ "title": "Api Key"
+ },
+ "domain": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "E2B API domain override. Falls back to E2B_DOMAIN env var.",
+ "required": false,
+ "title": "Domain"
+ },
+ "envs": {
+ "anyOf": [
+ {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Environment variables to set inside the sandbox at create time.",
+ "title": "Envs"
+ },
+ "metadata": {
+ "anyOf": [
+ {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Metadata key-value pairs to attach to the sandbox at create time.",
+ "title": "Metadata"
+ },
+ "persistent": {
+ "default": false,
+ "description": "If True, reuse one sandbox across all calls to this tool instance and kill it at process exit. Default False creates and kills a fresh sandbox per call.",
+ "title": "Persistent",
+ "type": "boolean"
+ },
+ "sandbox_id": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Attach to an existing sandbox by id instead of creating a new one. The tool will never kill a sandbox it did not create.",
+ "title": "Sandbox Id"
+ },
+ "sandbox_timeout": {
+ "default": 300,
+ "description": "Idle timeout in seconds after which E2B auto-kills the sandbox. Applied at create time and when attaching via sandbox_id.",
+ "title": "Sandbox Timeout",
+ "type": "integer"
+ },
+ "template": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Optional template/snapshot name or id to create the sandbox from. Defaults to E2B's base template when omitted.",
+ "title": "Template"
+ }
+ },
+ "required": [],
+ "title": "E2BFileTool",
+ "type": "object"
+ },
+ "name": "E2BFileTool",
+ "package_dependencies": [
+ "e2b"
+ ],
+ "run_params_schema": {
+ "properties": {
+ "action": {
+ "description": "The filesystem action to perform: 'read' (returns file contents), 'write' (create or replace a file with content), 'append' (append content to an existing file \u2014 use this for writing large files in chunks to avoid hitting tool-call size limits), 'list' (lists a directory), 'delete' (removes a file/dir), 'mkdir' (creates a directory), 'info' (returns file metadata), 'exists' (returns a boolean for whether the path exists).",
+ "enum": [
+ "read",
+ "write",
+ "append",
+ "list",
+ "delete",
+ "mkdir",
+ "info",
+ "exists"
+ ],
+ "title": "Action",
+ "type": "string"
+ },
+ "binary": {
+ "default": false,
+ "description": "For 'write'/'append': treat content as base64 and upload raw bytes. For 'read': return contents as base64 instead of decoded utf-8.",
+ "title": "Binary",
+ "type": "boolean"
+ },
+ "content": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Content to write or append. If omitted for 'write', an empty file is created. For files larger than a few KB, prefer one 'write' with empty content followed by multiple 'append' calls of ~4KB each to stay within tool-call payload limits.",
+ "title": "Content"
+ },
+ "depth": {
+ "default": 1,
+ "description": "For action='list': how many levels deep to recurse (default 1).",
+ "title": "Depth",
+ "type": "integer"
+ },
+ "path": {
+ "description": "Absolute path inside the sandbox.",
+ "title": "Path",
+ "type": "string"
+ }
+ },
+ "required": [
+ "action",
+ "path"
+ ],
+ "title": "E2BFileToolSchema",
+ "type": "object"
+ }
+ },
+ {
+ "description": "Execute a block of Python code inside an E2B code interpreter sandbox and return captured stdout, stderr, the final expression value, and any rich results (charts, dataframes). Use this for data processing, quick scripts, or analysis that should run in an isolated environment.",
+ "env_vars": [
+ {
+ "default": null,
+ "description": "API key for E2B sandbox service",
+ "name": "E2B_API_KEY",
+ "required": false
+ },
+ {
+ "default": null,
+ "description": "E2B API domain (optional)",
+ "name": "E2B_DOMAIN",
+ "required": false
+ }
+ ],
+ "humanized_name": "E2B Sandbox Python",
+ "init_params_schema": {
+ "$defs": {
+ "EnvVar": {
+ "properties": {
+ "default": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "title": "Default"
+ },
+ "description": {
+ "title": "Description",
+ "type": "string"
+ },
+ "name": {
+ "title": "Name",
+ "type": "string"
+ },
+ "required": {
+ "default": true,
+ "title": "Required",
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "name",
+ "description"
+ ],
+ "title": "EnvVar",
+ "type": "object"
+ }
+ },
+ "description": "Run Python code inside an E2B code interpreter sandbox.\n\nUses `e2b_code_interpreter`, which runs cells in a persistent Jupyter-style\nkernel so state (imports, variables) carries across calls when\n`persistent=True`.",
+ "properties": {
+ "api_key": {
+ "anyOf": [
+ {
+ "format": "password",
+ "type": "string",
+ "writeOnly": true
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "E2B API key. Falls back to E2B_API_KEY env var.",
+ "required": false,
+ "title": "Api Key"
+ },
+ "domain": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "E2B API domain override. Falls back to E2B_DOMAIN env var.",
+ "required": false,
+ "title": "Domain"
+ },
+ "envs": {
+ "anyOf": [
+ {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Environment variables to set inside the sandbox at create time.",
+ "title": "Envs"
+ },
+ "metadata": {
+ "anyOf": [
+ {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Metadata key-value pairs to attach to the sandbox at create time.",
+ "title": "Metadata"
+ },
+ "persistent": {
+ "default": false,
+ "description": "If True, reuse one sandbox across all calls to this tool instance and kill it at process exit. Default False creates and kills a fresh sandbox per call.",
+ "title": "Persistent",
+ "type": "boolean"
+ },
+ "sandbox_id": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Attach to an existing sandbox by id instead of creating a new one. The tool will never kill a sandbox it did not create.",
+ "title": "Sandbox Id"
+ },
+ "sandbox_timeout": {
+ "default": 300,
+ "description": "Idle timeout in seconds after which E2B auto-kills the sandbox. Applied at create time and when attaching via sandbox_id.",
+ "title": "Sandbox Timeout",
+ "type": "integer"
+ },
+ "template": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Optional template/snapshot name or id to create the sandbox from. Defaults to E2B's base template when omitted.",
+ "title": "Template"
+ }
+ },
+ "required": [],
+ "title": "E2BPythonTool",
+ "type": "object"
+ },
+ "name": "E2BPythonTool",
+ "package_dependencies": [
+ "e2b_code_interpreter"
+ ],
+ "run_params_schema": {
+ "properties": {
+ "code": {
+ "description": "Python source to execute inside the sandbox.",
+ "title": "Code",
+ "type": "string"
+ },
+ "envs": {
+ "anyOf": [
+ {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Optional environment variables for the run.",
+ "title": "Envs"
+ },
+ "language": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Override the execution language (e.g. 'python', 'r', 'javascript'). Defaults to Python when omitted.",
+ "title": "Language"
+ },
+ "timeout": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Maximum seconds to wait for the code to finish.",
+ "title": "Timeout"
+ }
+ },
+ "required": [
+ "code"
+ ],
+ "title": "E2BPythonToolSchema",
+ "type": "object"
+ }
+ },
{
"description": "Search the internet using Exa",
"env_vars": [
diff --git a/lib/crewai/pyproject.toml b/lib/crewai/pyproject.toml
index 350e1b65f..24f01ea90 100644
--- a/lib/crewai/pyproject.toml
+++ b/lib/crewai/pyproject.toml
@@ -24,7 +24,7 @@ dependencies = [
"tokenizers>=0.21,<1",
"openpyxl~=3.1.5",
# Authentication and Security
- "python-dotenv~=1.1.1",
+ "python-dotenv>=1.2.2,<2",
"pyjwt>=2.9.0,<3",
# TUI
"textual>=7.5.0",
@@ -55,7 +55,7 @@ Repository = "https://github.com/crewAIInc/crewAI"
[project.optional-dependencies]
tools = [
- "crewai-tools==1.14.2rc1",
+ "crewai-tools==1.14.3a3",
]
embeddings = [
"tiktoken~=0.8.0"
@@ -94,6 +94,7 @@ google-genai = [
]
azure-ai-inference = [
"azure-ai-inference~=1.0.0b9",
+ "azure-identity>=1.17.0,<2",
]
anthropic = [
"anthropic~=0.73.0",
diff --git a/lib/crewai/src/crewai/__init__.py b/lib/crewai/src/crewai/__init__.py
index 97f2ca983..fe93c7751 100644
--- a/lib/crewai/src/crewai/__init__.py
+++ b/lib/crewai/src/crewai/__init__.py
@@ -1,10 +1,9 @@
-import contextvars
-import threading
-from typing import Any
-import urllib.request
+import importlib
+import sys
+from typing import TYPE_CHECKING, Annotated, Any
import warnings
-from pydantic import PydanticUserError
+from pydantic import Field, PydanticUserError
from crewai.agent.core import Agent
from crewai.agent.planning_config import PlanningConfig
@@ -20,7 +19,10 @@ from crewai.state.checkpoint_config import CheckpointConfig # noqa: F401
from crewai.task import Task
from crewai.tasks.llm_guardrail import LLMGuardrail
from crewai.tasks.task_output import TaskOutput
-from crewai.telemetry.telemetry import Telemetry
+
+
+if TYPE_CHECKING:
+ from crewai.memory.unified_memory import Memory
def _suppress_pydantic_deprecation_warnings() -> None:
@@ -46,38 +48,7 @@ def _suppress_pydantic_deprecation_warnings() -> None:
_suppress_pydantic_deprecation_warnings()
-__version__ = "1.14.2rc1"
-_telemetry_submitted = False
-
-
-def _track_install() -> None:
- """Track package installation/first-use via Scarf analytics."""
- global _telemetry_submitted
-
- if _telemetry_submitted or Telemetry._is_telemetry_disabled():
- return
-
- try:
- pixel_url = "https://api.scarf.sh/v2/packages/CrewAI/crewai/docs/00f2dad1-8334-4a39-934e-003b2e1146db"
-
- req = urllib.request.Request(pixel_url) # noqa: S310
- req.add_header("User-Agent", f"CrewAI-Python/{__version__}")
-
- with urllib.request.urlopen(req, timeout=2): # noqa: S310
- _telemetry_submitted = True
- except Exception: # noqa: S110
- pass
-
-
-def _track_install_async() -> None:
- """Track installation in background thread to avoid blocking imports."""
- if not Telemetry._is_telemetry_disabled():
- ctx = contextvars.copy_context()
- thread = threading.Thread(target=ctx.run, args=(_track_install,), daemon=True)
- thread.start()
-
-
-_track_install_async()
+__version__ = "1.14.3a3"
_LAZY_IMPORTS: dict[str, tuple[str, str]] = {
"Memory": ("crewai.memory.unified_memory", "Memory"),
@@ -89,8 +60,6 @@ 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
@@ -148,8 +117,6 @@ try:
except ImportError:
pass
- import sys
-
_full_namespace = {
**_base_namespace,
"ToolsHandler": _ToolsHandler,
@@ -192,10 +159,6 @@ try:
Flow.model_rebuild(force=True, _types_namespace=_full_namespace)
_AgentExecutor.model_rebuild(force=True, _types_namespace=_full_namespace)
- from typing import Annotated
-
- from pydantic import Field
-
from crewai.state.runtime import RuntimeState
Entity = Annotated[
diff --git a/lib/crewai/src/crewai/agent/core.py b/lib/crewai/src/crewai/agent/core.py
index b83752344..a2df8c2b9 100644
--- a/lib/crewai/src/crewai/agent/core.py
+++ b/lib/crewai/src/crewai/agent/core.py
@@ -29,7 +29,7 @@ from pydantic import (
model_validator,
)
from pydantic.functional_serializers import PlainSerializer
-from typing_extensions import Self
+from typing_extensions import Self, TypeIs
from crewai.agent.planning_config import PlanningConfig
from crewai.agent.utils import (
@@ -78,8 +78,7 @@ from crewai.knowledge.knowledge import Knowledge
from crewai.knowledge.source.base_knowledge_source import BaseKnowledgeSource
from crewai.lite_agent_output import LiteAgentOutput
from crewai.llms.base_llm import BaseLLM
-from crewai.mcp import MCPServerConfig
-from crewai.mcp.tool_resolver import MCPToolResolver
+from crewai.mcp.config import MCPServerConfig
from crewai.rag.embeddings.types import EmbedderConfig
from crewai.security.fingerprint import Fingerprint
from crewai.skills.loader import activate_skill, discover_skills
@@ -119,6 +118,7 @@ if TYPE_CHECKING:
from crewai.a2a.config import A2AClientConfig, A2AConfig, A2AServerConfig
from crewai.agents.agent_builder.base_agent import PlatformAppOrAction
+ from crewai.mcp.tool_resolver import MCPToolResolver
from crewai.task import Task
from crewai.tools.base_tool import BaseTool
from crewai.tools.structured_tool import CrewStructuredTool
@@ -133,6 +133,13 @@ _EXECUTOR_CLASS_MAP: dict[str, type] = {
}
+def _is_resuming_agent_executor(
+ executor: CrewAgentExecutor | AgentExecutor | None,
+) -> TypeIs[AgentExecutor]:
+ """Type guard: True when the executor is resuming from a checkpoint."""
+ return isinstance(executor, AgentExecutor) and executor._resuming
+
+
def _validate_executor_class(value: Any) -> Any:
if isinstance(value, str):
cls = _EXECUTOR_CLASS_MAP.get(value)
@@ -1113,6 +1120,8 @@ class Agent(BaseAgent):
Delegates to :class:`~crewai.mcp.tool_resolver.MCPToolResolver`.
"""
self._cleanup_mcp_clients()
+ from crewai.mcp.tool_resolver import MCPToolResolver
+
self._mcp_resolver = MCPToolResolver(agent=self, logger=self._logger)
return self._mcp_resolver.resolve(mcps)
@@ -1366,24 +1375,42 @@ class Agent(BaseAgent):
prompt, stop_words, rpm_limit_fn = self._build_execution_prompt(raw_tools)
- executor = AgentExecutor(
- llm=cast(BaseLLM, self.llm),
- agent=self,
- prompt=prompt,
- max_iter=self.max_iter,
- tools=parsed_tools,
- tools_names=get_tool_names(parsed_tools),
- stop_words=stop_words,
- tools_description=render_text_description_and_args(parsed_tools),
- tools_handler=self.tools_handler,
- original_tools=raw_tools,
- step_callback=self.step_callback,
- function_calling_llm=self.function_calling_llm,
- respect_context_window=self.respect_context_window,
- request_within_rpm_limit=rpm_limit_fn,
- callbacks=[TokenCalcHandler(self._token_process)],
- response_model=response_format,
- )
+ if _is_resuming_agent_executor(self.agent_executor):
+ executor = self.agent_executor
+ executor.tools = parsed_tools
+ executor.tools_names = get_tool_names(parsed_tools)
+ executor.tools_description = render_text_description_and_args(parsed_tools)
+ executor.original_tools = raw_tools
+ executor.prompt = prompt
+ executor.response_model = response_format
+ executor.stop_words = stop_words
+ executor.tools_handler = self.tools_handler
+ executor.step_callback = self.step_callback
+ executor.function_calling_llm = cast(
+ BaseLLM | None, self.function_calling_llm
+ )
+ executor.respect_context_window = self.respect_context_window
+ executor.request_within_rpm_limit = rpm_limit_fn
+ executor.callbacks = [TokenCalcHandler(self._token_process)]
+ else:
+ executor = AgentExecutor(
+ llm=cast(BaseLLM, self.llm),
+ agent=self,
+ prompt=prompt,
+ max_iter=self.max_iter,
+ tools=parsed_tools,
+ tools_names=get_tool_names(parsed_tools),
+ stop_words=stop_words,
+ tools_description=render_text_description_and_args(parsed_tools),
+ tools_handler=self.tools_handler,
+ original_tools=raw_tools,
+ step_callback=self.step_callback,
+ function_calling_llm=self.function_calling_llm,
+ respect_context_window=self.respect_context_window,
+ request_within_rpm_limit=rpm_limit_fn,
+ callbacks=[TokenCalcHandler(self._token_process)],
+ response_model=response_format,
+ )
all_files: dict[str, Any] = {}
if isinstance(messages, str):
@@ -1504,14 +1531,17 @@ class Agent(BaseAgent):
)
try:
- crewai_event_bus.emit(
- self,
- event=LiteAgentExecutionStartedEvent(
+ if self.checkpoint_kickoff_event_id is not None:
+ self._kickoff_event_id = self.checkpoint_kickoff_event_id
+ self.checkpoint_kickoff_event_id = None
+ else:
+ started_event = LiteAgentExecutionStartedEvent(
agent_info=agent_info,
tools=parsed_tools,
messages=messages,
- ),
- )
+ )
+ crewai_event_bus.emit(self, event=started_event)
+ self._kickoff_event_id = started_event.event_id
output = self._execute_and_build_output(executor, inputs, response_format)
return self._finalize_kickoff(
@@ -1808,14 +1838,17 @@ class Agent(BaseAgent):
)
try:
- crewai_event_bus.emit(
- self,
- event=LiteAgentExecutionStartedEvent(
+ if self.checkpoint_kickoff_event_id is not None:
+ self._kickoff_event_id = self.checkpoint_kickoff_event_id
+ self.checkpoint_kickoff_event_id = None
+ else:
+ started_event = LiteAgentExecutionStartedEvent(
agent_info=agent_info,
tools=parsed_tools,
messages=messages,
- ),
- )
+ )
+ crewai_event_bus.emit(self, event=started_event)
+ self._kickoff_event_id = started_event.event_id
output = await self._execute_and_build_output_async(
executor, inputs, response_format
diff --git a/lib/crewai/src/crewai/agents/agent_builder/base_agent.py b/lib/crewai/src/crewai/agents/agent_builder/base_agent.py
index a00f9b49f..74d30e0b2 100644
--- a/lib/crewai/src/crewai/agents/agent_builder/base_agent.py
+++ b/lib/crewai/src/crewai/agents/agent_builder/base_agent.py
@@ -28,6 +28,9 @@ from crewai.agents.agent_builder.base_agent_executor import BaseAgentExecutor
from crewai.agents.agent_builder.utilities.base_token_process import TokenProcess
from crewai.agents.cache.cache_handler import CacheHandler
from crewai.agents.tools_handler import ToolsHandler
+from crewai.events.base_events import set_emission_counter
+from crewai.events.event_bus import crewai_event_bus
+from crewai.events.event_context import restore_event_scope, set_last_event_id
from crewai.knowledge.knowledge import Knowledge
from crewai.knowledge.knowledge_config import KnowledgeConfig
from crewai.knowledge.source.base_knowledge_source import BaseKnowledgeSource
@@ -51,6 +54,7 @@ from crewai.utilities.string_utils import interpolate_only
if TYPE_CHECKING:
from crewai.context import ExecutionContext
from crewai.crew import Crew
+ from crewai.state.runtime import RuntimeState
def _validate_crew_ref(value: Any) -> Any:
@@ -219,6 +223,7 @@ class BaseAgent(BaseModel, ABC, metaclass=AgentMeta):
_original_goal: str | None = PrivateAttr(default=None)
_original_backstory: str | None = PrivateAttr(default=None)
_token_process: TokenProcess = PrivateAttr(default_factory=TokenProcess)
+ _kickoff_event_id: str | None = PrivateAttr(default=None)
id: UUID4 = Field(default_factory=uuid.uuid4, frozen=True)
role: str = Field(description="Role of the agent")
goal: str = Field(description="Objective of the agent")
@@ -335,30 +340,90 @@ class BaseAgent(BaseModel, ABC, metaclass=AgentMeta):
min_length=1,
)
execution_context: ExecutionContext | None = Field(default=None)
+ checkpoint_kickoff_event_id: str | None = Field(default=None)
@classmethod
def from_checkpoint(cls, config: CheckpointConfig) -> Self:
- """Restore an Agent from a checkpoint.
+ """Restore an Agent from a checkpoint, ready to resume via kickoff().
Args:
- config: Checkpoint configuration with ``restore_from`` set.
+ config: Checkpoint configuration with ``restore_from`` set to
+ the path of the checkpoint to load.
+
+ Returns:
+ An Agent instance. Call kickoff() to resume execution.
"""
from crewai.context import apply_execution_context
from crewai.state.runtime import RuntimeState
state = RuntimeState.from_checkpoint(config, context={"from_checkpoint": True})
+ crewai_event_bus.set_runtime_state(state)
for entity in state.root:
if isinstance(entity, cls):
if entity.execution_context is not None:
apply_execution_context(entity.execution_context)
- if entity.agent_executor is not None:
- entity.agent_executor.agent = entity
- entity.agent_executor._resuming = True
+ entity._restore_runtime(state)
return entity
raise ValueError(
f"No {cls.__name__} found in checkpoint: {config.restore_from}"
)
+ @classmethod
+ def fork(cls, config: CheckpointConfig, branch: str | None = None) -> Self:
+ """Fork an Agent from a checkpoint, creating a new execution branch.
+
+ Args:
+ config: Checkpoint configuration with ``restore_from`` set.
+ branch: Branch label for the fork. Auto-generated if not provided.
+
+ Returns:
+ An Agent instance on the new branch. Call kickoff() to run.
+ """
+ agent = cls.from_checkpoint(config)
+ state = crewai_event_bus._runtime_state
+ if state is None:
+ raise RuntimeError("Cannot fork: no runtime state on the event bus.")
+ state.fork(branch)
+ return agent
+
+ def _restore_runtime(self, state: RuntimeState) -> None:
+ """Re-create runtime objects after restoring from a checkpoint.
+
+ Args:
+ state: The RuntimeState containing the event record.
+ """
+ if self.agent_executor is not None:
+ self.agent_executor.agent = self
+ self.agent_executor._resuming = True
+ if self.checkpoint_kickoff_event_id is not None:
+ self._kickoff_event_id = self.checkpoint_kickoff_event_id
+ self._restore_event_scope(state)
+
+ def _restore_event_scope(self, state: RuntimeState) -> None:
+ """Rebuild the event scope stack from the checkpoint's event record.
+
+ Args:
+ state: The RuntimeState containing the event record.
+ """
+ stack: list[tuple[str, str]] = []
+ kickoff_id = self._kickoff_event_id
+ if kickoff_id:
+ stack.append((kickoff_id, "lite_agent_execution_started"))
+
+ restore_event_scope(tuple(stack))
+
+ last_event_id: str | None = None
+ max_seq = 0
+ for node in state.event_record.nodes.values():
+ seq = node.event.emission_sequence or 0
+ if seq > max_seq:
+ max_seq = seq
+ last_event_id = node.event.event_id
+ if last_event_id is not None:
+ set_last_event_id(last_event_id)
+ if max_seq > 0:
+ set_emission_counter(max_seq)
+
@model_validator(mode="before")
@classmethod
def process_model_config(cls, values: Any) -> dict[str, Any]:
diff --git a/lib/crewai/src/crewai/cli/checkpoint_cli.py b/lib/crewai/src/crewai/cli/checkpoint_cli.py
index 9db783e0e..0b3139d7d 100644
--- a/lib/crewai/src/crewai/cli/checkpoint_cli.py
+++ b/lib/crewai/src/crewai/cli/checkpoint_cli.py
@@ -106,17 +106,50 @@ def _parse_checkpoint_json(raw: str, source: str) -> dict[str, Any]:
"name": entity.get("name"),
"id": entity.get("id"),
}
+
+ raw_agents = entity.get("agents", [])
+ agents_by_id: dict[str, dict[str, Any]] = {}
+ parsed_agents: list[dict[str, Any]] = []
+ for ag in raw_agents:
+ agent_info: dict[str, Any] = {
+ "id": ag.get("id", ""),
+ "role": ag.get("role", ""),
+ "goal": ag.get("goal", ""),
+ }
+ parsed_agents.append(agent_info)
+ if ag.get("id"):
+ agents_by_id[str(ag["id"])] = agent_info
+ if parsed_agents:
+ info["agents"] = parsed_agents
+
if tasks:
info["tasks_completed"] = completed
info["tasks_total"] = len(tasks)
- info["tasks"] = [
- {
+ parsed_tasks: list[dict[str, Any]] = []
+ for t in tasks:
+ task_info: dict[str, Any] = {
"description": t.get("description", ""),
"completed": t.get("output") is not None,
"output": (t.get("output") or {}).get("raw", ""),
}
- for t in tasks
- ]
+ task_agent = t.get("agent")
+ if isinstance(task_agent, dict):
+ task_info["agent_role"] = task_agent.get("role", "")
+ task_info["agent_id"] = task_agent.get("id", "")
+ elif isinstance(task_agent, str) and task_agent in agents_by_id:
+ task_info["agent_role"] = agents_by_id[task_agent].get("role", "")
+ task_info["agent_id"] = task_agent
+ parsed_tasks.append(task_info)
+ info["tasks"] = parsed_tasks
+
+ if entity.get("entity_type") == "flow":
+ completed_methods = entity.get("checkpoint_completed_methods")
+ if completed_methods:
+ info["completed_methods"] = sorted(completed_methods)
+ state = entity.get("checkpoint_state")
+ if isinstance(state, dict):
+ info["flow_state"] = state
+
parsed_entities.append(info)
inputs: dict[str, Any] = {}
@@ -439,6 +472,8 @@ def _entity_type_from_meta(meta: dict[str, Any]) -> str:
for ent in meta.get("entities", []):
if ent.get("type") == "flow":
return "flow"
+ if ent.get("type") == "agent":
+ return "agent"
return "crew"
@@ -472,6 +507,11 @@ def resume_checkpoint(location: str, checkpoint_id: str | None) -> None:
flow = Flow.from_checkpoint(config)
result = asyncio.run(flow.kickoff_async(inputs=inputs))
+ elif entity_type == "agent":
+ from crewai.agent import Agent
+
+ agent = Agent.from_checkpoint(config)
+ result = asyncio.run(agent.akickoff(messages="Resume execution."))
else:
from crewai.crew import Crew
diff --git a/lib/crewai/src/crewai/cli/checkpoint_tui.py b/lib/crewai/src/crewai/cli/checkpoint_tui.py
index 26791af23..7cc1d6867 100644
--- a/lib/crewai/src/crewai/cli/checkpoint_tui.py
+++ b/lib/crewai/src/crewai/cli/checkpoint_tui.py
@@ -3,17 +3,20 @@
from __future__ import annotations
from collections import defaultdict
+from datetime import datetime
from typing import Any, ClassVar, Literal
from textual.app import App, ComposeResult
from textual.binding import Binding
from textual.containers import Horizontal, Vertical, VerticalScroll
from textual.widgets import (
- Button,
+ Collapsible,
Footer,
Header,
Input,
Static,
+ TabPane,
+ TabbedContent,
TextArea,
Tree,
)
@@ -32,6 +35,22 @@ _TERTIARY = "#ffffff"
_DIM = "#888888"
_BG_DARK = "#0d1117"
_BG_PANEL = "#161b22"
+_ACCENT = "#c9a227"
+_SUCCESS = "#3fb950"
+_PENDING = "#e3b341"
+
+_ENTITY_ICONS: dict[str, str] = {
+ "flow": "◆",
+ "crew": "●",
+ "agent": "◈",
+ "unknown": "○",
+}
+_ENTITY_COLORS: dict[str, str] = {
+ "flow": _ACCENT,
+ "crew": _SECONDARY,
+ "agent": _PRIMARY,
+ "unknown": _DIM,
+}
def _load_entries(location: str) -> list[dict[str, Any]]:
@@ -40,8 +59,27 @@ def _load_entries(location: str) -> list[dict[str, Any]]:
return _list_json(location)
+def _human_ts(ts: str) -> str:
+ """Turn '2026-04-17 17:05:00' into a short relative label."""
+ try:
+ dt = datetime.strptime(ts, "%Y-%m-%d %H:%M:%S")
+ except ValueError:
+ return ts
+ now = datetime.now()
+ delta = now.date() - dt.date()
+ hour = dt.hour % 12 or 12
+ ampm = "am" if dt.hour < 12 else "pm"
+ time_str = f"{hour}:{dt.minute:02d}{ampm}"
+ if delta.days == 0:
+ return time_str
+ if delta.days == 1:
+ return f"yest {time_str}"
+ if delta.days < 7:
+ return f"{dt.strftime('%a').lower()} {time_str}"
+ return f"{dt.strftime('%b')} {dt.day}"
+
+
def _short_id(name: str) -> str:
- """Shorten a checkpoint name for tree display."""
if len(name) > 30:
return name[:27] + "..."
return name
@@ -63,29 +101,29 @@ def _entry_id(entry: dict[str, Any]) -> str:
return name
-def _build_entity_header(ent: dict[str, Any]) -> str:
- """Build rich text header for an entity (progress bar only)."""
- lines: list[str] = []
- tasks = ent.get("tasks")
- if isinstance(tasks, list):
- completed = ent.get("tasks_completed", 0)
- total = ent.get("tasks_total", 0)
- pct = int(completed / total * 100) if total else 0
- bar_len = 20
- filled = int(bar_len * completed / total) if total else 0
- bar = f"[{_PRIMARY}]{'█' * filled}[/][{_DIM}]{'░' * (bar_len - filled)}[/]"
- lines.append(f"{bar} {completed}/{total} tasks ({pct}%)")
- return "\n".join(lines)
+def _build_progress_bar(completed: int, total: int, width: int = 20) -> str:
+ if total == 0:
+ return f"[{_DIM}]{'░' * width}[/] 0/0"
+ pct = int(completed / total * 100)
+ filled = int(width * completed / total)
+ color = _SUCCESS if completed == total else _PRIMARY
+ bar = f"[{color}]{'█' * filled}[/][{_DIM}]{'░' * (width - filled)}[/]"
+ return f"{bar} {completed}/{total} ({pct}%)"
+
+
+def _entity_icon(etype: str) -> str:
+ icon = _ENTITY_ICONS.get(etype, _ENTITY_ICONS["unknown"])
+ color = _ENTITY_COLORS.get(etype, _DIM)
+ return f"[{color}]{icon}[/]"
-# Return type: (location, action, inputs, task_output_overrides, entity_type)
_TuiResult = (
tuple[
str,
str,
dict[str, Any] | None,
dict[int, str] | None,
- Literal["crew", "flow"],
+ Literal["crew", "flow", "agent"],
]
| None
)
@@ -122,7 +160,7 @@ class CheckpointTUI(App[_TuiResult]):
height: 1fr;
}}
#tree-panel {{
- width: 45%;
+ width: 40%;
background: {_BG_PANEL};
border: round {_SECONDARY};
padding: 0 1;
@@ -132,41 +170,81 @@ class CheckpointTUI(App[_TuiResult]):
border: round {_PRIMARY};
}}
#detail-container {{
- width: 55%;
+ width: 60%;
height: 1fr;
}}
- #detail-scroll {{
- height: 1fr;
- background: {_BG_PANEL};
- border: round {_SECONDARY};
- padding: 1 2;
- scrollbar-color: {_PRIMARY};
- }}
- #detail-scroll:focus-within {{
- border: round {_PRIMARY};
- }}
- #detail-header {{
- margin-bottom: 1;
- }}
#status {{
height: 1;
padding: 0 2;
color: {_DIM};
}}
- #inputs-section {{
- display: none;
- height: auto;
- max-height: 8;
- padding: 0 1;
+ #detail-tabs {{
+ height: 1fr;
}}
- #inputs-section.visible {{
- display: block;
+ TabbedContent > ContentSwitcher {{
+ background: {_BG_PANEL};
+ height: 1fr;
}}
- #inputs-label {{
- height: 1;
+ TabPane {{
+ padding: 0;
+ }}
+ Tabs {{
+ background: {_BG_DARK};
+ }}
+ Tab {{
+ background: {_BG_DARK};
color: {_DIM};
+ padding: 0 2;
+ }}
+ Tab.-active {{
+ background: {_BG_PANEL};
+ color: {_PRIMARY};
+ }}
+ Tab:hover {{
+ color: {_TERTIARY};
+ }}
+ Underline > .underline--bar {{
+ color: {_SECONDARY};
+ background: {_BG_DARK};
+ }}
+ .tab-scroll {{
+ background: {_BG_PANEL};
+ height: 1fr;
+ padding: 1 2;
+ scrollbar-color: {_PRIMARY};
+ }}
+ .section-header {{
+ padding: 0 0 0 1;
+ margin: 1 0 0 0;
+ }}
+ .detail-line {{
+ padding: 0 0 0 1;
+ }}
+ .task-label {{
padding: 0 1;
}}
+ .task-output-editor {{
+ height: auto;
+ max-height: 10;
+ margin: 0 1 1 3;
+ border: round {_DIM};
+ }}
+ .task-output-editor:focus {{
+ border: round {_PRIMARY};
+ }}
+ Collapsible {{
+ background: {_BG_PANEL};
+ padding: 0;
+ margin: 0 0 1 1;
+ }}
+ CollapsibleTitle {{
+ background: {_BG_DARK};
+ color: {_TERTIARY};
+ padding: 0 1;
+ }}
+ CollapsibleTitle:hover {{
+ background: {_SECONDARY};
+ }}
.input-row {{
height: 3;
padding: 0 1;
@@ -180,55 +258,9 @@ class CheckpointTUI(App[_TuiResult]):
.input-row Input {{
width: 1fr;
}}
- #no-inputs-label {{
- height: 1;
+ .empty-state {{
color: {_DIM};
- padding: 0 1;
- }}
- #action-buttons {{
- height: 3;
- align: right middle;
- padding: 0 1;
- display: none;
- }}
- #action-buttons.visible {{
- display: block;
- }}
- #action-buttons Button {{
- margin: 0 0 0 1;
- min-width: 10;
- }}
- #btn-resume {{
- background: {_SECONDARY};
- color: {_TERTIARY};
- }}
- #btn-resume:hover {{
- background: {_PRIMARY};
- }}
- #btn-fork {{
- background: {_PRIMARY};
- color: {_TERTIARY};
- }}
- #btn-fork:hover {{
- background: {_SECONDARY};
- }}
- .entity-title {{
- padding: 1 1 0 1;
- }}
- .entity-detail {{
- padding: 0 1;
- }}
- .task-output-editor {{
- height: auto;
- max-height: 10;
- margin: 0 1 1 1;
- border: round {_DIM};
- }}
- .task-output-editor:focus {{
- border: round {_PRIMARY};
- }}
- .task-label {{
- padding: 0 1;
+ padding: 1;
}}
Tree {{
background: {_BG_PANEL};
@@ -242,6 +274,8 @@ class CheckpointTUI(App[_TuiResult]):
BINDINGS: ClassVar[list[Binding | tuple[str, str] | tuple[str, str, str]]] = [
("q", "quit", "Quit"),
("r", "refresh", "Refresh"),
+ ("e", "resume", "Resume"),
+ ("f", "fork", "Fork"),
]
def __init__(self, location: str = "./.checkpoints") -> None:
@@ -256,27 +290,49 @@ class CheckpointTUI(App[_TuiResult]):
yield Header(show_clock=False)
with Horizontal(id="main-layout"):
tree: Tree[dict[str, Any]] = Tree("Checkpoints", id="tree-panel")
- tree.show_root = True
+ tree.show_root = False
tree.guide_depth = 3
yield tree
with Vertical(id="detail-container"):
yield Static("", id="status")
- with VerticalScroll(id="detail-scroll"):
- yield Static(
- f"[{_DIM}]Select a checkpoint from the tree[/]", # noqa: S608
- id="detail-header",
- )
- with Vertical(id="inputs-section"):
- yield Static("Inputs", id="inputs-label")
- with Horizontal(id="action-buttons"):
- yield Button("Resume", id="btn-resume")
- yield Button("Fork", id="btn-fork")
+ with TabbedContent(id="detail-tabs"):
+ with TabPane("Overview", id="tab-overview"):
+ with VerticalScroll(classes="tab-scroll"):
+ yield Static(
+ f"[{_DIM}]Select a checkpoint from the tree[/]", # noqa: S608
+ id="overview-empty",
+ )
+ with TabPane("Tasks", id="tab-tasks"):
+ with VerticalScroll(classes="tab-scroll"):
+ yield Static(
+ f"[{_DIM}]Select a checkpoint to view tasks[/]",
+ id="tasks-empty",
+ )
+ with TabPane("Inputs", id="tab-inputs"):
+ with VerticalScroll(classes="tab-scroll"):
+ yield Static(
+ f"[{_DIM}]Select a checkpoint to view inputs[/]",
+ id="inputs-empty",
+ )
yield Footer()
async def on_mount(self) -> None:
self._refresh_tree()
self.query_one("#tree-panel", Tree).root.expand()
+ # ── Tree building ──────────────────────────────────────────────
+
+ @staticmethod
+ def _top_level_entity(entry: dict[str, Any]) -> tuple[str, str]:
+ etype, ename = "unknown", ""
+ for ent in entry.get("entities", []):
+ t = ent.get("type", "unknown")
+ if t == "flow":
+ return "flow", ent.get("name") or ""
+ if t == "crew" and etype != "crew":
+ etype, ename = "crew", ent.get("name") or ""
+ return etype, ename
+
def _refresh_tree(self) -> None:
self._entries = _load_entries(self._location)
self._selected_entry = None
@@ -285,45 +341,57 @@ class CheckpointTUI(App[_TuiResult]):
tree.clear()
if not self._entries:
- self.query_one("#detail-header", Static).update(
- f"[{_DIM}]No checkpoints in {self._location}[/]"
- )
- self.query_one("#status", Static).update("")
self.sub_title = self._location
+ self.query_one("#status", Static).update("")
return
- # Group by branch
- branches: dict[str, list[dict[str, Any]]] = defaultdict(list)
+ grouped: dict[tuple[str, str], dict[str, list[dict[str, Any]]]] = defaultdict(
+ lambda: defaultdict(list)
+ )
for entry in self._entries:
+ key = self._top_level_entity(entry)
branch = entry.get("branch", "main")
- branches[branch].append(entry)
-
- # Index checkpoint names to tree nodes so forks can attach
- node_by_name: dict[str, Any] = {}
+ grouped[key][branch].append(entry)
def _make_label(e: dict[str, Any]) -> str:
- name = e.get("name", "")
ts = e.get("ts") or ""
trigger = e.get("trigger") or ""
- parts = [f"[bold]{_short_id(name)}[/]"]
- if ts:
- time_part = ts.split(" ")[-1] if " " in ts else ts
+ time_part = ts.split(" ")[-1] if " " in ts else ts
+
+ total_c, total_t = 0, 0
+ for ent in e.get("entities", []):
+ c = ent.get("tasks_completed")
+ t = ent.get("tasks_total")
+ if c is not None and t is not None:
+ total_c += c
+ total_t += t
+
+ parts: list[str] = []
+ if time_part:
parts.append(f"[{_DIM}]{time_part}[/]")
if trigger:
parts.append(f"[{_PRIMARY}]{trigger}[/]")
- return " ".join(parts)
+ if total_t:
+ display_c = total_c
+ if trigger == "task_started" and total_c < total_t:
+ display_c = total_c + 1
+ color = _SUCCESS if total_c == total_t else _DIM
+ parts.append(f"[{color}]{display_c}/{total_t}[/]")
+ return " ".join(parts) if parts else _short_id(e.get("name", ""))
fork_parents: set[str] = set()
- for branch_name, entries in branches.items():
- if branch_name == "main" or not entries:
- continue
- oldest = min(entries, key=lambda e: str(e.get("name", "")))
- first_parent = oldest.get("parent_id")
- if first_parent:
- fork_parents.add(str(first_parent))
+ for branches in grouped.values():
+ for branch_name, entries in branches.items():
+ if branch_name == "main" or not entries:
+ continue
+ oldest = min(entries, key=lambda e: str(e.get("name", "")))
+ first_parent = oldest.get("parent_id")
+ if first_parent:
+ fork_parents.add(str(first_parent))
+
+ node_by_name: dict[str, Any] = {}
def _add_checkpoint(parent_node: Any, e: dict[str, Any]) -> None:
- """Add a checkpoint node — expandable only if a fork attaches to it."""
cp_id = _entry_id(e)
if cp_id in fork_parents:
node = parent_node.add(
@@ -333,67 +401,97 @@ class CheckpointTUI(App[_TuiResult]):
node = parent_node.add_leaf(_make_label(e), data=e)
node_by_name[cp_id] = node
- if "main" in branches:
- for entry in reversed(branches["main"]):
- _add_checkpoint(tree.root, entry)
+ type_order = {"flow": 0, "crew": 1}
+ sorted_keys = sorted(
+ grouped.keys(), key=lambda k: (type_order.get(k[0], 9), k[1])
+ )
+
+ for etype, ename in sorted_keys:
+ branches = grouped[(etype, ename)]
+ icon = _entity_icon(etype)
+ color = _ENTITY_COLORS.get(etype, _DIM)
+ total = sum(len(v) for v in branches.values())
+
+ label_parts = [f"{icon} [bold {color}]{etype.upper()}[/]"]
+ if ename:
+ label_parts.append(f"[bold]{ename}[/]")
+ label_parts.append(f"[{_DIM}]({total})[/]")
+ all_entries = [e for bl in branches.values() for e in bl]
+ timestamps = [str(e.get("ts", "")) for e in all_entries if e.get("ts")]
+ if timestamps:
+ latest = max(timestamps)
+ label_parts.append(f"[{_DIM}]{_human_ts(latest)}[/]")
+ entity_label = " ".join(label_parts)
+ entity_node = tree.root.add(entity_label, expand=True)
+
+ if "main" in branches:
+ for entry in reversed(branches["main"]):
+ _add_checkpoint(entity_node, entry)
+
+ fork_branches = [
+ (name, sorted(entries, key=lambda e: str(e.get("name", ""))))
+ for name, entries in branches.items()
+ if name != "main"
+ ]
+ remaining = fork_branches
+ max_passes = len(remaining) + 1
+ while remaining and max_passes > 0:
+ max_passes -= 1
+ deferred = []
+ made_progress = False
+ for branch_name, entries in remaining:
+ first_parent = entries[0].get("parent_id") if entries else None
+ if first_parent and str(first_parent) not in node_by_name:
+ deferred.append((branch_name, entries))
+ continue
+ attach_to: Any = entity_node
+ if first_parent:
+ attach_to = node_by_name.get(str(first_parent), entity_node)
+ branch_label = (
+ f"[bold {_SECONDARY}]{branch_name}[/] "
+ f"[{_DIM}]({len(entries)})[/]"
+ )
+ branch_node = attach_to.add(branch_label, expand=False)
+ for entry in entries:
+ _add_checkpoint(branch_node, entry)
+ made_progress = True
+ remaining = deferred
+ if not made_progress:
+ break
- fork_branches = [
- (name, sorted(entries, key=lambda e: str(e.get("name", ""))))
- for name, entries in branches.items()
- if name != "main"
- ]
- remaining = fork_branches
- max_passes = len(remaining) + 1
- while remaining and max_passes > 0:
- max_passes -= 1
- deferred = []
- made_progress = False
for branch_name, entries in remaining:
- first_parent = entries[0].get("parent_id") if entries else None
- if first_parent and str(first_parent) not in node_by_name:
- deferred.append((branch_name, entries))
- continue
- attach_to: Any = tree.root
- if first_parent:
- attach_to = node_by_name.get(str(first_parent), tree.root)
branch_label = (
- f"[bold {_SECONDARY}]{branch_name}[/] [{_DIM}]({len(entries)})[/]"
+ f"[bold {_SECONDARY}]{branch_name}[/] "
+ f"[{_DIM}]({len(entries)})[/] [{_DIM}](orphaned)[/]"
)
- branch_node = attach_to.add(branch_label, expand=False)
+ branch_node = entity_node.add(branch_label, expand=False)
for entry in entries:
_add_checkpoint(branch_node, entry)
- made_progress = True
- remaining = deferred
- if not made_progress:
- break
-
- for branch_name, entries in remaining:
- branch_label = (
- f"[bold {_SECONDARY}]{branch_name}[/] "
- f"[{_DIM}]({len(entries)})[/] [{_DIM}](orphaned)[/]"
- )
- branch_node = tree.root.add(branch_label, expand=False)
- for entry in entries:
- _add_checkpoint(branch_node, entry)
count = len(self._entries)
storage = "SQLite" if _is_sqlite(self._location) else "JSON"
self.sub_title = self._location
self.query_one("#status", Static).update(f" {count} checkpoint(s) | {storage}")
- async def _show_detail(self, entry: dict[str, Any]) -> None:
- """Update the detail panel for a checkpoint entry."""
- self._selected_entry = entry
- self.query_one("#action-buttons").add_class("visible")
+ # ── Detail panel ───────────────────────────────────────────────
- detail_scroll = self.query_one("#detail-scroll", VerticalScroll)
-
- # Remove all dynamic children except the header — await so IDs are freed
- to_remove = [c for c in detail_scroll.children if c.id != "detail-header"]
- for child in to_remove:
+ async def _clear_scroll(self, tab_id: str) -> VerticalScroll:
+ tab = self.query_one(f"#{tab_id}", TabPane)
+ scroll = tab.query_one(VerticalScroll)
+ for child in list(scroll.children):
await child.remove()
+ return scroll
+
+ async def _show_detail(self, entry: dict[str, Any]) -> None:
+ self._selected_entry = entry
+
+ await self._render_overview(entry)
+ await self._render_tasks(entry)
+ await self._render_inputs(entry.get("inputs", {}))
+
+ async def _render_overview(self, entry: dict[str, Any]) -> None:
+ scroll = await self._clear_scroll("tab-overview")
- # Header
name = entry.get("name", "")
ts = entry.get("ts") or "unknown"
trigger = entry.get("trigger") or ""
@@ -414,42 +512,115 @@ class CheckpointTUI(App[_TuiResult]):
header_lines.append(f" [bold]Branch[/] [{_SECONDARY}]{branch}[/]")
if parent_id:
header_lines.append(f" [bold]Parent[/] [{_DIM}]{parent_id}[/]")
- if "path" in entry:
- header_lines.append(f" [bold]Path[/] [{_DIM}]{entry['path']}[/]")
- if "db" in entry:
- header_lines.append(f" [bold]Database[/] [{_DIM}]{entry['db']}[/]")
- self.query_one("#detail-header", Static).update("\n".join(header_lines))
+ await scroll.mount(Static("\n".join(header_lines)))
+
+ for ent in entry.get("entities", []):
+ etype = ent.get("type", "unknown")
+ ename = ent.get("name", "unnamed")
+ icon = _entity_icon(etype)
+ color = _ENTITY_COLORS.get(etype, _DIM)
+
+ eid = str(ent.get("id", ""))[:8]
+ entity_title = (
+ f"\n{icon} [bold {color}]{etype.upper()}[/] [bold]{ename}[/]"
+ )
+ if eid:
+ entity_title += f" [{_DIM}]{eid}…[/]"
+ await scroll.mount(Static(entity_title, classes="section-header"))
+ await scroll.mount(Static(f"[{_DIM}]{'─' * 46}[/]", classes="detail-line"))
+
+ if etype == "flow":
+ methods = ent.get("completed_methods", [])
+ if methods:
+ method_list = ", ".join(f"[{_SUCCESS}]{m}[/]" for m in methods)
+ await scroll.mount(
+ Static(
+ f" [bold]Methods[/] {method_list}",
+ classes="detail-line",
+ )
+ )
+ flow_state = ent.get("flow_state")
+ if isinstance(flow_state, dict) and flow_state:
+ state_parts: list[str] = []
+ for k, v in list(flow_state.items())[:5]:
+ sv = str(v)
+ if len(sv) > 40:
+ sv = sv[:37] + "..."
+ state_parts.append(f"[{_DIM}]{k}[/]={sv}")
+ await scroll.mount(
+ Static(
+ f" [bold]State[/] {', '.join(state_parts)}",
+ classes="detail-line",
+ )
+ )
+
+ agents = ent.get("agents", [])
+ if agents:
+ agent_lines: list[Static] = []
+ for ag in agents:
+ role = ag.get("role", "unnamed")
+ goal = ag.get("goal", "")
+ if len(goal) > 60:
+ goal = goal[:57] + "..."
+ agent_line = f" {_entity_icon('agent')} [bold]{role}[/]"
+ if goal:
+ agent_line += f"\n [{_DIM}]{goal}[/]"
+ agent_lines.append(Static(agent_line))
+
+ collapsible = Collapsible(
+ *agent_lines,
+ title=f"Agents ({len(agents)})",
+ collapsed=len(agents) > 3,
+ )
+ await scroll.mount(collapsible)
+
+ async def _render_tasks(self, entry: dict[str, Any]) -> None:
+ scroll = await self._clear_scroll("tab-tasks")
- # Entity details and editable task outputs — mounted flat for scrolling
self._task_output_ids = []
flat_task_idx = 0
+ has_tasks = False
+
for ent_idx, ent in enumerate(entry.get("entities", [])):
etype = ent.get("type", "unknown")
ename = ent.get("name", "unnamed")
- completed = ent.get("tasks_completed")
- total = ent.get("tasks_total")
- entity_title = f"[bold {_SECONDARY}]{etype}: {ename}[/]"
- if completed is not None and total is not None:
- entity_title += f" [{_DIM}]{completed}/{total} tasks[/]"
- await detail_scroll.mount(Static(entity_title, classes="entity-title"))
- await detail_scroll.mount(
- Static(_build_entity_header(ent), classes="entity-detail")
- )
+ icon = _entity_icon(etype)
+ color = _ENTITY_COLORS.get(etype, _DIM)
tasks = ent.get("tasks", [])
+ if not tasks:
+ continue
+ has_tasks = True
+
+ completed = ent.get("tasks_completed", 0)
+ total = ent.get("tasks_total", 0)
+
+ await scroll.mount(
+ Static(
+ f"{icon} [bold {color}]{ename}[/] "
+ f"{_build_progress_bar(completed, total, width=16)}",
+ classes="section-header",
+ )
+ )
+
for i, task in enumerate(tasks):
desc = str(task.get("description", ""))
- if len(desc) > 55:
- desc = desc[:52] + "..."
+ if len(desc) > 50:
+ desc = desc[:47] + "..."
+ agent_role = task.get("agent_role", "")
+
if task.get("completed"):
- icon = "[green]✓[/]"
- await detail_scroll.mount(
- Static(f" {icon} {i + 1}. {desc}", classes="task-label")
- )
+ status_icon = f"[{_SUCCESS}]✓[/]"
+ task_line = f" {status_icon} {i + 1}. {desc}"
+ if agent_role:
+ task_line += (
+ f" [{_DIM}]→ {_entity_icon('agent')} {agent_role}[/]"
+ )
+ await scroll.mount(Static(task_line, classes="task-label"))
output_text = task.get("output", "")
editor_id = f"task-output-{ent_idx}-{i}"
- await detail_scroll.mount(
+ await scroll.mount(
TextArea(
str(output_text),
classes="task-output-editor",
@@ -460,28 +631,25 @@ class CheckpointTUI(App[_TuiResult]):
(flat_task_idx, editor_id, str(output_text))
)
else:
- icon = "[yellow]○[/]"
- await detail_scroll.mount(
- Static(f" {icon} {i + 1}. {desc}", classes="task-label")
- )
+ status_icon = f"[{_PENDING}]○[/]"
+ task_line = f" {status_icon} {i + 1}. {desc}"
+ if agent_role:
+ task_line += (
+ f" [{_DIM}]→ {_entity_icon('agent')} {agent_role}[/]"
+ )
+ await scroll.mount(Static(task_line, classes="task-label"))
flat_task_idx += 1
- # Build input fields
- await self._build_input_fields(entry.get("inputs", {}))
+ if not has_tasks:
+ await scroll.mount(Static(f"[{_DIM}]No tasks[/]", classes="empty-state"))
- async def _build_input_fields(self, inputs: dict[str, Any]) -> None:
- """Rebuild the inputs section with one field per input key."""
- section = self.query_one("#inputs-section")
-
- # Remove old dynamic children — await so IDs are freed
- for widget in list(section.query(".input-row, .no-inputs")):
- await widget.remove()
+ async def _render_inputs(self, inputs: dict[str, Any]) -> None:
+ scroll = await self._clear_scroll("tab-inputs")
self._input_keys = []
if not inputs:
- await section.mount(Static(f"[{_DIM}]No inputs[/]", classes="no-inputs"))
- section.add_class("visible")
+ await scroll.mount(Static(f"[{_DIM}]No inputs[/]", classes="empty-state"))
return
for key, value in inputs.items():
@@ -491,12 +659,11 @@ class CheckpointTUI(App[_TuiResult]):
row.compose_add_child(
Input(value=str(value), placeholder=key, id=f"input-{key}")
)
- await section.mount(row)
+ await scroll.mount(row)
- section.add_class("visible")
+ # ── Data collection ────────────────────────────────────────────
def _collect_inputs(self) -> dict[str, Any] | None:
- """Collect current values from input fields."""
if not self._input_keys:
return None
result: dict[str, Any] = {}
@@ -506,7 +673,6 @@ class CheckpointTUI(App[_TuiResult]):
return result
def _collect_task_overrides(self) -> dict[int, str] | None:
- """Collect edited task outputs. Returns only changed values."""
if not self._task_output_ids or self._selected_entry is None:
return None
overrides: dict[int, str] = {}
@@ -516,38 +682,48 @@ class CheckpointTUI(App[_TuiResult]):
overrides[task_idx] = editor.text
return overrides or None
- def _detect_entity_type(self, entry: dict[str, Any]) -> Literal["crew", "flow"]:
- """Infer the top-level entity type from checkpoint entities."""
+ def _detect_entity_type(
+ self, entry: dict[str, Any]
+ ) -> Literal["crew", "flow", "agent"]:
for ent in entry.get("entities", []):
if ent.get("type") == "flow":
return "flow"
+ if ent.get("type") == "agent":
+ return "agent"
return "crew"
def _resolve_location(self, entry: dict[str, Any]) -> str:
- """Get the restore location string for a checkpoint entry."""
if "path" in entry:
return str(entry["path"])
if _is_sqlite(self._location):
return f"{self._location}#{entry['name']}"
return str(entry.get("name", ""))
+ # ── Events ─────────────────────────────────────────────────────
+
async def on_tree_node_highlighted(
self, event: Tree.NodeHighlighted[dict[str, Any]]
) -> None:
if event.node.data is not None:
await self._show_detail(event.node.data)
- def on_button_pressed(self, event: Button.Pressed) -> None:
+ def _exit_with_action(self, action: str) -> None:
if self._selected_entry is None:
+ self.notify("No checkpoint selected", severity="warning")
return
inputs = self._collect_inputs()
overrides = self._collect_task_overrides()
loc = self._resolve_location(self._selected_entry)
etype = self._detect_entity_type(self._selected_entry)
- if event.button.id == "btn-resume":
- self.exit((loc, "resume", inputs, overrides, etype))
- elif event.button.id == "btn-fork":
- self.exit((loc, "fork", inputs, overrides, etype))
+ name = self._selected_entry.get("name", "")[:30]
+ self.notify(f"{action.title()}: {name}")
+ self.exit((loc, action, inputs, overrides, etype))
+
+ def action_resume(self) -> None:
+ self._exit_with_action("resume")
+
+ def action_fork(self) -> None:
+ self._exit_with_action("fork")
def action_refresh(self) -> None:
self._refresh_tree()
@@ -657,6 +833,21 @@ async def _run_checkpoint_tui_async(location: str) -> None:
click.echo(f"\nResult: {getattr(result, 'raw', result)}")
return
+ if entity_type == "agent":
+ from crewai.agent import Agent
+
+ if action == "fork":
+ click.echo(f"\nForking agent from: {selected}\n")
+ agent = Agent.fork(config)
+ else:
+ click.echo(f"\nResuming agent from: {selected}\n")
+ agent = Agent.from_checkpoint(config)
+
+ click.echo()
+ result = await agent.akickoff(messages="Resume execution.")
+ click.echo(f"\nResult: {getattr(result, 'raw', result)}")
+ return
+
from crewai.crew import Crew
if action == "fork":
diff --git a/lib/crewai/src/crewai/cli/templates/crew/pyproject.toml b/lib/crewai/src/crewai/cli/templates/crew/pyproject.toml
index 01ce3f12b..65225c0fb 100644
--- a/lib/crewai/src/crewai/cli/templates/crew/pyproject.toml
+++ b/lib/crewai/src/crewai/cli/templates/crew/pyproject.toml
@@ -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.14.2rc1"
+ "crewai[tools]==1.14.3a3"
]
[project.scripts]
diff --git a/lib/crewai/src/crewai/cli/templates/flow/pyproject.toml b/lib/crewai/src/crewai/cli/templates/flow/pyproject.toml
index b91fcbaf1..0b0760f5d 100644
--- a/lib/crewai/src/crewai/cli/templates/flow/pyproject.toml
+++ b/lib/crewai/src/crewai/cli/templates/flow/pyproject.toml
@@ -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.14.2rc1"
+ "crewai[tools]==1.14.3a3"
]
[project.scripts]
diff --git a/lib/crewai/src/crewai/cli/templates/tool/pyproject.toml b/lib/crewai/src/crewai/cli/templates/tool/pyproject.toml
index 1089ad5c0..4dd6b344c 100644
--- a/lib/crewai/src/crewai/cli/templates/tool/pyproject.toml
+++ b/lib/crewai/src/crewai/cli/templates/tool/pyproject.toml
@@ -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.14.2rc1"
+ "crewai[tools]==1.14.3a3"
]
[tool.crewai]
diff --git a/lib/crewai/src/crewai/crew.py b/lib/crewai/src/crewai/crew.py
index de9a8f73d..7631a4c2b 100644
--- a/lib/crewai/src/crewai/crew.py
+++ b/lib/crewai/src/crewai/crew.py
@@ -419,10 +419,32 @@ class Crew(FlowTrackable, BaseModel):
def _restore_runtime(self) -> None:
"""Re-create runtime objects after restoring from a checkpoint."""
+ from crewai.events.event_bus import crewai_event_bus
+
+ started_task_ids: set[str] = set()
+ state = crewai_event_bus._runtime_state
+ if state is not None:
+ for node in state.event_record.nodes.values():
+ if node.event.type == "task_started" and node.event.task_id:
+ started_task_ids.add(node.event.task_id)
+
+ resuming_task_agent_roles: set[str] = set()
+ for task in self.tasks:
+ if (
+ task.output is None
+ and task.agent is not None
+ and str(task.id) in started_task_ids
+ ):
+ resuming_task_agent_roles.add(task.agent.role)
+
for agent in self.agents:
agent.crew = self
executor = agent.agent_executor
- if executor and executor.messages:
+ if (
+ executor
+ and executor.messages
+ and agent.role in resuming_task_agent_roles
+ ):
executor.crew = self
executor.agent = agent
executor._resuming = True
diff --git a/lib/crewai/src/crewai/events/__init__.py b/lib/crewai/src/crewai/events/__init__.py
index bcdafe49a..a9c02a243 100644
--- a/lib/crewai/src/crewai/events/__init__.py
+++ b/lib/crewai/src/crewai/events/__init__.py
@@ -6,112 +6,20 @@ This module provides the event infrastructure that allows users to:
- Build custom logging and analytics
- Extend CrewAI with custom event handlers
- Declare handler dependencies for ordered execution
+
+Event type classes are lazy-loaded on first access to avoid importing
+~12 Pydantic model modules (and their transitive deps) at package init time.
"""
from __future__ import annotations
+import importlib
from typing import TYPE_CHECKING, Any
from crewai.events.base_event_listener import BaseEventListener
from crewai.events.depends import Depends
from crewai.events.event_bus import crewai_event_bus
from crewai.events.handler_graph import CircularDependencyError
-from crewai.events.types.crew_events import (
- CrewKickoffCompletedEvent,
- CrewKickoffFailedEvent,
- CrewKickoffStartedEvent,
- CrewTestCompletedEvent,
- CrewTestFailedEvent,
- CrewTestResultEvent,
- CrewTestStartedEvent,
- CrewTrainCompletedEvent,
- CrewTrainFailedEvent,
- CrewTrainStartedEvent,
-)
-from crewai.events.types.flow_events import (
- FlowCreatedEvent,
- FlowEvent,
- FlowFinishedEvent,
- FlowPlotEvent,
- FlowStartedEvent,
- HumanFeedbackReceivedEvent,
- HumanFeedbackRequestedEvent,
- MethodExecutionFailedEvent,
- MethodExecutionFinishedEvent,
- MethodExecutionStartedEvent,
-)
-from crewai.events.types.knowledge_events import (
- KnowledgeQueryCompletedEvent,
- KnowledgeQueryFailedEvent,
- KnowledgeQueryStartedEvent,
- KnowledgeRetrievalCompletedEvent,
- KnowledgeRetrievalStartedEvent,
- KnowledgeSearchQueryFailedEvent,
-)
-from crewai.events.types.llm_events import (
- LLMCallCompletedEvent,
- LLMCallFailedEvent,
- LLMCallStartedEvent,
- LLMStreamChunkEvent,
-)
-from crewai.events.types.llm_guardrail_events import (
- LLMGuardrailCompletedEvent,
- LLMGuardrailStartedEvent,
-)
-from crewai.events.types.logging_events import (
- AgentLogsExecutionEvent,
- AgentLogsStartedEvent,
-)
-from crewai.events.types.mcp_events import (
- MCPConfigFetchFailedEvent,
- MCPConnectionCompletedEvent,
- MCPConnectionFailedEvent,
- MCPConnectionStartedEvent,
- MCPToolExecutionCompletedEvent,
- MCPToolExecutionFailedEvent,
- MCPToolExecutionStartedEvent,
-)
-from crewai.events.types.memory_events import (
- MemoryQueryCompletedEvent,
- MemoryQueryFailedEvent,
- MemoryQueryStartedEvent,
- MemoryRetrievalCompletedEvent,
- MemoryRetrievalFailedEvent,
- MemoryRetrievalStartedEvent,
- MemorySaveCompletedEvent,
- MemorySaveFailedEvent,
- MemorySaveStartedEvent,
-)
-from crewai.events.types.reasoning_events import (
- AgentReasoningCompletedEvent,
- AgentReasoningFailedEvent,
- AgentReasoningStartedEvent,
- ReasoningEvent,
-)
-from crewai.events.types.skill_events import (
- SkillActivatedEvent,
- SkillDiscoveryCompletedEvent,
- SkillDiscoveryStartedEvent,
- SkillEvent,
- SkillLoadFailedEvent,
- SkillLoadedEvent,
-)
-from crewai.events.types.task_events import (
- TaskCompletedEvent,
- TaskEvaluationEvent,
- TaskFailedEvent,
- TaskStartedEvent,
-)
-from crewai.events.types.tool_usage_events import (
- ToolExecutionErrorEvent,
- ToolSelectionErrorEvent,
- ToolUsageErrorEvent,
- ToolUsageEvent,
- ToolUsageFinishedEvent,
- ToolUsageStartedEvent,
- ToolValidateInputErrorEvent,
-)
-
if TYPE_CHECKING:
from crewai.events.types.agent_events import (
@@ -125,6 +33,223 @@ if TYPE_CHECKING:
LiteAgentExecutionErrorEvent,
LiteAgentExecutionStartedEvent,
)
+ from crewai.events.types.crew_events import (
+ CrewKickoffCompletedEvent,
+ CrewKickoffFailedEvent,
+ CrewKickoffStartedEvent,
+ CrewTestCompletedEvent,
+ CrewTestFailedEvent,
+ CrewTestResultEvent,
+ CrewTestStartedEvent,
+ CrewTrainCompletedEvent,
+ CrewTrainFailedEvent,
+ CrewTrainStartedEvent,
+ )
+ from crewai.events.types.flow_events import (
+ FlowCreatedEvent,
+ FlowEvent,
+ FlowFinishedEvent,
+ FlowPlotEvent,
+ FlowStartedEvent,
+ HumanFeedbackReceivedEvent,
+ HumanFeedbackRequestedEvent,
+ MethodExecutionFailedEvent,
+ MethodExecutionFinishedEvent,
+ MethodExecutionStartedEvent,
+ )
+ from crewai.events.types.knowledge_events import (
+ KnowledgeQueryCompletedEvent,
+ KnowledgeQueryFailedEvent,
+ KnowledgeQueryStartedEvent,
+ KnowledgeRetrievalCompletedEvent,
+ KnowledgeRetrievalStartedEvent,
+ KnowledgeSearchQueryFailedEvent,
+ )
+ from crewai.events.types.llm_events import (
+ LLMCallCompletedEvent,
+ LLMCallFailedEvent,
+ LLMCallStartedEvent,
+ LLMStreamChunkEvent,
+ )
+ from crewai.events.types.llm_guardrail_events import (
+ LLMGuardrailCompletedEvent,
+ LLMGuardrailStartedEvent,
+ )
+ from crewai.events.types.logging_events import (
+ AgentLogsExecutionEvent,
+ AgentLogsStartedEvent,
+ )
+ from crewai.events.types.mcp_events import (
+ MCPConfigFetchFailedEvent,
+ MCPConnectionCompletedEvent,
+ MCPConnectionFailedEvent,
+ MCPConnectionStartedEvent,
+ MCPToolExecutionCompletedEvent,
+ MCPToolExecutionFailedEvent,
+ MCPToolExecutionStartedEvent,
+ )
+ from crewai.events.types.memory_events import (
+ MemoryQueryCompletedEvent,
+ MemoryQueryFailedEvent,
+ MemoryQueryStartedEvent,
+ MemoryRetrievalCompletedEvent,
+ MemoryRetrievalFailedEvent,
+ MemoryRetrievalStartedEvent,
+ MemorySaveCompletedEvent,
+ MemorySaveFailedEvent,
+ MemorySaveStartedEvent,
+ )
+ from crewai.events.types.reasoning_events import (
+ AgentReasoningCompletedEvent,
+ AgentReasoningFailedEvent,
+ AgentReasoningStartedEvent,
+ ReasoningEvent,
+ )
+ from crewai.events.types.skill_events import (
+ SkillActivatedEvent,
+ SkillDiscoveryCompletedEvent,
+ SkillDiscoveryStartedEvent,
+ SkillEvent,
+ SkillLoadFailedEvent,
+ SkillLoadedEvent,
+ )
+ from crewai.events.types.task_events import (
+ TaskCompletedEvent,
+ TaskEvaluationEvent,
+ TaskFailedEvent,
+ TaskStartedEvent,
+ )
+ from crewai.events.types.tool_usage_events import (
+ ToolExecutionErrorEvent,
+ ToolSelectionErrorEvent,
+ ToolUsageErrorEvent,
+ ToolUsageEvent,
+ ToolUsageFinishedEvent,
+ ToolUsageStartedEvent,
+ ToolValidateInputErrorEvent,
+ )
+
+# Map every event class name → its module path for lazy loading
+_LAZY_EVENT_MAPPING: dict[str, str] = {
+ # agent_events
+ "AgentEvaluationCompletedEvent": "crewai.events.types.agent_events",
+ "AgentEvaluationFailedEvent": "crewai.events.types.agent_events",
+ "AgentEvaluationStartedEvent": "crewai.events.types.agent_events",
+ "AgentExecutionCompletedEvent": "crewai.events.types.agent_events",
+ "AgentExecutionErrorEvent": "crewai.events.types.agent_events",
+ "AgentExecutionStartedEvent": "crewai.events.types.agent_events",
+ "LiteAgentExecutionCompletedEvent": "crewai.events.types.agent_events",
+ "LiteAgentExecutionErrorEvent": "crewai.events.types.agent_events",
+ "LiteAgentExecutionStartedEvent": "crewai.events.types.agent_events",
+ # crew_events
+ "CrewKickoffCompletedEvent": "crewai.events.types.crew_events",
+ "CrewKickoffFailedEvent": "crewai.events.types.crew_events",
+ "CrewKickoffStartedEvent": "crewai.events.types.crew_events",
+ "CrewTestCompletedEvent": "crewai.events.types.crew_events",
+ "CrewTestFailedEvent": "crewai.events.types.crew_events",
+ "CrewTestResultEvent": "crewai.events.types.crew_events",
+ "CrewTestStartedEvent": "crewai.events.types.crew_events",
+ "CrewTrainCompletedEvent": "crewai.events.types.crew_events",
+ "CrewTrainFailedEvent": "crewai.events.types.crew_events",
+ "CrewTrainStartedEvent": "crewai.events.types.crew_events",
+ # flow_events
+ "FlowCreatedEvent": "crewai.events.types.flow_events",
+ "FlowEvent": "crewai.events.types.flow_events",
+ "FlowFinishedEvent": "crewai.events.types.flow_events",
+ "FlowPlotEvent": "crewai.events.types.flow_events",
+ "FlowStartedEvent": "crewai.events.types.flow_events",
+ "HumanFeedbackReceivedEvent": "crewai.events.types.flow_events",
+ "HumanFeedbackRequestedEvent": "crewai.events.types.flow_events",
+ "MethodExecutionFailedEvent": "crewai.events.types.flow_events",
+ "MethodExecutionFinishedEvent": "crewai.events.types.flow_events",
+ "MethodExecutionStartedEvent": "crewai.events.types.flow_events",
+ # knowledge_events
+ "KnowledgeQueryCompletedEvent": "crewai.events.types.knowledge_events",
+ "KnowledgeQueryFailedEvent": "crewai.events.types.knowledge_events",
+ "KnowledgeQueryStartedEvent": "crewai.events.types.knowledge_events",
+ "KnowledgeRetrievalCompletedEvent": "crewai.events.types.knowledge_events",
+ "KnowledgeRetrievalStartedEvent": "crewai.events.types.knowledge_events",
+ "KnowledgeSearchQueryFailedEvent": "crewai.events.types.knowledge_events",
+ # llm_events
+ "LLMCallCompletedEvent": "crewai.events.types.llm_events",
+ "LLMCallFailedEvent": "crewai.events.types.llm_events",
+ "LLMCallStartedEvent": "crewai.events.types.llm_events",
+ "LLMStreamChunkEvent": "crewai.events.types.llm_events",
+ # llm_guardrail_events
+ "LLMGuardrailCompletedEvent": "crewai.events.types.llm_guardrail_events",
+ "LLMGuardrailStartedEvent": "crewai.events.types.llm_guardrail_events",
+ # logging_events
+ "AgentLogsExecutionEvent": "crewai.events.types.logging_events",
+ "AgentLogsStartedEvent": "crewai.events.types.logging_events",
+ # mcp_events
+ "MCPConfigFetchFailedEvent": "crewai.events.types.mcp_events",
+ "MCPConnectionCompletedEvent": "crewai.events.types.mcp_events",
+ "MCPConnectionFailedEvent": "crewai.events.types.mcp_events",
+ "MCPConnectionStartedEvent": "crewai.events.types.mcp_events",
+ "MCPToolExecutionCompletedEvent": "crewai.events.types.mcp_events",
+ "MCPToolExecutionFailedEvent": "crewai.events.types.mcp_events",
+ "MCPToolExecutionStartedEvent": "crewai.events.types.mcp_events",
+ # memory_events
+ "MemoryQueryCompletedEvent": "crewai.events.types.memory_events",
+ "MemoryQueryFailedEvent": "crewai.events.types.memory_events",
+ "MemoryQueryStartedEvent": "crewai.events.types.memory_events",
+ "MemoryRetrievalCompletedEvent": "crewai.events.types.memory_events",
+ "MemoryRetrievalFailedEvent": "crewai.events.types.memory_events",
+ "MemoryRetrievalStartedEvent": "crewai.events.types.memory_events",
+ "MemorySaveCompletedEvent": "crewai.events.types.memory_events",
+ "MemorySaveFailedEvent": "crewai.events.types.memory_events",
+ "MemorySaveStartedEvent": "crewai.events.types.memory_events",
+ # reasoning_events
+ "AgentReasoningCompletedEvent": "crewai.events.types.reasoning_events",
+ "AgentReasoningFailedEvent": "crewai.events.types.reasoning_events",
+ "AgentReasoningStartedEvent": "crewai.events.types.reasoning_events",
+ "ReasoningEvent": "crewai.events.types.reasoning_events",
+ # skill_events
+ "SkillActivatedEvent": "crewai.events.types.skill_events",
+ "SkillDiscoveryCompletedEvent": "crewai.events.types.skill_events",
+ "SkillDiscoveryStartedEvent": "crewai.events.types.skill_events",
+ "SkillEvent": "crewai.events.types.skill_events",
+ "SkillLoadFailedEvent": "crewai.events.types.skill_events",
+ "SkillLoadedEvent": "crewai.events.types.skill_events",
+ # task_events
+ "TaskCompletedEvent": "crewai.events.types.task_events",
+ "TaskEvaluationEvent": "crewai.events.types.task_events",
+ "TaskFailedEvent": "crewai.events.types.task_events",
+ "TaskStartedEvent": "crewai.events.types.task_events",
+ # tool_usage_events
+ "ToolExecutionErrorEvent": "crewai.events.types.tool_usage_events",
+ "ToolSelectionErrorEvent": "crewai.events.types.tool_usage_events",
+ "ToolUsageErrorEvent": "crewai.events.types.tool_usage_events",
+ "ToolUsageEvent": "crewai.events.types.tool_usage_events",
+ "ToolUsageFinishedEvent": "crewai.events.types.tool_usage_events",
+ "ToolUsageStartedEvent": "crewai.events.types.tool_usage_events",
+ "ToolValidateInputErrorEvent": "crewai.events.types.tool_usage_events",
+}
+
+_extension_exports: dict[str, Any] = {}
+
+
+def __getattr__(name: str) -> Any:
+ """Lazy import for event types and registered extensions."""
+ if name in _LAZY_EVENT_MAPPING:
+ module_path = _LAZY_EVENT_MAPPING[name]
+ module = importlib.import_module(module_path)
+ val = getattr(module, name)
+ globals()[name] = val # cache for subsequent access
+ return val
+
+ if name in _extension_exports:
+ value = _extension_exports[name]
+ if isinstance(value, str):
+ module_path, _, attr_name = value.rpartition(".")
+ if module_path:
+ module = importlib.import_module(module_path)
+ return getattr(module, attr_name)
+ return importlib.import_module(value)
+ return value
+
+ msg = f"module {__name__!r} has no attribute {name!r}"
+ raise AttributeError(msg)
__all__ = [
@@ -214,42 +339,3 @@ __all__ = [
"_extension_exports",
"crewai_event_bus",
]
-
-_AGENT_EVENT_MAPPING = {
- "AgentEvaluationCompletedEvent": "crewai.events.types.agent_events",
- "AgentEvaluationFailedEvent": "crewai.events.types.agent_events",
- "AgentEvaluationStartedEvent": "crewai.events.types.agent_events",
- "AgentExecutionCompletedEvent": "crewai.events.types.agent_events",
- "AgentExecutionErrorEvent": "crewai.events.types.agent_events",
- "AgentExecutionStartedEvent": "crewai.events.types.agent_events",
- "LiteAgentExecutionCompletedEvent": "crewai.events.types.agent_events",
- "LiteAgentExecutionErrorEvent": "crewai.events.types.agent_events",
- "LiteAgentExecutionStartedEvent": "crewai.events.types.agent_events",
-}
-
-_extension_exports: dict[str, Any] = {}
-
-
-def __getattr__(name: str) -> Any:
- """Lazy import for agent events and registered extensions."""
- if name in _AGENT_EVENT_MAPPING:
- import importlib
-
- module_path = _AGENT_EVENT_MAPPING[name]
- module = importlib.import_module(module_path)
- return getattr(module, name)
-
- if name in _extension_exports:
- import importlib
-
- value = _extension_exports[name]
- if isinstance(value, str):
- module_path, _, attr_name = value.rpartition(".")
- if module_path:
- module = importlib.import_module(module_path)
- return getattr(module, attr_name)
- return importlib.import_module(value)
- return value
-
- msg = f"module {__name__!r} has no attribute {name!r}"
- raise AttributeError(msg)
diff --git a/lib/crewai/src/crewai/events/listeners/tracing/trace_batch_manager.py b/lib/crewai/src/crewai/events/listeners/tracing/trace_batch_manager.py
index d2a0912f6..e35fe66e1 100644
--- a/lib/crewai/src/crewai/events/listeners/tracing/trace_batch_manager.py
+++ b/lib/crewai/src/crewai/events/listeners/tracing/trace_batch_manager.py
@@ -81,8 +81,11 @@ class TraceBatchManager:
"""Initialize a new trace batch (thread-safe)"""
with self._batch_ready_cv:
if self.current_batch is not None:
+ # Lazy init (e.g. DefaultEnvEvent) may have created the batch without
+ # execution_type; merge metadata from a later flow/crew initializer.
+ self.current_batch.execution_metadata.update(execution_metadata)
logger.debug(
- "Batch already initialized, skipping duplicate initialization"
+ "Batch already initialized, merged execution metadata and skipped duplicate initialization"
)
return self.current_batch
diff --git a/lib/crewai/src/crewai/events/listeners/tracing/trace_listener.py b/lib/crewai/src/crewai/events/listeners/tracing/trace_listener.py
index c4cc6cb71..046bc0f1a 100644
--- a/lib/crewai/src/crewai/events/listeners/tracing/trace_listener.py
+++ b/lib/crewai/src/crewai/events/listeners/tracing/trace_listener.py
@@ -60,12 +60,6 @@ from crewai.events.types.crew_events import (
CrewKickoffFailedEvent,
CrewKickoffStartedEvent,
)
-from crewai.events.types.env_events import (
- CCEnvEvent,
- CodexEnvEvent,
- CursorEnvEvent,
- DefaultEnvEvent,
-)
from crewai.events.types.flow_events import (
FlowCreatedEvent,
FlowFinishedEvent,
@@ -212,7 +206,6 @@ class TraceCollectionListener(BaseEventListener):
self._listeners_setup = True
return
- self._register_env_event_handlers(crewai_event_bus)
self._register_flow_event_handlers(crewai_event_bus)
self._register_context_event_handlers(crewai_event_bus)
self._register_action_event_handlers(crewai_event_bus)
@@ -221,25 +214,6 @@ class TraceCollectionListener(BaseEventListener):
self._listeners_setup = True
- def _register_env_event_handlers(self, event_bus: CrewAIEventsBus) -> None:
- """Register handlers for environment context events."""
-
- @event_bus.on(CCEnvEvent)
- def on_cc_env(source: Any, event: CCEnvEvent) -> None:
- self._handle_action_event("cc_env", source, event)
-
- @event_bus.on(CodexEnvEvent)
- def on_codex_env(source: Any, event: CodexEnvEvent) -> None:
- self._handle_action_event("codex_env", source, event)
-
- @event_bus.on(CursorEnvEvent)
- def on_cursor_env(source: Any, event: CursorEnvEvent) -> None:
- self._handle_action_event("cursor_env", source, event)
-
- @event_bus.on(DefaultEnvEvent)
- def on_default_env(source: Any, event: DefaultEnvEvent) -> None:
- self._handle_action_event("default_env", source, event)
-
def _register_flow_event_handlers(self, event_bus: CrewAIEventsBus) -> None:
"""Register handlers for flow events."""
@@ -286,8 +260,8 @@ class TraceCollectionListener(BaseEventListener):
if self.batch_manager.batch_owner_type != "flow":
# Always call _initialize_crew_batch to claim ownership.
# If batch was already initialized by a concurrent action event
- # (race condition with DefaultEnvEvent), initialize_batch() returns
- # early but batch_owner_type is still correctly set to "crew".
+ # (e.g. LLM/tool before crew_kickoff_started), initialize_batch()
+ # returns early but batch_owner_type is still correctly set to "crew".
# Skip only when a parent flow already owns the batch.
self._initialize_crew_batch(source, event)
self._handle_trace_event("crew_kickoff_started", source, event)
diff --git a/lib/crewai/src/crewai/flow/flow.py b/lib/crewai/src/crewai/flow/flow.py
index 88457f7aa..b363ebc71 100644
--- a/lib/crewai/src/crewai/flow/flow.py
+++ b/lib/crewai/src/crewai/flow/flow.py
@@ -1503,6 +1503,8 @@ class Flow(BaseModel, Generic[T], metaclass=FlowMeta):
except Exception:
logger.warning("FlowStartedEvent handler failed", exc_info=True)
+ get_env_context()
+
context = self._pending_feedback_context
emit = context.emit
default_outcome = context.default_outcome
@@ -2004,7 +2006,6 @@ class Flow(BaseModel, Generic[T], metaclass=FlowMeta):
restored = apply_checkpoint(self, from_checkpoint)
if restored is not None:
return restored.kickoff(inputs=inputs, input_files=input_files)
- get_env_context()
if self.stream:
result_holder: list[Any] = []
current_task_info: TaskInfo = {
@@ -2206,6 +2207,10 @@ class Flow(BaseModel, Generic[T], metaclass=FlowMeta):
f"Flow started with ID: {self.flow_id}", color="bold magenta"
)
+ # After FlowStarted (when not suppressed): env events must not pre-empt
+ # trace batch init with implicit "crew" execution_type.
+ get_env_context()
+
if inputs is not None and "id" not in inputs:
self._initialize_state(inputs)
diff --git a/lib/crewai/src/crewai/llm.py b/lib/crewai/src/crewai/llm.py
index db126954e..fb8461c04 100644
--- a/lib/crewai/src/crewai/llm.py
+++ b/lib/crewai/src/crewai/llm.py
@@ -175,6 +175,16 @@ LLM_CONTEXT_WINDOW_SIZES: Final[dict[str, int]] = {
"us.amazon.nova-pro-v1:0": 300000,
"us.amazon.nova-micro-v1:0": 128000,
"us.amazon.nova-lite-v1:0": 300000,
+ # Claude 4 models
+ "us.anthropic.claude-opus-4-7": 1000000,
+ "us.anthropic.claude-sonnet-4-6": 1000000,
+ "us.anthropic.claude-opus-4-6-v1": 1000000,
+ "us.anthropic.claude-opus-4-5-20251101-v1:0": 200000,
+ "us.anthropic.claude-haiku-4-5-20251001-v1:0": 200000,
+ "us.anthropic.claude-sonnet-4-5-20250929-v1:0": 200000,
+ "us.anthropic.claude-opus-4-1-20250805-v1:0": 200000,
+ "us.anthropic.claude-opus-4-20250514-v1:0": 200000,
+ "us.anthropic.claude-sonnet-4-20250514-v1:0": 200000,
"us.anthropic.claude-3-5-sonnet-20240620-v1:0": 200000,
"us.anthropic.claude-3-5-haiku-20241022-v1:0": 200000,
"us.anthropic.claude-3-5-sonnet-20241022-v2:0": 200000,
@@ -193,15 +203,44 @@ LLM_CONTEXT_WINDOW_SIZES: Final[dict[str, int]] = {
"eu.anthropic.claude-3-5-sonnet-20240620-v1:0": 200000,
"eu.anthropic.claude-3-sonnet-20240229-v1:0": 200000,
"eu.anthropic.claude-3-haiku-20240307-v1:0": 200000,
+ # Claude 4 EU
+ "eu.anthropic.claude-opus-4-7": 1000000,
+ "eu.anthropic.claude-sonnet-4-6": 1000000,
+ "eu.anthropic.claude-opus-4-6-v1": 1000000,
+ "eu.anthropic.claude-opus-4-5-20251101-v1:0": 200000,
+ "eu.anthropic.claude-haiku-4-5-20251001-v1:0": 200000,
+ "eu.anthropic.claude-sonnet-4-5-20250929-v1:0": 200000,
+ "eu.anthropic.claude-opus-4-1-20250805-v1:0": 200000,
+ "eu.anthropic.claude-opus-4-20250514-v1:0": 200000,
+ "eu.anthropic.claude-sonnet-4-20250514-v1:0": 200000,
"eu.meta.llama3-2-3b-instruct-v1:0": 131000,
"eu.meta.llama3-2-1b-instruct-v1:0": 131000,
"apac.anthropic.claude-3-5-sonnet-20240620-v1:0": 200000,
"apac.anthropic.claude-3-5-sonnet-20241022-v2:0": 200000,
"apac.anthropic.claude-3-sonnet-20240229-v1:0": 200000,
"apac.anthropic.claude-3-haiku-20240307-v1:0": 200000,
+ # Claude 4 APAC
+ "apac.anthropic.claude-opus-4-7": 1000000,
+ "apac.anthropic.claude-sonnet-4-6": 1000000,
+ "apac.anthropic.claude-opus-4-6-v1": 1000000,
+ "apac.anthropic.claude-opus-4-5-20251101-v1:0": 200000,
+ "apac.anthropic.claude-haiku-4-5-20251001-v1:0": 200000,
+ "apac.anthropic.claude-sonnet-4-5-20250929-v1:0": 200000,
+ "apac.anthropic.claude-opus-4-1-20250805-v1:0": 200000,
+ "apac.anthropic.claude-opus-4-20250514-v1:0": 200000,
+ "apac.anthropic.claude-sonnet-4-20250514-v1:0": 200000,
"amazon.nova-pro-v1:0": 300000,
"amazon.nova-micro-v1:0": 128000,
"amazon.nova-lite-v1:0": 300000,
+ "anthropic.claude-opus-4-7": 1000000,
+ "anthropic.claude-sonnet-4-6": 1000000,
+ "anthropic.claude-opus-4-6-v1": 1000000,
+ "anthropic.claude-opus-4-5-20251101-v1:0": 200000,
+ "anthropic.claude-haiku-4-5-20251001-v1:0": 200000,
+ "anthropic.claude-sonnet-4-5-20250929-v1:0": 200000,
+ "anthropic.claude-opus-4-1-20250805-v1:0": 200000,
+ "anthropic.claude-opus-4-20250514-v1:0": 200000,
+ "anthropic.claude-sonnet-4-20250514-v1:0": 200000,
"anthropic.claude-3-5-sonnet-20240620-v1:0": 200000,
"anthropic.claude-3-5-haiku-20241022-v1:0": 200000,
"anthropic.claude-3-5-sonnet-20241022-v2:0": 200000,
diff --git a/lib/crewai/src/crewai/llms/constants.py b/lib/crewai/src/crewai/llms/constants.py
index 595a0a30d..260c23daf 100644
--- a/lib/crewai/src/crewai/llms/constants.py
+++ b/lib/crewai/src/crewai/llms/constants.py
@@ -423,6 +423,34 @@ AZURE_MODELS: list[AzureModels] = [
BedrockModels: TypeAlias = Literal[
+ # Inference profiles (regional) - Claude 4
+ "us.anthropic.claude-sonnet-4-5-20250929-v1:0",
+ "us.anthropic.claude-sonnet-4-20250514-v1:0",
+ "us.anthropic.claude-opus-4-5-20251101-v1:0",
+ "us.anthropic.claude-opus-4-20250514-v1:0",
+ "us.anthropic.claude-opus-4-1-20250805-v1:0",
+ "us.anthropic.claude-haiku-4-5-20251001-v1:0",
+ "us.anthropic.claude-sonnet-4-6",
+ "us.anthropic.claude-opus-4-6-v1",
+ # Inference profiles - shorter versions
+ "us.anthropic.claude-sonnet-4-5-v1:0",
+ "us.anthropic.claude-opus-4-5-v1:0",
+ "us.anthropic.claude-opus-4-6-v1:0",
+ "us.anthropic.claude-haiku-4-5-v1:0",
+ "eu.anthropic.claude-sonnet-4-5-v1:0",
+ "eu.anthropic.claude-opus-4-5-v1:0",
+ "eu.anthropic.claude-haiku-4-5-v1:0",
+ "apac.anthropic.claude-sonnet-4-5-v1:0",
+ "apac.anthropic.claude-opus-4-5-v1:0",
+ "apac.anthropic.claude-haiku-4-5-v1:0",
+ # Global inference profiles
+ "global.anthropic.claude-sonnet-4-5-20250929-v1:0",
+ "global.anthropic.claude-sonnet-4-20250514-v1:0",
+ "global.anthropic.claude-opus-4-5-20251101-v1:0",
+ "global.anthropic.claude-opus-4-6-v1",
+ "global.anthropic.claude-haiku-4-5-20251001-v1:0",
+ "global.anthropic.claude-sonnet-4-6",
+ # Direct model IDs
"ai21.jamba-1-5-large-v1:0",
"ai21.jamba-1-5-mini-v1:0",
"amazon.nova-lite-v1:0",
@@ -496,6 +524,34 @@ BedrockModels: TypeAlias = Literal[
"twelvelabs.pegasus-1-2-v1:0",
]
BEDROCK_MODELS: list[BedrockModels] = [
+ # Inference profiles (regional) - Claude 4
+ "us.anthropic.claude-sonnet-4-5-20250929-v1:0",
+ "us.anthropic.claude-sonnet-4-20250514-v1:0",
+ "us.anthropic.claude-opus-4-5-20251101-v1:0",
+ "us.anthropic.claude-opus-4-20250514-v1:0",
+ "us.anthropic.claude-opus-4-1-20250805-v1:0",
+ "us.anthropic.claude-haiku-4-5-20251001-v1:0",
+ "us.anthropic.claude-sonnet-4-6",
+ "us.anthropic.claude-opus-4-6-v1",
+ # Inference profiles - shorter versions
+ "us.anthropic.claude-sonnet-4-5-v1:0",
+ "us.anthropic.claude-opus-4-5-v1:0",
+ "us.anthropic.claude-opus-4-6-v1:0",
+ "us.anthropic.claude-haiku-4-5-v1:0",
+ "eu.anthropic.claude-sonnet-4-5-v1:0",
+ "eu.anthropic.claude-opus-4-5-v1:0",
+ "eu.anthropic.claude-haiku-4-5-v1:0",
+ "apac.anthropic.claude-sonnet-4-5-v1:0",
+ "apac.anthropic.claude-opus-4-5-v1:0",
+ "apac.anthropic.claude-haiku-4-5-v1:0",
+ # Global inference profiles
+ "global.anthropic.claude-sonnet-4-5-20250929-v1:0",
+ "global.anthropic.claude-sonnet-4-20250514-v1:0",
+ "global.anthropic.claude-opus-4-5-20251101-v1:0",
+ "global.anthropic.claude-opus-4-6-v1",
+ "global.anthropic.claude-haiku-4-5-20251001-v1:0",
+ "global.anthropic.claude-sonnet-4-6",
+ # Direct model IDs
"ai21.jamba-1-5-large-v1:0",
"ai21.jamba-1-5-mini-v1:0",
"amazon.nova-lite-v1:0",
diff --git a/lib/crewai/src/crewai/llms/providers/azure/completion.py b/lib/crewai/src/crewai/llms/providers/azure/completion.py
index 4b8d842a5..714a7f0e9 100644
--- a/lib/crewai/src/crewai/llms/providers/azure/completion.py
+++ b/lib/crewai/src/crewai/llms/providers/azure/completion.py
@@ -183,11 +183,6 @@ class AzureCompletion(BaseLLM):
AzureCompletion._is_azure_openai_endpoint(self.endpoint)
)
- if not self.api_key:
- raise ValueError(
- "Azure API key is required. Set AZURE_API_KEY environment "
- "variable or pass api_key parameter."
- )
if not self.endpoint:
raise ValueError(
"Azure endpoint is required. Set AZURE_ENDPOINT environment "
@@ -195,12 +190,39 @@ class AzureCompletion(BaseLLM):
)
client_kwargs: dict[str, Any] = {
"endpoint": self.endpoint,
- "credential": AzureKeyCredential(self.api_key),
+ "credential": self._resolve_credential(),
}
if self.api_version:
client_kwargs["api_version"] = self.api_version
return client_kwargs
+ def _resolve_credential(self) -> Any:
+ """Return an Azure credential, preferring the API key when set.
+
+ Without an API key, fall back to ``DefaultAzureCredential`` from
+ ``azure-identity``. That chain auto-detects the standard keyless
+ paths the customer's environment may provide — OIDC Workload
+ Identity Federation (``AZURE_FEDERATED_TOKEN_FILE`` +
+ ``AZURE_TENANT_ID`` + ``AZURE_CLIENT_ID``), Managed Identity on
+ AKS/Azure VMs, environment-configured service principals, and
+ developer tools like the Azure CLI. Installing ``azure-identity``
+ is what enables these paths; without it we raise the existing
+ API-key error.
+ """
+ if self.api_key:
+ return AzureKeyCredential(self.api_key)
+
+ try:
+ from azure.identity import DefaultAzureCredential
+ except ImportError:
+ raise ValueError(
+ "Azure API key is required when azure-identity is not "
+ "installed. Set AZURE_API_KEY, or install azure-identity "
+ 'for keyless auth: uv add "crewai[azure-ai-inference]"'
+ ) from None
+
+ return DefaultAzureCredential()
+
def _get_sync_client(self) -> Any:
if self._client is None:
self._client = self._build_sync_client()
diff --git a/lib/crewai/src/crewai/llms/providers/bedrock/completion.py b/lib/crewai/src/crewai/llms/providers/bedrock/completion.py
index 54c222c85..cd323eac0 100644
--- a/lib/crewai/src/crewai/llms/providers/bedrock/completion.py
+++ b/lib/crewai/src/crewai/llms/providers/bedrock/completion.py
@@ -2075,6 +2075,9 @@ class BedrockCompletion(BaseLLM):
# Context window sizes for common Bedrock models
context_windows = {
+ "anthropic.claude-sonnet-4": 200000,
+ "anthropic.claude-opus-4": 200000,
+ "anthropic.claude-haiku-4": 200000,
"anthropic.claude-3-5-sonnet": 200000,
"anthropic.claude-3-5-haiku": 200000,
"anthropic.claude-3-opus": 200000,
diff --git a/lib/crewai/src/crewai/llms/providers/gemini/completion.py b/lib/crewai/src/crewai/llms/providers/gemini/completion.py
index 1b2fb26cb..f7fd0f61e 100644
--- a/lib/crewai/src/crewai/llms/providers/gemini/completion.py
+++ b/lib/crewai/src/crewai/llms/providers/gemini/completion.py
@@ -976,6 +976,7 @@ class GeminiCompletion(BaseLLM):
"id": call_id,
"name": part.function_call.name,
"args": args_dict,
+ "raw_part": part,
}
self._emit_stream_chunk_event(
@@ -1060,29 +1061,20 @@ class GeminiCompletion(BaseLLM):
if call_data.get("name") != STRUCTURED_OUTPUT_TOOL_NAME
}
- # If there are function calls but no available_functions,
- # return them for the executor to handle
if non_structured_output_calls and not available_functions:
- formatted_function_calls = [
- {
- "id": call_data["id"],
- "function": {
- "name": call_data["name"],
- "arguments": json.dumps(call_data["args"]),
- },
- "type": "function",
- }
+ raw_parts = [
+ call_data["raw_part"]
for call_data in non_structured_output_calls.values()
]
self._emit_call_completed_event(
- response=formatted_function_calls,
+ response=raw_parts,
call_type=LLMCallType.TOOL_CALL,
from_task=from_task,
from_agent=from_agent,
messages=self._convert_contents_to_dict(contents),
usage=usage_data,
)
- return formatted_function_calls
+ return raw_parts
# Handle completed function calls (excluding structured_output)
if non_structured_output_calls and available_functions:
diff --git a/lib/crewai/src/crewai/mcp/__init__.py b/lib/crewai/src/crewai/mcp/__init__.py
index e078919fd..bb3dab199 100644
--- a/lib/crewai/src/crewai/mcp/__init__.py
+++ b/lib/crewai/src/crewai/mcp/__init__.py
@@ -2,9 +2,17 @@
This module provides native MCP client functionality, allowing CrewAI agents
to connect to any MCP-compliant server using various transport types.
+
+Heavy imports (MCPClient, MCPToolResolver, BaseTransport, TransportType) are
+lazy-loaded on first access to avoid pulling in the ``mcp`` SDK (~400ms)
+when only lightweight config/filter types are needed.
"""
-from crewai.mcp.client import MCPClient
+from __future__ import annotations
+
+import importlib
+from typing import TYPE_CHECKING, Any
+
from crewai.mcp.config import (
MCPServerConfig,
MCPServerHTTP,
@@ -18,8 +26,28 @@ from crewai.mcp.filters import (
create_dynamic_tool_filter,
create_static_tool_filter,
)
-from crewai.mcp.tool_resolver import MCPToolResolver
-from crewai.mcp.transports.base import BaseTransport, TransportType
+
+if TYPE_CHECKING:
+ from crewai.mcp.client import MCPClient
+ from crewai.mcp.tool_resolver import MCPToolResolver
+ from crewai.mcp.transports.base import BaseTransport, TransportType
+
+_LAZY: dict[str, tuple[str, str]] = {
+ "MCPClient": ("crewai.mcp.client", "MCPClient"),
+ "MCPToolResolver": ("crewai.mcp.tool_resolver", "MCPToolResolver"),
+ "BaseTransport": ("crewai.mcp.transports.base", "BaseTransport"),
+ "TransportType": ("crewai.mcp.transports.base", "TransportType"),
+}
+
+
+def __getattr__(name: str) -> Any:
+ if name in _LAZY:
+ mod_path, attr = _LAZY[name]
+ mod = importlib.import_module(mod_path)
+ val = getattr(mod, attr)
+ globals()[name] = val # cache for subsequent access
+ return val
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
__all__ = [
diff --git a/lib/crewai/src/crewai/project/annotations.py b/lib/crewai/src/crewai/project/annotations.py
index c198c979a..b4b4b69d3 100644
--- a/lib/crewai/src/crewai/project/annotations.py
+++ b/lib/crewai/src/crewai/project/annotations.py
@@ -237,6 +237,8 @@ def crew(
self.tasks = instantiated_tasks
crew_instance: Crew = _call_method(meth, self, *args, **kwargs)
+ if "name" not in crew_instance.model_fields_set:
+ crew_instance.name = getattr(self, "_crew_name", None) or crew_instance.name
def callback_wrapper(
hook: Callable[Concatenate[CrewInstance, P2], R2], instance: CrewInstance
diff --git a/lib/crewai/src/crewai/state/runtime.py b/lib/crewai/src/crewai/state/runtime.py
index daae0620e..3243d4c19 100644
--- a/lib/crewai/src/crewai/state/runtime.py
+++ b/lib/crewai/src/crewai/state/runtime.py
@@ -44,9 +44,12 @@ def _sync_checkpoint_fields(entity: object) -> None:
entity: The entity whose private runtime attributes will be
copied into its public checkpoint fields.
"""
+ from crewai.agents.agent_builder.base_agent import BaseAgent
from crewai.crew import Crew
from crewai.flow.flow import Flow
+ if isinstance(entity, BaseAgent):
+ entity.checkpoint_kickoff_event_id = entity._kickoff_event_id
if isinstance(entity, Flow):
entity.checkpoint_completed_methods = (
set(entity._completed_methods) if entity._completed_methods else None
diff --git a/lib/crewai/src/crewai/task.py b/lib/crewai/src/crewai/task.py
index e12caa2af..04bbf3718 100644
--- a/lib/crewai/src/crewai/task.py
+++ b/lib/crewai/src/crewai/task.py
@@ -32,6 +32,7 @@ from pydantic import (
field_validator,
model_validator,
)
+from pydantic.functional_serializers import PlainSerializer
from pydantic_core import PydanticCustomError
from typing_extensions import Self
@@ -86,6 +87,22 @@ from crewai.utilities.printer import PRINTER
from crewai.utilities.string_utils import interpolate_only
+def _serialize_model_class(v: type[BaseModel] | None) -> dict[str, Any] | None:
+ """Serialize a Pydantic model class reference to its JSON schema."""
+ return v.model_json_schema() if v else None
+
+
+def _deserialize_model_class(v: Any) -> type[BaseModel] | None:
+ """Hydrate a model class reference from checkpoint data."""
+ if v is None or isinstance(v, type):
+ return v
+ if isinstance(v, dict):
+ from crewai.utilities.pydantic_schema_utils import create_model_from_schema
+
+ return create_model_from_schema(v)
+ return None
+
+
class Task(BaseModel):
"""Class that represents a task to be executed.
@@ -141,15 +158,33 @@ class Task(BaseModel):
description="Whether the task should be executed asynchronously or not.",
default=False,
)
- output_json: type[BaseModel] | None = Field(
+ output_json: Annotated[
+ type[BaseModel] | None,
+ BeforeValidator(_deserialize_model_class),
+ PlainSerializer(
+ _serialize_model_class, return_type=dict | None, when_used="json"
+ ),
+ ] = Field(
description="A Pydantic model to be used to create a JSON output.",
default=None,
)
- output_pydantic: type[BaseModel] | None = Field(
+ output_pydantic: Annotated[
+ type[BaseModel] | None,
+ BeforeValidator(_deserialize_model_class),
+ PlainSerializer(
+ _serialize_model_class, return_type=dict | None, when_used="json"
+ ),
+ ] = Field(
description="A Pydantic model to be used to create a Pydantic output.",
default=None,
)
- response_model: type[BaseModel] | None = Field(
+ response_model: Annotated[
+ type[BaseModel] | None,
+ BeforeValidator(_deserialize_model_class),
+ PlainSerializer(
+ _serialize_model_class, return_type=dict | None, when_used="json"
+ ),
+ ] = Field(
description="A Pydantic model for structured LLM outputs using native provider features.",
default=None,
)
@@ -189,7 +224,13 @@ class Task(BaseModel):
description="Whether the task should instruct the agent to return the final answer formatted in Markdown",
default=False,
)
- converter_cls: type[Converter] | None = Field(
+ converter_cls: Annotated[
+ type[Converter] | None,
+ BeforeValidator(lambda v: v if v is None or isinstance(v, type) else None),
+ PlainSerializer(
+ _serialize_model_class, return_type=dict | None, when_used="json"
+ ),
+ ] = Field(
description="A converter class used to export structured output",
default=None,
)
@@ -1241,12 +1282,26 @@ Follow these guidelines:
tools=tools,
)
- pydantic_output, json_output = self._export_output(result)
+ if isinstance(result, BaseModel):
+ raw = result.model_dump_json()
+ if self.output_pydantic:
+ pydantic_output = result
+ json_output = None
+ elif self.output_json:
+ pydantic_output = None
+ json_output = result.model_dump()
+ else:
+ pydantic_output = None
+ json_output = None
+ else:
+ raw = result
+ pydantic_output, json_output = self._export_output(result)
+
task_output = TaskOutput(
name=self.name or self.description,
description=self.description,
expected_output=self.expected_output,
- raw=result,
+ raw=raw,
pydantic=pydantic_output,
json_dict=json_output,
agent=agent.role,
@@ -1337,12 +1392,26 @@ Follow these guidelines:
tools=tools,
)
- pydantic_output, json_output = self._export_output(result)
+ if isinstance(result, BaseModel):
+ raw = result.model_dump_json()
+ if self.output_pydantic:
+ pydantic_output = result
+ json_output = None
+ elif self.output_json:
+ pydantic_output = None
+ json_output = result.model_dump()
+ else:
+ pydantic_output = None
+ json_output = None
+ else:
+ raw = result
+ pydantic_output, json_output = self._export_output(result)
+
task_output = TaskOutput(
name=self.name or self.description,
description=self.description,
expected_output=self.expected_output,
- raw=result,
+ raw=raw,
pydantic=pydantic_output,
json_dict=json_output,
agent=agent.role,
diff --git a/lib/crewai/tests/llms/azure/test_azure.py b/lib/crewai/tests/llms/azure/test_azure.py
index d42e2d7fe..774d23f20 100644
--- a/lib/crewai/tests/llms/azure/test_azure.py
+++ b/lib/crewai/tests/llms/azure/test_azure.py
@@ -389,17 +389,41 @@ def test_azure_raises_error_when_endpoint_missing():
llm._get_sync_client()
-def test_azure_raises_error_when_api_key_missing():
- """Credentials are validated lazily: construction succeeds, first
+def test_azure_raises_error_when_api_key_missing_without_azure_identity():
+ """Without an API key AND without ``azure-identity`` installed,
client build raises the descriptive error."""
from crewai.llms.providers.azure.completion import AzureCompletion
with patch.dict(os.environ, {}, clear=True):
- llm = AzureCompletion(
- model="gpt-4", endpoint="https://test.openai.azure.com"
- )
- with pytest.raises(ValueError, match="Azure API key is required"):
- llm._get_sync_client()
+ with patch.dict("sys.modules", {"azure.identity": None}):
+ llm = AzureCompletion(
+ model="gpt-4", endpoint="https://test.openai.azure.com"
+ )
+ with pytest.raises(ValueError, match="Azure API key is required"):
+ llm._get_sync_client()
+
+
+def test_azure_uses_default_credential_when_api_key_missing():
+ """With ``azure-identity`` installed, a missing API key falls back to
+ ``DefaultAzureCredential`` instead of raising. This is the path that
+ enables keyless auth (OIDC WIF on EKS/AKS, Managed Identity, Azure
+ CLI) without any crewAI-specific config."""
+ from unittest.mock import MagicMock
+
+ from crewai.llms.providers.azure.completion import AzureCompletion
+
+ sentinel = MagicMock(name="DefaultAzureCredential()")
+ with patch.dict(os.environ, {}, clear=True):
+ with patch(
+ "azure.identity.DefaultAzureCredential", return_value=sentinel
+ ) as mock_cls:
+ llm = AzureCompletion(
+ model="gpt-4",
+ endpoint="https://test-ai.services.example.com",
+ )
+ kwargs = llm._make_client_kwargs()
+ assert kwargs["credential"] is sentinel
+ mock_cls.assert_called()
@pytest.mark.asyncio
diff --git a/lib/crewai/tests/test_checkpoint.py b/lib/crewai/tests/test_checkpoint.py
index b1ad9e2df..d92a24803 100644
--- a/lib/crewai/tests/test_checkpoint.py
+++ b/lib/crewai/tests/test_checkpoint.py
@@ -562,3 +562,75 @@ class TestKickoffFromCheckpoint:
)
assert mock_restored.checkpoint.restore_from is None
assert result == "flow_result"
+
+
+# ---------- Agent checkpoint/fork ----------
+
+
+class TestAgentCheckpoint:
+ def _make_agent_state(self) -> RuntimeState:
+ agent = Agent(role="r", goal="g", backstory="b", llm="gpt-4o-mini")
+ return RuntimeState(root=[agent])
+
+ def test_agent_from_checkpoint_sets_runtime_state(self) -> None:
+ state = self._make_agent_state()
+ state._provider = JsonProvider()
+ with tempfile.TemporaryDirectory() as d:
+ loc = state.checkpoint(d)
+ cfg = CheckpointConfig(restore_from=loc)
+
+ from crewai.events.event_bus import crewai_event_bus
+
+ crewai_event_bus._runtime_state = None
+ Agent.from_checkpoint(cfg)
+ assert crewai_event_bus._runtime_state is not None
+
+ def test_agent_fork_sets_branch(self) -> None:
+ state = self._make_agent_state()
+ state._provider = JsonProvider()
+ with tempfile.TemporaryDirectory() as d:
+ loc = state.checkpoint(d)
+ cfg = CheckpointConfig(restore_from=loc)
+
+ from crewai.events.event_bus import crewai_event_bus
+
+ Agent.fork(cfg, branch="agent-experiment")
+ rt = crewai_event_bus._runtime_state
+ assert rt is not None
+ assert rt._branch == "agent-experiment"
+
+ def test_agent_fork_auto_branch(self) -> None:
+ state = self._make_agent_state()
+ state._provider = JsonProvider()
+ with tempfile.TemporaryDirectory() as d:
+ loc = state.checkpoint(d)
+ cfg = CheckpointConfig(restore_from=loc)
+
+ from crewai.events.event_bus import crewai_event_bus
+
+ Agent.fork(cfg)
+ rt = crewai_event_bus._runtime_state
+ assert rt is not None
+ assert rt._branch.startswith("fork/")
+
+ def test_sync_checkpoint_fields_agent(self) -> None:
+ from crewai.state.runtime import _sync_checkpoint_fields
+
+ agent = Agent(role="r", goal="g", backstory="b", llm="gpt-4o-mini")
+ agent._kickoff_event_id = "evt-123"
+ _sync_checkpoint_fields(agent)
+ assert agent.checkpoint_kickoff_event_id == "evt-123"
+
+ def test_agent_restore_kickoff_event_id(self) -> None:
+ agent = Agent(role="r", goal="g", backstory="b", llm="gpt-4o-mini")
+ agent._kickoff_event_id = "evt-456"
+ state = RuntimeState(root=[agent])
+ state._provider = JsonProvider()
+ with tempfile.TemporaryDirectory() as d:
+ from crewai.state.runtime import _prepare_entities
+
+ _prepare_entities(state.root)
+ loc = state.checkpoint(d)
+ cfg = CheckpointConfig(restore_from=loc)
+ restored = Agent.from_checkpoint(cfg)
+ assert restored._kickoff_event_id == "evt-456"
diff --git a/lib/crewai/tests/test_checkpoint_cli.py b/lib/crewai/tests/test_checkpoint_cli.py
index 38e105cce..aa1188336 100644
--- a/lib/crewai/tests/test_checkpoint_cli.py
+++ b/lib/crewai/tests/test_checkpoint_cli.py
@@ -292,7 +292,7 @@ class TestPruneJson:
d, name="20250101T000000_old01111_p-none.json"
)
os.utime(old_path, (0, 0))
- _write_json_checkpoint(d, name="20260417T000000_new01111_p-none.json")
+ _write_json_checkpoint(d, name="20990101T000000_new01111_p-none.json")
deleted = _prune_json(d, keep=None, older_than=timedelta(days=1))
assert deleted == 1
@@ -330,7 +330,7 @@ class TestPruneSqlite:
with tempfile.TemporaryDirectory() as d:
db_path = os.path.join(d, "test.db")
_create_sqlite_checkpoint(db_path, "20200101T000000_old01111")
- _create_sqlite_checkpoint(db_path, "20260417T000000_new01111")
+ _create_sqlite_checkpoint(db_path, "20990101T000000_new01111")
deleted = _prune_sqlite(db_path, keep=None, older_than=timedelta(days=1))
assert deleted >= 1
with sqlite3.connect(db_path) as conn:
diff --git a/lib/crewai/tests/test_crew.py b/lib/crewai/tests/test_crew.py
index 9db9ef4e2..3d6fe4602 100644
--- a/lib/crewai/tests/test_crew.py
+++ b/lib/crewai/tests/test_crew.py
@@ -8,6 +8,7 @@ from concurrent.futures import Future
from hashlib import md5
import re
import sys
+from typing import Any, cast
from unittest.mock import ANY, MagicMock, call, patch
from crewai.agent import Agent
@@ -17,6 +18,7 @@ from crewai.crew import Crew
from crewai.crews.crew_output import CrewOutput
from crewai.events.event_bus import crewai_event_bus
from crewai.events.types.crew_events import (
+ CrewKickoffStartedEvent,
CrewTestCompletedEvent,
CrewTestStartedEvent,
CrewTrainCompletedEvent,
@@ -4741,6 +4743,61 @@ def test_default_crew_name(researcher, writer):
assert crew.name == "crew"
+@pytest.mark.parametrize(
+ "explicit_name,expected",
+ [
+ (None, "ResearchAutomation"),
+ ("My Research Automation", "My Research Automation"),
+ ],
+ ids=["class_name_from_decorator", "explicit_name_preserved"],
+)
+def test_crew_kickoff_started_emits_display_name(
+ researcher, writer, explicit_name, expected
+):
+ """Kickoff events should use the decorator-provided display name when implicit."""
+ from crewai.crews.utils import prepare_kickoff
+ from crewai.project import CrewBase, agent, crew, task
+
+ @CrewBase
+ class ResearchAutomation:
+ agents_config = None
+ tasks_config = None
+
+ @agent
+ def researcher(self):
+ return researcher
+
+ @task
+ def first_task(self):
+ return Task(
+ description="Task 1",
+ expected_output="output",
+ agent=self.researcher(),
+ )
+
+ @crew
+ def crew(self):
+ crew_kwargs: dict[str, Any] = {
+ "agents": self.agents,
+ "tasks": self.tasks,
+ }
+ if explicit_name is not None:
+ crew_kwargs["name"] = explicit_name
+ return Crew(**crew_kwargs)
+
+ captured: list[str | None] = []
+ with crewai_event_bus.scoped_handlers():
+
+ @crewai_event_bus.on(CrewKickoffStartedEvent)
+ def _capture(_source: Any, event: CrewKickoffStartedEvent) -> None:
+ captured.append(event.crew_name)
+
+ automation_cls = cast(type[Any], ResearchAutomation)
+ prepare_kickoff(cast(Any, automation_cls()).crew(), inputs=None)
+
+ assert captured == [expected]
+
+
@pytest.mark.vcr()
def test_memory_remember_receives_task_content():
"""With memory=True, extract_memories receives raw content with task, agent, expected output, and result."""
diff --git a/lib/crewai/tests/test_project.py b/lib/crewai/tests/test_project.py
index 9d7f332da..368afe7fd 100644
--- a/lib/crewai/tests/test_project.py
+++ b/lib/crewai/tests/test_project.py
@@ -1,4 +1,4 @@
-from typing import Any, ClassVar
+from typing import Any, ClassVar, cast
from unittest.mock import Mock, create_autospec, patch
import pytest
@@ -261,6 +261,55 @@ def test_crew_name():
assert crew._crew_name == "InternalCrew"
+def test_crew_decorator_propagates_class_name_to_instance():
+ """@crew-decorated factory method should set Crew.name to the decorated class name."""
+ sample_agent = Agent(role="r", goal="g", backstory="b")
+ sample_task = Task(description="d", expected_output="o", agent=sample_agent)
+
+ @CrewBase
+ class ImplicitNameCrewFactory:
+ agents_config = None
+ tasks_config = None
+ agents: list[BaseAgent] = [sample_agent]
+ tasks: list[Task] = [sample_task]
+
+ @crew
+ def crew(self):
+ return Crew(
+ agents=[sample_agent],
+ tasks=[sample_task],
+ )
+
+ factory_cls = cast(type[Any], ImplicitNameCrewFactory)
+ crew_instance: Crew = cast(Any, factory_cls()).crew()
+ assert crew_instance.name == "ImplicitNameCrewFactory"
+
+
+def test_crew_decorator_preserves_explicit_name():
+ """Explicit Crew(name=...) inside @crew should win over the @CrewBase class name."""
+ sample_agent = Agent(role="r", goal="g", backstory="b")
+ sample_task = Task(description="d", expected_output="o", agent=sample_agent)
+
+ @CrewBase
+ class NamedCrewFactory:
+ agents_config = None
+ tasks_config = None
+ agents: list[BaseAgent] = [sample_agent]
+ tasks: list[Task] = [sample_task]
+
+ @crew
+ def crew(self):
+ return Crew(
+ name="My Explicit Name",
+ agents=[sample_agent],
+ tasks=[sample_task],
+ )
+
+ factory_cls = cast(type[Any], NamedCrewFactory)
+ crew_instance: Crew = cast(Any, factory_cls()).crew()
+ assert crew_instance.name == "My Explicit Name"
+
+
@tool
def simple_tool():
"""Return 'Hi!'"""
diff --git a/lib/crewai/tests/tracing/test_tracing.py b/lib/crewai/tests/tracing/test_tracing.py
index 640aca832..38bb060bd 100644
--- a/lib/crewai/tests/tracing/test_tracing.py
+++ b/lib/crewai/tests/tracing/test_tracing.py
@@ -1640,3 +1640,43 @@ class TestBackendInitializedGatedOnSuccess:
assert bm.backend_initialized is False
assert bm.trace_batch_id is None
+
+
+class TestTraceBatchManagerDuplicateInitMerge:
+ """Second initialize_batch call merges execution_metadata (flow after lazy action)."""
+
+ def test_duplicate_initialize_merges_execution_metadata(self):
+ with (
+ patch(
+ "crewai.events.listeners.tracing.trace_batch_manager.should_auto_collect_first_time_traces",
+ return_value=True,
+ ),
+ patch(
+ "crewai.events.listeners.tracing.trace_batch_manager.is_tracing_enabled_in_context",
+ return_value=True,
+ ),
+ ):
+ bm = TraceBatchManager()
+ bm.initialize_batch(
+ user_context={"privacy_level": "standard"},
+ execution_metadata={
+ "crew_name": "Unknown Crew",
+ "crewai_version": "9.9.9",
+ },
+ )
+ first_batch_id = bm.current_batch.batch_id
+ bm.initialize_batch(
+ user_context={"privacy_level": "standard"},
+ execution_metadata={
+ "flow_name": "ResearchFlow",
+ "execution_type": "flow",
+ "crewai_version": "9.9.9",
+ "execution_start": "2026-01-01T00:00:00+00:00",
+ },
+ )
+
+ assert bm.current_batch.batch_id == first_batch_id
+ meta = bm.current_batch.execution_metadata
+ assert meta.get("execution_type") == "flow"
+ assert meta.get("flow_name") == "ResearchFlow"
+ assert meta.get("crew_name") == "Unknown Crew"
diff --git a/lib/devtools/pyproject.toml b/lib/devtools/pyproject.toml
index 7eebc9ea4..88938fa5c 100644
--- a/lib/devtools/pyproject.toml
+++ b/lib/devtools/pyproject.toml
@@ -13,7 +13,7 @@ dependencies = [
"click~=8.1.7",
"tomlkit~=0.13.2",
"openai>=1.83.0,<3",
- "python-dotenv~=1.1.1",
+ "python-dotenv>=1.2.2,<2",
"pygithub~=1.59.1",
"rich>=13.9.4",
]
diff --git a/lib/devtools/src/crewai_devtools/__init__.py b/lib/devtools/src/crewai_devtools/__init__.py
index db857f660..9574be2db 100644
--- a/lib/devtools/src/crewai_devtools/__init__.py
+++ b/lib/devtools/src/crewai_devtools/__init__.py
@@ -1,3 +1,3 @@
"""CrewAI development tools."""
-__version__ = "1.14.2rc1"
+__version__ = "1.14.3a3"
diff --git a/lib/devtools/src/crewai_devtools/cli.py b/lib/devtools/src/crewai_devtools/cli.py
index eca54063b..35cebf979 100644
--- a/lib/devtools/src/crewai_devtools/cli.py
+++ b/lib/devtools/src/crewai_devtools/cli.py
@@ -154,6 +154,117 @@ def check_git_clean() -> None:
sys.exit(1)
+def _branch_exists_local(branch: str, cwd: Path | None = None) -> bool:
+ try:
+ subprocess.run( # noqa: S603
+ ["git", "show-ref", "--verify", "--quiet", f"refs/heads/{branch}"], # noqa: S607
+ cwd=cwd,
+ check=True,
+ capture_output=True,
+ )
+ return True
+ except subprocess.CalledProcessError:
+ return False
+
+
+def _branch_exists_remote(branch: str, cwd: Path | None = None) -> bool:
+ try:
+ output = run_command(["git", "ls-remote", "--heads", "origin", branch], cwd=cwd)
+ return bool(output.strip())
+ except subprocess.CalledProcessError:
+ return False
+
+
+def _open_pr_url_for_branch(branch: str, cwd: Path | None = None) -> str | None:
+ """Return URL of open PR for branch, or None if no open PR exists."""
+ try:
+ url = run_command(
+ [
+ "gh",
+ "pr",
+ "list",
+ "--head",
+ branch,
+ "--state",
+ "open",
+ "--json",
+ "url",
+ "--jq",
+ ".[0].url // empty",
+ ],
+ cwd=cwd,
+ )
+ return url or None
+ except subprocess.CalledProcessError:
+ return None
+
+
+def create_or_reset_branch(branch: str, cwd: Path | None = None) -> None:
+ """Create ``branch`` from current HEAD, resetting any stale copy.
+
+ If the branch exists locally or on origin, prompts the user to
+ choose between resetting it or aborting. If an open PR exists on
+ the branch, the prompt surfaces the PR URL and includes a
+ close-and-reset option so in-flight work isn't silently clobbered.
+
+ Raises:
+ SystemExit: If the user declines to reset.
+ """
+ local_exists = _branch_exists_local(branch, cwd=cwd)
+ remote_exists = _branch_exists_remote(branch, cwd=cwd)
+ open_pr = _open_pr_url_for_branch(branch, cwd=cwd) if remote_exists else None
+
+ if local_exists or remote_exists:
+ if open_pr:
+ console.print(
+ f"\n[yellow]![/yellow] Branch [bold]{branch}[/bold] already has an open PR: {open_pr}"
+ )
+ prompt = "Close the PR, reset the branch, and continue?"
+ else:
+ where = []
+ if local_exists:
+ where.append("local")
+ if remote_exists:
+ where.append("remote")
+ console.print(
+ f"\n[yellow]![/yellow] Branch [bold]{branch}[/bold] already exists ({', '.join(where)}) with no open PR"
+ )
+ prompt = "Delete it and recreate?"
+
+ if not Confirm.ask(prompt, default=False):
+ console.print("[red]Aborted.[/red]")
+ sys.exit(1)
+
+ if open_pr:
+ console.print(f"Closing PR {open_pr}...")
+ run_command(
+ ["gh", "pr", "close", branch, "--delete-branch"],
+ cwd=cwd,
+ )
+ # `gh pr close --delete-branch` removes the remote branch
+ # and, when checked out, the local branch too.
+ local_exists = _branch_exists_local(branch, cwd=cwd)
+ remote_exists = False
+
+ if local_exists:
+ current = run_command(
+ ["git", "rev-parse", "--abbrev-ref", "HEAD"], cwd=cwd
+ ).strip()
+ if current == branch:
+ console.print(
+ f"[yellow]![/yellow] Currently on {branch}, switching to main before delete"
+ )
+ run_command(["git", "checkout", "main"], cwd=cwd)
+ console.print(f"[yellow]![/yellow] Deleting local branch {branch}")
+ run_command(["git", "branch", "-D", branch], cwd=cwd)
+
+ if remote_exists:
+ console.print(f"[yellow]![/yellow] Deleting remote branch {branch}")
+ run_command(["git", "push", "origin", "--delete", branch], cwd=cwd)
+
+ run_command(["git", "checkout", "-b", branch], cwd=cwd)
+
+
def update_version_in_file(file_path: Path, new_version: str) -> bool:
"""Update __version__ attribute in a Python file.
@@ -980,7 +1091,7 @@ def _update_docs_and_create_pr(
if docs_files_staged:
docs_branch = f"docs/changelog-v{version}"
- run_command(["git", "checkout", "-b", docs_branch])
+ create_or_reset_branch(docs_branch)
for f in docs_files_staged:
run_command(["git", "add", f])
run_command(
@@ -1418,7 +1529,7 @@ def _release_enterprise(version: str, is_prerelease: bool, dry_run: bool) -> Non
console.print("[green]✓[/green] Workspace synced")
branch_name = f"feat/bump-version-{version}"
- run_command(["git", "checkout", "-b", branch_name], cwd=repo_dir)
+ create_or_reset_branch(branch_name, cwd=repo_dir)
run_command(["git", "add", "."], cwd=repo_dir)
run_command(
["git", "commit", "-m", f"feat: bump versions to {version}"],
@@ -1616,18 +1727,20 @@ def bump(version: str, dry_run: bool, no_push: bool, no_commit: bool) -> None:
for pkg in packages:
console.print(f" - {pkg.name}")
- console.print(f"\nUpdating version to {version}...")
- _update_all_versions(cwd, lib_dir, version, packages, dry_run)
-
if no_commit:
+ console.print(f"\nUpdating version to {version}...")
+ _update_all_versions(cwd, lib_dir, version, packages, dry_run)
console.print("\nSkipping git operations (--no-commit flag set)")
else:
branch_name = f"feat/bump-version-{version}"
if not dry_run:
console.print(f"\nCreating branch {branch_name}...")
- run_command(["git", "checkout", "-b", branch_name])
+ create_or_reset_branch(branch_name)
console.print("[green]✓[/green] Branch created")
+ console.print(f"\nUpdating version to {version}...")
+ _update_all_versions(cwd, lib_dir, version, packages, dry_run)
+
console.print("\nCommitting changes...")
run_command(["git", "add", "."])
run_command(
@@ -1643,6 +1756,8 @@ def bump(version: str, dry_run: bool, no_push: bool, no_commit: bool) -> None:
console.print(
f"[dim][DRY RUN][/dim] Would create branch: {branch_name}"
)
+ console.print(f"\nUpdating version to {version}...")
+ _update_all_versions(cwd, lib_dir, version, packages, dry_run)
console.print(
f"[dim][DRY RUN][/dim] Would commit: feat: bump versions to {version}"
)
@@ -1906,14 +2021,14 @@ def release(
console.print(f"\n[bold cyan]Phase 1: Bumping versions to {version}[/bold cyan]")
try:
- _update_all_versions(cwd, lib_dir, version, packages, dry_run)
-
branch_name = f"feat/bump-version-{version}"
if not dry_run:
console.print(f"\nCreating branch {branch_name}...")
- run_command(["git", "checkout", "-b", branch_name])
+ create_or_reset_branch(branch_name)
console.print("[green]✓[/green] Branch created")
+ _update_all_versions(cwd, lib_dir, version, packages, dry_run)
+
console.print("\nCommitting changes...")
run_command(["git", "add", "."])
run_command(["git", "commit", "-m", f"feat: bump versions to {version}"])
@@ -1943,6 +2058,7 @@ def release(
_poll_pr_until_merged(branch_name, "bump PR")
else:
console.print(f"[dim][DRY RUN][/dim] Would create branch: {branch_name}")
+ _update_all_versions(cwd, lib_dir, version, packages, dry_run)
console.print(
f"[dim][DRY RUN][/dim] Would commit: feat: bump versions to {version}"
)
diff --git a/pyproject.toml b/pyproject.toml
index f3d5f7f8f..754b4d635 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -162,30 +162,36 @@ info = "Commits must follow Conventional Commits 1.0.0."
[tool.uv]
-exclude-newer = "1 day"
+# Pinned to include the security patch releases (authlib 1.6.11,
+# langchain-text-splitters 1.1.2) uploaded on 2026-04-16.
+exclude-newer = "2026-04-22"
# composio-core pins rich<14 but textual requires rich>=14.
# onnxruntime 1.24+ dropped Python 3.10 wheels; cap it so qdrant[fastembed] resolves on 3.10.
# fastembed 0.7.x and docling 2.63 cap pillow<12; the removed APIs don't affect them.
-# langchain-core <1.2.28 has GHSA-926x-3r5x-gfhw (incomplete f-string validation).
+# langchain-core <1.2.31 has GHSA-926x-3r5x-gfhw and is required by langchain-text-splitters 1.1.2+.
+# langchain-text-splitters <1.1.2 has GHSA-fv5p-p927-qmxr (SSRF bypass in split_text_from_url).
# transformers 4.57.6 has CVE-2026-1839; force 5.4+ (docling 2.84 allows huggingface-hub>=1).
# cryptography 46.0.6 has CVE-2026-39892; force 46.0.7+.
-# pypdf <6.10.1 has CVE-2026-40260 and GHSA-jj6c-8h6c-hppx; force 6.10.1+.
+# pypdf <6.10.2 has GHSA-4pxv-j86v-mhcw, GHSA-7gw9-cf7v-778f, GHSA-x284-j5p8-9c5p; force 6.10.2+.
# uv <0.11.6 has GHSA-pjjw-68hj-v9mw; force 0.11.6+.
# python-multipart <0.0.26 has GHSA-mj87-hwqh-73pj; force 0.0.26+.
# langsmith <0.7.31 has GHSA-rr7j-v2q5-chgv (streaming token redaction bypass); force 0.7.31+.
+# authlib <1.6.11 has GHSA-jj8c-mmj3-mmgv (CSRF bypass in cache-based state storage).
override-dependencies = [
"rich>=13.7.1",
"onnxruntime<1.24; python_version < '3.11'",
"pillow>=12.1.1",
- "langchain-core>=1.2.28,<2",
+ "langchain-core>=1.2.31,<2",
+ "langchain-text-splitters>=1.1.2,<2",
"urllib3>=2.6.3",
"transformers>=5.4.0; python_version >= '3.10'",
"cryptography>=46.0.7",
- "pypdf>=6.10.1,<7",
+ "pypdf>=6.10.2,<7",
"uv>=0.11.6,<1",
"python-multipart>=0.0.26,<1",
"langsmith>=0.7.31,<0.8",
+ "authlib>=1.6.11",
]
[tool.uv.workspace]
diff --git a/uv.lock b/uv.lock
index a89b53544..461c859a4 100644
--- a/uv.lock
+++ b/uv.lock
@@ -13,8 +13,7 @@ resolution-markers = [
]
[options]
-exclude-newer = "2026-04-15T15:14:38.695171Z"
-exclude-newer-span = "P1D"
+exclude-newer = "2026-04-22T16:00:00Z"
[manifest]
members = [
@@ -24,12 +23,14 @@ members = [
"crewai-tools",
]
overrides = [
+ { name = "authlib", specifier = ">=1.6.11" },
{ name = "cryptography", specifier = ">=46.0.7" },
- { name = "langchain-core", specifier = ">=1.2.28,<2" },
+ { name = "langchain-core", specifier = ">=1.2.31,<2" },
+ { name = "langchain-text-splitters", specifier = ">=1.1.2,<2" },
{ name = "langsmith", specifier = ">=0.7.31,<0.8" },
{ name = "onnxruntime", marker = "python_full_version < '3.11'", specifier = "<1.24" },
{ name = "pillow", specifier = ">=12.1.1" },
- { name = "pypdf", specifier = ">=6.10.1,<7" },
+ { name = "pypdf", specifier = ">=6.10.2,<7" },
{ name = "python-multipart", specifier = ">=0.0.26,<1" },
{ name = "rich", specifier = ">=13.7.1" },
{ name = "transformers", marker = "python_full_version >= '3.10'", specifier = ">=5.4.0" },
@@ -239,6 +240,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c0/1b/ac685a8882896acf0f6b31d689e3792199cfe7aba37969fa91da63a7fa27/aiohttp-3.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:69f571de7500e0557801c0b51f4780482c0ec5fe2ac851af5a92cfce1af1cb83", size = 458896, upload-time = "2026-03-31T21:58:48.119Z" },
]
+[[package]]
+name = "aiohttp-retry"
+version = "2.9.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "aiohttp" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/9d/61/ebda4d8e3d8cfa1fd3db0fb428db2dd7461d5742cea35178277ad180b033/aiohttp_retry-2.9.1.tar.gz", hash = "sha256:8eb75e904ed4ee5c2ec242fefe85bf04240f685391c4879d8f541d6028ff01f1", size = 13608, upload-time = "2024-11-06T10:44:54.574Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1a/99/84ba7273339d0f3dfa57901b846489d2e5c2cd731470167757f1935fffbd/aiohttp_retry-2.9.1-py3-none-any.whl", hash = "sha256:66d2759d1921838256a05a3f80ad7e724936f083e35be5abb5e16eed6be6dc54", size = 9981, upload-time = "2024-11-06T10:44:52.917Z" },
+]
+
[[package]]
name = "aioitertools"
version = "0.13.0"
@@ -422,14 +435,14 @@ wheels = [
[[package]]
name = "authlib"
-version = "1.6.9"
+version = "1.6.11"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cryptography" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/af/98/00d3dd826d46959ad8e32af2dbb2398868fd9fd0683c26e56d0789bd0e68/authlib-1.6.9.tar.gz", hash = "sha256:d8f2421e7e5980cc1ddb4e32d3f5fa659cfaf60d8eaf3281ebed192e4ab74f04", size = 165134, upload-time = "2026-03-02T07:44:01.998Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/28/10/b325d58ffe86815b399334a101e63bc6fa4e1953921cb23703b48a0a0220/authlib-1.6.11.tar.gz", hash = "sha256:64db35b9b01aeccb4715a6c9a6613a06f2bd7be2ab9d2eb89edd1dfc7580a38f", size = 165359, upload-time = "2026-04-16T07:22:50.279Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/53/23/b65f568ed0c22f1efacb744d2db1a33c8068f384b8c9b482b52ebdbc3ef6/authlib-1.6.9-py2.py3-none-any.whl", hash = "sha256:f08b4c14e08f0861dc18a32357b33fbcfd2ea86cfe3fe149484b4d764c4a0ac3", size = 244197, upload-time = "2026-03-02T07:44:00.307Z" },
+ { url = "https://files.pythonhosted.org/packages/57/2f/55fca558f925a51db046e5b929deb317ddb05afed74b22d89f4eca578980/authlib-1.6.11-py2.py3-none-any.whl", hash = "sha256:c8687a9a26451c51a34a06fa17bb97cb15bba46a6a626755e2d7f50da8bff3e3", size = 244469, upload-time = "2026-04-16T07:22:48.413Z" },
]
[[package]]
@@ -497,6 +510,22 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/7e/d6/8ebcd05b01a580f086ac9a97fb9fac65c09a4b012161cc97c21a336e880b/azure_core-1.39.0-py3-none-any.whl", hash = "sha256:4ac7b70fab5438c3f68770649a78daf97833caa83827f91df9c14e0e0ea7d34f", size = 218318, upload-time = "2026-03-19T01:31:31.25Z" },
]
+[[package]]
+name = "azure-identity"
+version = "1.25.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "azure-core" },
+ { name = "cryptography" },
+ { name = "msal" },
+ { name = "msal-extensions" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c5/0e/3a63efb48aa4a5ae2cfca61ee152fbcb668092134d3eb8bfda472dd5c617/azure_identity-1.25.3.tar.gz", hash = "sha256:ab23c0d63015f50b630ef6c6cf395e7262f439ce06e5d07a64e874c724f8d9e6", size = 286304, upload-time = "2026-03-13T01:12:20.892Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/49/9a/417b3a533e01953a7c618884df2cb05a71e7b68bdbce4fbdb62349d2a2e8/azure_identity-1.25.3-py3-none-any.whl", hash = "sha256:f4d0b956a8146f30333e071374171f3cfa7bdb8073adb8c3814b65567aa7447c", size = 192138, upload-time = "2026-03-13T01:12:22.951Z" },
+]
+
[[package]]
name = "backoff"
version = "2.2.1"
@@ -602,7 +631,7 @@ wheels = [
[[package]]
name = "bedrock-agentcore"
-version = "1.3.2"
+version = "1.6.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "boto3" },
@@ -614,9 +643,9 @@ dependencies = [
{ name = "uvicorn" },
{ name = "websockets" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/05/90/a11e5a3208b7f607a3eabc8567b7c36767c6e094ec8128fba7ed2f5b3020/bedrock_agentcore-1.3.2.tar.gz", hash = "sha256:1dfae10fd315e078c002e49fd9d9686c41aee71ec8495f21e898a1ef3f782fa3", size = 421197, upload-time = "2026-02-23T20:52:56.202Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/ca/f6/2884c954343e794e3419348f5ffb0276a26f57b30af11f9fe63c4ca535c0/bedrock_agentcore-1.6.0.tar.gz", hash = "sha256:7ea176c3226dc6af8c399a8f9abb58629948cd8ed8675ece9f2f32b94e861b92", size = 512010, upload-time = "2026-03-31T23:10:06.561Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/36/b7/a5cc566901af27314408b95701f8e1d9c286b0aecfa50fc76c53d73efa6f/bedrock_agentcore-1.3.2-py3-none-any.whl", hash = "sha256:3a4e7122f777916f8bd74b42f29eb881415e37fda784a5ff8fab3c813b921706", size = 121703, upload-time = "2026-02-23T20:52:55.038Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/f8/bcf158979324f4f4d171588afffadb2154fa8499701290bfc7bdaf82bd3a/bedrock_agentcore-1.6.0-py3-none-any.whl", hash = "sha256:a4cd02f2bfb80fcc7a8c8835be8d55c778339f8286b071ac3aae579460dd2eb2", size = 164034, upload-time = "2026-03-31T23:10:04.902Z" },
]
[[package]]
@@ -687,6 +716,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/32/76/cab7af7f16c0b09347f2ebe7ffda7101132f786acb767666dce43055faab/botocore_stubs-1.42.41-py3-none-any.whl", hash = "sha256:9423110fb0e391834bd2ed44ae5f879d8cb370a444703d966d30842ce2bcb5f0", size = 66759, upload-time = "2026-02-03T20:46:13.02Z" },
]
+[[package]]
+name = "bracex"
+version = "2.6"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/63/9a/fec38644694abfaaeca2798b58e276a8e61de49e2e37494ace423395febc/bracex-2.6.tar.gz", hash = "sha256:98f1347cd77e22ee8d967a30ad4e310b233f7754dbf31ff3fceb76145ba47dc7", size = 26642, upload-time = "2025-06-22T19:12:31.254Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9d/2a/9186535ce58db529927f6cf5990a849aa9e052eea3e2cfefe20b9e1802da/bracex-2.6-py3-none-any.whl", hash = "sha256:0b0049264e7340b3ec782b5cb99beb325f36c3782a32e36e876452fd49a09952", size = 11508, upload-time = "2025-06-22T19:12:29.781Z" },
+]
+
[[package]]
name = "browserbase"
version = "1.8.0"
@@ -706,7 +744,7 @@ wheels = [
[[package]]
name = "build"
-version = "1.4.2"
+version = "1.4.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "os_name == 'nt'" },
@@ -715,9 +753,9 @@ dependencies = [
{ name = "pyproject-hooks" },
{ name = "tomli", marker = "python_full_version < '3.11'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/6c/1d/ab15c8ac57f4ee8778d7633bc6685f808ab414437b8644f555389cdc875e/build-1.4.2.tar.gz", hash = "sha256:35b14e1ee329c186d3f08466003521ed7685ec15ecffc07e68d706090bf161d1", size = 83433, upload-time = "2026-03-25T14:20:27.659Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/3f/16/4b272700dea44c1d2e8ca963ebb3c684efe22b3eba8cfa31c5fdb60de707/build-1.4.3.tar.gz", hash = "sha256:5aa4231ae0e807efdf1fd0623e07366eca2ab215921345a2e38acdd5d0fa0a74", size = 89314, upload-time = "2026-04-10T21:25:40.857Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/4a/57/3b7d4dd193ade4641c865bc2b93aeeb71162e81fc348b8dad020215601ed/build-1.4.2-py3-none-any.whl", hash = "sha256:7a4d8651ea877cb2a89458b1b198f2e69f536c95e89129dbf5d448045d60db88", size = 24643, upload-time = "2026-03-25T14:20:26.568Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/30/f169e1d8b2071beaf8b97088787e30662b1d8fb82f8c0941d14678c0cbf1/build-1.4.3-py3-none-any.whl", hash = "sha256:1bc22b19b383303de8f2c8554c9a32894a58d3f185fe3756b0b20d255bee9a38", size = 26171, upload-time = "2026-04-10T21:25:39.671Z" },
]
[[package]]
@@ -989,7 +1027,7 @@ wheels = [
[[package]]
name = "commitizen"
-version = "4.13.9"
+version = "4.13.10"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "argcomplete" },
@@ -1006,9 +1044,9 @@ dependencies = [
{ name = "tomlkit" },
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/a6/44/10f95e8178ab5a584298726a4a94ceb83a7f77e00741fec4680df05fedd5/commitizen-4.13.9.tar.gz", hash = "sha256:2b4567ed50555e10920e5bd804a6a4e2c42ec70bb74f14a83f2680fe9eaf9727", size = 64145, upload-time = "2026-02-25T02:40:05.326Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/37/95/da2c71ed6a1c06836cdd4eb60a8b9e1bf05f4ce7029ab508081745171be9/commitizen-4.13.10.tar.gz", hash = "sha256:402b5bcd466be69ba79a3f380be6ba5b55ac658c7d2a93e82fc99668a6eb2673", size = 64106, upload-time = "2026-04-11T06:49:12.907Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/28/22/9b14ee0f17f0aad219a2fb37a293a57b8324d9d195c6ef6807bcd0bf2055/commitizen-4.13.9-py3-none-any.whl", hash = "sha256:d2af3d6a83cacec9d5200e17768942c5de6266f93d932c955986c60c4285f2db", size = 85373, upload-time = "2026-02-25T02:40:03.83Z" },
+ { url = "https://files.pythonhosted.org/packages/11/3a/ad70b3c7dc3da1255668a9396429b1d820c15b74a501668158e4574c1edd/commitizen-4.13.10-py3-none-any.whl", hash = "sha256:95a281317990ac613501fdfe65745cec1fa4042bc5d003a72d332a74926e3039", size = 85746, upload-time = "2026-04-11T06:49:11.167Z" },
]
[[package]]
@@ -1283,6 +1321,7 @@ aws = [
]
azure-ai-inference = [
{ name = "azure-ai-inference" },
+ { name = "azure-identity" },
]
bedrock = [
{ name = "boto3" },
@@ -1337,6 +1376,7 @@ requires-dist = [
{ name = "anthropic", marker = "extra == 'anthropic'", specifier = "~=0.73.0" },
{ name = "appdirs", specifier = "~=1.4.4" },
{ name = "azure-ai-inference", marker = "extra == 'azure-ai-inference'", specifier = "~=1.0.0b9" },
+ { name = "azure-identity", marker = "extra == 'azure-ai-inference'", specifier = ">=1.17.0,<2" },
{ name = "boto3", marker = "extra == 'aws'", specifier = "~=1.42.79" },
{ name = "boto3", marker = "extra == 'bedrock'", specifier = "~=1.42.79" },
{ name = "chromadb", specifier = "~=1.1.0" },
@@ -1369,7 +1409,7 @@ requires-dist = [
{ name = "pydantic", specifier = "~=2.11.9" },
{ name = "pydantic-settings", specifier = "~=2.10.1" },
{ name = "pyjwt", specifier = ">=2.9.0,<3" },
- { name = "python-dotenv", specifier = "~=1.1.1" },
+ { name = "python-dotenv", specifier = ">=1.2.2,<2" },
{ name = "pyyaml", specifier = "~=6.0" },
{ name = "qdrant-client", extras = ["fastembed"], marker = "extra == 'qdrant'", specifier = "~=1.14.3" },
{ name = "qdrant-edge-py", marker = "extra == 'qdrant-edge'", specifier = ">=0.6.0" },
@@ -1401,7 +1441,7 @@ requires-dist = [
{ name = "click", specifier = "~=8.1.7" },
{ name = "openai", specifier = ">=1.83.0,<3" },
{ name = "pygithub", specifier = "~=1.59.1" },
- { name = "python-dotenv", specifier = "~=1.1.1" },
+ { name = "python-dotenv", specifier = ">=1.2.2,<2" },
{ name = "rich", specifier = ">=13.9.4" },
{ name = "tomlkit", specifier = "~=0.13.2" },
]
@@ -1473,6 +1513,13 @@ couchbase = [
databricks-sdk = [
{ name = "databricks-sdk" },
]
+daytona = [
+ { name = "daytona" },
+]
+e2b = [
+ { name = "e2b" },
+ { name = "e2b-code-interpreter" },
+]
exa-py = [
{ name = "exa-py" },
]
@@ -1573,13 +1620,16 @@ requires-dist = [
{ name = "crewai", editable = "lib/crewai" },
{ name = "cryptography", marker = "extra == 'snowflake'", specifier = ">=43.0.3" },
{ name = "databricks-sdk", marker = "extra == 'databricks-sdk'", specifier = ">=0.46.0" },
+ { name = "daytona", marker = "extra == 'daytona'", specifier = "~=0.140.0" },
+ { name = "e2b", marker = "extra == 'e2b'", specifier = "~=2.20.0" },
+ { name = "e2b-code-interpreter", marker = "extra == 'e2b'", specifier = "~=2.6.0" },
{ name = "exa-py", marker = "extra == 'exa-py'", specifier = ">=1.8.7" },
{ name = "firecrawl-py", marker = "extra == 'firecrawl-py'", specifier = ">=1.8.0" },
{ name = "gitpython", marker = "extra == 'github'", specifier = ">=3.1.41,<4" },
{ name = "hyperbrowser", marker = "extra == 'hyperbrowser'", specifier = ">=0.18.0" },
{ name = "langchain-apify", marker = "extra == 'apify'", specifier = ">=0.1.2,<1.0.0" },
{ name = "linkup-sdk", marker = "extra == 'linkup-sdk'", specifier = ">=0.2.2" },
- { name = "lxml", marker = "extra == 'rag'", specifier = ">=5.3.0,<5.4.0" },
+ { name = "lxml", marker = "extra == 'rag'", specifier = ">=6.1.0,<7" },
{ name = "mcp", marker = "extra == 'mcp'", specifier = ">=1.6.0" },
{ name = "mcpadapt", marker = "extra == 'mcp'", specifier = ">=0.1.9" },
{ name = "multion", marker = "extra == 'multion'", specifier = ">=1.1.0" },
@@ -1615,7 +1665,7 @@ requires-dist = [
{ name = "weaviate-client", marker = "extra == 'weaviate-client'", specifier = ">=4.10.2" },
{ name = "youtube-transcript-api", specifier = "~=1.2.2" },
]
-provides-extras = ["apify", "beautifulsoup4", "bedrock", "browserbase", "composio-core", "contextual", "couchbase", "databricks-sdk", "exa-py", "firecrawl-py", "github", "hyperbrowser", "linkup-sdk", "mcp", "mongodb", "multion", "mysql", "oxylabs", "patronus", "postgresql", "qdrant-client", "rag", "scrapegraph-py", "scrapfly-sdk", "selenium", "serpapi", "singlestore", "snowflake", "spider-client", "sqlalchemy", "stagehand", "tavily-python", "weaviate-client", "xml"]
+provides-extras = ["apify", "beautifulsoup4", "bedrock", "browserbase", "composio-core", "contextual", "couchbase", "databricks-sdk", "daytona", "e2b", "exa-py", "firecrawl-py", "github", "hyperbrowser", "linkup-sdk", "mcp", "mongodb", "multion", "mysql", "oxylabs", "patronus", "postgresql", "qdrant-client", "rag", "scrapegraph-py", "scrapfly-sdk", "selenium", "serpapi", "singlestore", "snowflake", "spider-client", "sqlalchemy", "stagehand", "tavily-python", "weaviate-client", "xml"]
[[package]]
name = "cryptography"
@@ -1683,10 +1733,10 @@ wheels = [
[[package]]
name = "cuda-pathfinder"
-version = "1.5.2"
+version = "1.5.3"
source = { registry = "https://pypi.org/simple" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/f2/f9/1b9b60a30fc463c14cdea7a77228131a0ccc89572e8df9cb86c9648271ab/cuda_pathfinder-1.5.2-py3-none-any.whl", hash = "sha256:0c5f160a7756c5b072723cbbd6d861e38917ef956c68150b02f0b6e9271c71fa", size = 49988, upload-time = "2026-04-06T23:01:05.17Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/d6/ac63065d33dd700fee7ebd7d287332401b54e31b9346e142f871e1f0b116/cuda_pathfinder-1.5.3-py3-none-any.whl", hash = "sha256:dff021123aedbb4117cc7ec81717bbfe198fb4e8b5f1ee57e0e084fec5c8577d", size = 49991, upload-time = "2026-04-14T20:09:27.037Z" },
]
[[package]]
@@ -1783,6 +1833,94 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl", hash = "sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a", size = 28686, upload-time = "2024-06-09T16:20:16.715Z" },
]
+[[package]]
+name = "daytona"
+version = "0.140.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "aiofiles" },
+ { name = "daytona-api-client" },
+ { name = "daytona-api-client-async" },
+ { name = "daytona-toolbox-api-client" },
+ { name = "daytona-toolbox-api-client-async" },
+ { name = "deprecated" },
+ { name = "environs" },
+ { name = "httpx" },
+ { name = "multipart" },
+ { name = "obstore" },
+ { name = "pydantic" },
+ { name = "toml" },
+ { name = "websockets" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/31/d4/4362b885f461ca2849f873c98e08594acb89d80ab82644ac88cdb4b7f8e9/daytona-0.140.0.tar.gz", hash = "sha256:8fa6dcc28ec735a9255d02cd98350b819fcf83daab866e688f659760c22bbfbf", size = 121616, upload-time = "2026-02-10T12:20:34.299Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9e/18/531ec599ff19adc9561ebfc5bdc5e5483fbb47e00d392376e69a259ed384/daytona-0.140.0-py3-none-any.whl", hash = "sha256:93a85d2c76e7e3dccbd708784026a61cd977ebfde37ed0777966c2e702918662", size = 150607, upload-time = "2026-02-10T12:20:32.889Z" },
+]
+
+[[package]]
+name = "daytona-api-client"
+version = "0.140.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pydantic" },
+ { name = "python-dateutil" },
+ { name = "typing-extensions" },
+ { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e4/7e/64676a69f357be5a32154240c89d145090d76c6706652e50137997f2fcab/daytona_api_client-0.140.0.tar.gz", hash = "sha256:ed28b3337189393d2766697c98d1b764dea4fda82359040e6f8d111f5d073aef", size = 134360, upload-time = "2026-02-10T12:19:35.791Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/11/79/17fd48a00c5aea1386f46a232f8af03014ec827c7c6ea46a2e192cddedbd/daytona_api_client-0.140.0-py3-none-any.whl", hash = "sha256:6a0ba0b4483da23f6557e18350de292b727a663874fd82aac3ae21a444d55215", size = 375797, upload-time = "2026-02-10T12:19:33.987Z" },
+]
+
+[[package]]
+name = "daytona-api-client-async"
+version = "0.140.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "aiohttp" },
+ { name = "aiohttp-retry" },
+ { name = "pydantic" },
+ { name = "python-dateutil" },
+ { name = "typing-extensions" },
+ { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e3/e3/f5dcfa17f02988899427d1b898f6176922787b8cb361e0a42d962ca319b2/daytona_api_client_async-0.140.0.tar.gz", hash = "sha256:dc6c7126649162bbe31e3da665b421165f52407d34598f8ec89617650456949e", size = 134486, upload-time = "2026-02-10T12:19:50.396Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1b/74/0a13a70d19756da1987369820d6bac0c704cffdc684b0e237ccbabf8ffb0/daytona_api_client_async-0.140.0-py3-none-any.whl", hash = "sha256:404ea5492714f6f82d2afbaaa722b87e5f2f9d419dfd28ec37c0a1edad408fb1", size = 378645, upload-time = "2026-02-10T12:19:48.434Z" },
+]
+
+[[package]]
+name = "daytona-toolbox-api-client"
+version = "0.140.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pydantic" },
+ { name = "python-dateutil" },
+ { name = "typing-extensions" },
+ { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/7b/f1/b04957487ef7b6de4a45ba5348123f6b8ed18325fa6e5bf3eea71c0a387d/daytona_toolbox_api_client-0.140.0.tar.gz", hash = "sha256:b7421327fd5f45168ab5d1579cfdceae55356fb3da5939d13d9087ae49f79945", size = 64094, upload-time = "2026-02-10T12:19:40.882Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b2/d5/08136d47cfec7199081f6a6ccf8e19992425bff091a9c97fdf6872de8a40/daytona_toolbox_api_client-0.140.0-py3-none-any.whl", hash = "sha256:4d71842b461e2a3123e563475964ddda78884d012286d950c9d947a0d2779d07", size = 171059, upload-time = "2026-02-10T12:19:39.107Z" },
+]
+
+[[package]]
+name = "daytona-toolbox-api-client-async"
+version = "0.140.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "aiohttp" },
+ { name = "aiohttp-retry" },
+ { name = "pydantic" },
+ { name = "python-dateutil" },
+ { name = "typing-extensions" },
+ { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a6/52/2a1b5fe303f4ea116ade0fe09dd85eba349a67318b83c74f7d2808a42905/daytona_toolbox_api_client_async-0.140.0.tar.gz", hash = "sha256:62a4b51404db28e95e18da836c8de0d2b67192d42027bc3c9273937d3066612b", size = 61090, upload-time = "2026-02-10T12:20:02.273Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9c/ca/0113aba439cad635a1ecaf4ac50c9a8248002d529b2c44d02f80ec08f503/daytona_toolbox_api_client_async-0.140.0-py3-none-any.whl", hash = "sha256:dddf18320449234ed62ce8d051f470ecaac0f56bf23e800c0bf51b11b5251d17", size = 172380, upload-time = "2026-02-10T12:20:01.005Z" },
+]
+
[[package]]
name = "decli"
version = "0.6.3"
@@ -1870,6 +2008,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" },
]
+[[package]]
+name = "dockerfile-parse"
+version = "2.0.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/92/df/929ee0b5d2c8bd8d713c45e71b94ab57c7e11e322130724d54f469b2cd48/dockerfile-parse-2.0.1.tar.gz", hash = "sha256:3184ccdc513221983e503ac00e1aa504a2aa8f84e5de673c46b0b6eee99ec7bc", size = 24556, upload-time = "2023-07-18T13:36:07.897Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7a/6c/79cd5bc1b880d8c1a9a5550aa8dacd57353fa3bb2457227e1fb47383eb49/dockerfile_parse-2.0.1-py2.py3-none-any.whl", hash = "sha256:bdffd126d2eb26acf1066acb54cb2e336682e1d72b974a40894fac76a4df17f6", size = 14845, upload-time = "2023-07-18T13:36:06.052Z" },
+]
+
[[package]]
name = "docling"
version = "2.84.0"
@@ -1915,7 +2062,7 @@ wheels = [
[[package]]
name = "docling-core"
-version = "2.73.0"
+version = "2.74.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "defusedxml" },
@@ -1930,9 +2077,9 @@ dependencies = [
{ name = "typer" },
{ name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/4c/e3/b9c3b1a1ea62e5e03d9e844a5cff2f89b7a3e960725a862f009e8553ca3d/docling_core-2.73.0.tar.gz", hash = "sha256:33ffc2b2bf736ed0e079bba296081a26885f6cb08081c828d630ca85a51e22e0", size = 308895, upload-time = "2026-04-09T08:08:51.573Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/43/d1/147ec84a59217d63620885e5103f9f40101972e70aae9e1c3b501e5637b8/docling_core-2.74.0.tar.gz", hash = "sha256:e8beb0b84a033c814386b1d990e73cb1c68c6485906c78c841b901577c705dc0", size = 316214, upload-time = "2026-04-17T06:50:28.344Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/7f/c3/08143b7e8fe1b9230ce15e54926859f8c40ec2622fb612f0b2ff13169696/docling_core-2.73.0-py3-none-any.whl", hash = "sha256:4366fab8f4422fbde090ed87d9b091bd25b3b37cdd284dc0b02c9a5e24caaa22", size = 271518, upload-time = "2026-04-09T08:08:49.838Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/9e/a7a5a71db047f5f50f5e4a4a43a918f346f97752539f1e5d99c785487497/docling_core-2.74.0-py3-none-any.whl", hash = "sha256:359f101a261cdcfa592bcb0e82dd508bd431f8d9ed49c6938ee271db1d420039", size = 275860, upload-time = "2026-04-17T06:50:26.779Z" },
]
[package.optional-dependencies]
@@ -1973,7 +2120,7 @@ wheels = [
[[package]]
name = "docling-parse"
-version = "5.8.0"
+version = "5.9.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "docling-core" },
@@ -1982,33 +2129,33 @@ dependencies = [
{ name = "pywin32", marker = "sys_platform == 'win32'" },
{ name = "tabulate" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/be/57/7b98e3ccf1ed40977bf832f028c68c248b0df1c25a5a33a50c2b2943ea72/docling_parse-5.8.0.tar.gz", hash = "sha256:cbb1d591dd94edab4ab3b81e9e42a3e4c7fe9ab3c3e690dccd498602aae63c5a", size = 65990181, upload-time = "2026-04-08T09:41:39.651Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/f9/10/69dc586f0ef54cc4e21e50debcb6bc52a77571482c88b7664aa725a7f150/docling_parse-5.9.0.tar.gz", hash = "sha256:c6812a143225490096cc2491a200b8731670c1dadff9aaf928c481bd5feba410", size = 66685491, upload-time = "2026-04-15T14:53:45.021Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/06/38/02a686660fe89a6f6775618ae43f9d4b76f615edc7374a1e8e1bf648fb73/docling_parse-5.8.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:241d09a904d8e4b70a2c040252a75a088e971a7926a46973389cb3235a5cab74", size = 8539476, upload-time = "2026-04-08T09:40:53.245Z" },
- { url = "https://files.pythonhosted.org/packages/f1/38/ebd2fd850eef60d9c201cfb28b24bc3c8a27efeb34e817c12f544453a3c2/docling_parse-5.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2e81da134baff612ea38ff0af3bf17deef196195d2415bfcf4f531bc7d0dd84", size = 9311993, upload-time = "2026-04-08T09:40:55.362Z" },
- { url = "https://files.pythonhosted.org/packages/c5/ba/c05c35a75b358ddaafdf0cd1e3f3737091722c6547b692cd66a99071159a/docling_parse-5.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b149bd7eeb91a5c6bdbc4a9bd87055a2a06d9ea959bf34d309580c1722d2e2b9", size = 9553650, upload-time = "2026-04-08T09:40:57.636Z" },
- { url = "https://files.pythonhosted.org/packages/63/7a/3670258908f6e5cf04251b9547967ebbf28211e29ede30eb5da41e0b509a/docling_parse-5.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:ac2c03347de9a0f02cdd46385ee4ae05f91eefc72aeac4749389d17f661dd7d5", size = 10357004, upload-time = "2026-04-08T09:40:59.921Z" },
- { url = "https://files.pythonhosted.org/packages/fc/09/57e47cc861f4e98201d6b881c6a7683e84f8ad20e2c1d619fe94c39ab7f2/docling_parse-5.8.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:fd1ae1cc22a96ccef76f82756ff7958d2a1eb38804e7cd9eed6ae951e2480c30", size = 8540650, upload-time = "2026-04-08T09:41:01.933Z" },
- { url = "https://files.pythonhosted.org/packages/5b/55/0265703d03377ad7ad3c4d482b00265275061ac15470dc815815944637cf/docling_parse-5.8.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b3908496e6949d2e56e361fc743a8f9248cb0f76807a1860027dde02be14f854", size = 9269550, upload-time = "2026-04-08T09:41:04.454Z" },
- { url = "https://files.pythonhosted.org/packages/96/03/962449ed1b6692e16c3cae0cf00fd60145d620dd1886aedacd1636727dec/docling_parse-5.8.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:860fbd5f2d30774d1c739d373aec14b7e074fdace191e5ac16750e7b14f136f4", size = 9601965, upload-time = "2026-04-08T09:41:06.807Z" },
- { url = "https://files.pythonhosted.org/packages/eb/18/5bee07b6ef6451b71904e0d21d7721af964fd92f3465305ef791d7a3cf56/docling_parse-5.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:854630f6ef7889d1757611194330d88fbbe53c0b202b5a010a467bf059f715da", size = 10358059, upload-time = "2026-04-08T09:41:09.049Z" },
- { url = "https://files.pythonhosted.org/packages/f9/61/3038e3a759df3aff0f02628eaeb71f6068b428ddd62981e639c5acf1eca8/docling_parse-5.8.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:a37c8c0aab730a9857c726420925cccc304a16abd91f054b25726394ee1ac836", size = 8541739, upload-time = "2026-04-08T09:41:11.525Z" },
- { url = "https://files.pythonhosted.org/packages/d1/98/b9307f84a7753cc369bbdd81f0183f308e8be1efeb2998193a494f8a8f44/docling_parse-5.8.0-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b2c7455b058525cdd46d4c6b7c429871f096aa7718ce1b8481dae426358cf29", size = 9269677, upload-time = "2026-04-08T09:41:13.721Z" },
- { url = "https://files.pythonhosted.org/packages/3a/a6/686adf6ed39d9de9912b233b8d0bd4f5e8113023aef47630ffde12ff0ba4/docling_parse-5.8.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:987d8eacb0f515f53a860329acc5c826487a9d2ff4430f08bd37498854cdab42", size = 9604016, upload-time = "2026-04-08T09:41:15.762Z" },
- { url = "https://files.pythonhosted.org/packages/f0/1b/90c5447a00a652a81e2b4fea86b33a694b1e0fec3b9fb1862f9b6f48f54a/docling_parse-5.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:6f72b0fdd370e825777f7a9989c390c630774870390c7277b7f016bfae395d6a", size = 10360133, upload-time = "2026-04-08T09:41:18.085Z" },
- { url = "https://files.pythonhosted.org/packages/33/c9/799cc497b71537bafb6b8bf66fcccf303f8a84684503e8783d489db03aab/docling_parse-5.8.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:292b82a9773c66a76e5ee376cfdde4a4d6a8edae6a4493aba4013d939e7a213f", size = 8541804, upload-time = "2026-04-08T09:41:20.358Z" },
- { url = "https://files.pythonhosted.org/packages/93/29/1030c13b257be7a4317bc7837c22366eff6d961ca6d6604b426dc8a9adcd/docling_parse-5.8.0-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:85c896983aaa7b95f409ed52014da59a945f2b914291c0782740e6a5b6d39028", size = 9269366, upload-time = "2026-04-08T09:41:22.437Z" },
- { url = "https://files.pythonhosted.org/packages/54/22/40990653103c2eb83b073d2aca47aa95b767f1360214fca4c6339df105c3/docling_parse-5.8.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2d9139f8da5e6553a36afb40dba614011ebd1bf97e5d17896ace07191a289c4b", size = 9604422, upload-time = "2026-04-08T09:41:24.619Z" },
- { url = "https://files.pythonhosted.org/packages/7e/9e/4ab1b16f6ba17f9695df79faa08a332b09a2d333d609036a7d0106538d57/docling_parse-5.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:7343ee48b0480593ed08b04ed0b09421724a6dec63d82c23fac436129b32c66a", size = 10360242, upload-time = "2026-04-08T09:41:27.132Z" },
+ { url = "https://files.pythonhosted.org/packages/58/a0/f04284a3e620d93d496ecfcf3e88bff46661c1bf0b2e90fe8c515ca6b6a4/docling_parse-5.9.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:e7794b173e4d9ae0ea061106aedc98093951394efc7305c7adffe4c43918369a", size = 8618285, upload-time = "2026-04-15T14:52:44.849Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/49/ed3b83457b4aef027ceff9d24348fb4397101497721d9449da8292eeb246/docling_parse-5.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21d1b0fdcb6965d3b1c1a224d87ce6cddc3c52649125ddec951d6b99dcda57da", size = 9335733, upload-time = "2026-04-15T14:52:47.188Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/45/cf9bfd6515d8e34181befa9a7567680fee7e109be5902138e665b3021179/docling_parse-5.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:690f10074ec05c69fb76050c282965ed9072c16f8eb020bc2483e228f0dfe39e", size = 9578860, upload-time = "2026-04-15T14:52:49.939Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/94/873be136532196e7224c94810826c9517ae6b0065c620c288799c4f9d48b/docling_parse-5.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:7b54b2272af1a4b6812f30d3b77c7774b021f34b65f2ee7032c561da2cc2c0a8", size = 10385131, upload-time = "2026-04-15T14:52:52.732Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/6c/3d6a840a208835b18235dc39a55a49ffbe36b739dffcd23edb43d56f977e/docling_parse-5.9.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:5880485aaf7d16cb398c67fcb804abc52f3797364338354fcc13240dac0e829e", size = 8619332, upload-time = "2026-04-15T14:52:56.362Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/91/eb49ee414b97190303047abd888478fe9596ae9af7c631668bca37ce0b93/docling_parse-5.9.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:322152aa19c74547a145b1563c6a1d3a1773ad39fcf4c0a7554ef333701101de", size = 9294677, upload-time = "2026-04-15T14:52:59.318Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/ba/8954e384e3e94b745279d5c213b5096a8bedce92ea69acea3377110835a6/docling_parse-5.9.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:afd7cd326ebe5de545e327f45b14be3e9b683efee0714d1b784f1314b1e22275", size = 9632461, upload-time = "2026-04-15T14:53:01.888Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/44/a786427fb8f77578639da41937f51284cff0b756d1507eeae5aee34c60ca/docling_parse-5.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:17dea2d9e467feb5b7fe53c58ed7493fffb9482563e8f065d426c87fe1078beb", size = 10386431, upload-time = "2026-04-15T14:53:04.538Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/c2/c98e01230920c151c679e4526fd655a8f10fe0ce9e34a4d49b3f456ee200/docling_parse-5.9.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:f9bb08e9e26cdd30d102d1a81420aca4a4b4136af2070d179147529ed991a64f", size = 8620298, upload-time = "2026-04-15T14:53:07.311Z" },
+ { url = "https://files.pythonhosted.org/packages/84/54/fc38b47d77d2ef97fdfb9a67e92daecaa68e29b3c54d6409f725b5901686/docling_parse-5.9.0-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5e141b536ccd954b612f2d7a091bf31e4684af07866ad6fa8b92b83fd60972e4", size = 9295434, upload-time = "2026-04-15T14:53:10.189Z" },
+ { url = "https://files.pythonhosted.org/packages/20/68/f5ba9c8bb743e65b79448089bf27d73189aca9ba781bd97d8712ff51595e/docling_parse-5.9.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:27eb3358564998f5f85264b093efc6e09d967113211448438911c646baa8c9b8", size = 9633448, upload-time = "2026-04-15T14:53:12.767Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/22/986312f5d7ec860e83fed6b3a604a736700510cb04e0fd8b8ab52a3bfedc/docling_parse-5.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:fcbea80304e7a1549e8cf049c0b3ff8b27e8d99150fc86e65fa1839506c7c002", size = 10388840, upload-time = "2026-04-15T14:53:15.495Z" },
+ { url = "https://files.pythonhosted.org/packages/41/28/7284bc189214e5c2a9ed15d0849a51f44d40dd9df9238d03c6db664bfc9e/docling_parse-5.9.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:0ff97842fd48bcc0ffae3dc8dfd1c96cca45b024395bdabea1ff2706bd23b44e", size = 8620340, upload-time = "2026-04-15T14:53:17.994Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/5a/5716684a43e6ff0199be57f3b2177b36c2f69449d63a1a5b4db5b5419800/docling_parse-5.9.0-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:292f54cceba3847d94a34c9110deb932df475185e0773a0297c17d646a0ec641", size = 9296689, upload-time = "2026-04-15T14:53:20.926Z" },
+ { url = "https://files.pythonhosted.org/packages/91/36/0a7001fa865a7023b3b26b97eb16a0ad0dfa472836e4042a8053be39ce37/docling_parse-5.9.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3ae90c0444034b1252881c99cec3a02779108df71ccf5a8eafaec7d4c5b4a8e0", size = 9633550, upload-time = "2026-04-15T14:53:23.831Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/ae/7880fd8b64b59f5d132426ec2cbe4db7595494254dbb3ffb5b9517ddb768/docling_parse-5.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:25a65bf93b826f733c3169623df720933294a89357c3dfef335e454b57507804", size = 10388600, upload-time = "2026-04-15T14:53:26.711Z" },
]
[[package]]
name = "docstring-parser"
-version = "0.17.0"
+version = "0.18.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/b2/9d/c3b43da9515bd270df0f80548d9944e389870713cc1fe2b8fb35fe2bcefd/docstring_parser-0.17.0.tar.gz", hash = "sha256:583de4a309722b3315439bb31d64ba3eebada841f2e2cee23b99df001434c912", size = 27442, upload-time = "2025-07-21T07:35:01.868Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/e0/4d/f332313098c1de1b2d2ff91cf2674415cc7cddab2ca1b01ae29774bd5fdf/docstring_parser-0.18.0.tar.gz", hash = "sha256:292510982205c12b1248696f44959db3cdd1740237a968ea1e2e7a900eeb2015", size = 29341, upload-time = "2026-04-14T04:09:19.867Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-py3-none-any.whl", hash = "sha256:cf2569abd23dce8099b300f9b4fa8191e9582dda731fd533daf54c4551658708", size = 36896, upload-time = "2025-07-21T07:35:00.684Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl", hash = "sha256:b3fcbed555c47d8479be0796ef7e19c2670d428d72e96da63f3a40122860374b", size = 22484, upload-time = "2026-04-14T04:09:18.638Z" },
]
[[package]]
@@ -2020,6 +2167,41 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/b0/0d/9feae160378a3553fa9a339b0e9c1a048e147a4127210e286ef18b730f03/durationpy-0.10-py3-none-any.whl", hash = "sha256:3b41e1b601234296b4fb368338fdcd3e13e0b4fb5b67345948f4f2bf9868b286", size = 3922, upload-time = "2025-05-17T13:52:36.463Z" },
]
+[[package]]
+name = "e2b"
+version = "2.20.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "attrs" },
+ { name = "dockerfile-parse" },
+ { name = "httpcore" },
+ { name = "httpx" },
+ { name = "packaging" },
+ { name = "protobuf" },
+ { name = "python-dateutil" },
+ { name = "rich" },
+ { name = "typing-extensions" },
+ { name = "wcmatch" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/8c/87/e9b3bd252a4fe2b3fd6967ff985c7a5a15a31b2d5b8c37e50afb18797b17/e2b-2.20.0.tar.gz", hash = "sha256:52b3a00ac7015bbdce84913b2a57664d2def33d5a4069e34fa2354de31759173", size = 156575, upload-time = "2026-04-02T19:20:32.375Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c2/ce/e402e2ecebe40ed9af20cddb862386f2ce20336e35c0dea257812129020e/e2b-2.20.0-py3-none-any.whl", hash = "sha256:66f6edcf6b742ca180f3aadcff7966fda86d68430fa6b2becdfa0fcc72224988", size = 296483, upload-time = "2026-04-02T19:20:30.573Z" },
+]
+
+[[package]]
+name = "e2b-code-interpreter"
+version = "2.6.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "attrs" },
+ { name = "e2b" },
+ { name = "httpx" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/cf/dd/f90b56d1597abfcdabdc018ac184fa714066be93d24b97edc2bf0671d483/e2b_code_interpreter-2.6.0.tar.gz", hash = "sha256:67e66531e5cf65c9df6e82aa0bdb1e73223a1ab205f10d47c027eb2ea09b73f9", size = 10683, upload-time = "2026-03-23T17:01:07.327Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/6b/79/f70d50604584df66064892f3fca7ab57b10ad40c826fd003be53a4cd5fa5/e2b_code_interpreter-2.6.0-py3-none-any.whl", hash = "sha256:a15f1d155566aef98cf2ccc0f8d9b07d15e07582d6cc8a128bc97de371bd617c", size = 13715, upload-time = "2026-03-23T17:01:06.111Z" },
+]
+
[[package]]
name = "effdet"
version = "0.4.1"
@@ -2045,6 +2227,20 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/e1/5e/4b5aaaabddfacfe36ba7768817bd1f71a7a810a43705e531f3ae4c690767/emoji-2.15.0-py3-none-any.whl", hash = "sha256:205296793d66a89d88af4688fa57fd6496732eb48917a87175a023c8138995eb", size = 608433, upload-time = "2025-09-21T12:13:01.197Z" },
]
+[[package]]
+name = "environs"
+version = "14.6.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "marshmallow" },
+ { name = "python-dotenv" },
+ { name = "typing-extensions", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/fb/c7/94f97e6e74482a50b5fc798856b6cc06e8d072ab05a0b74cb5d87bd0d065/environs-14.6.0.tar.gz", hash = "sha256:ed2767588deb503209ffe4dd9bb2b39311c2e4e7e27ce2c64bf62ca83328d068", size = 35563, upload-time = "2026-02-20T04:02:08.869Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/97/a8/c070e1340636acb38d4e6a7e45c46d168a462b48b9b3257e14ca0e5af79b/environs-14.6.0-py3-none-any.whl", hash = "sha256:f8fb3d6c6a55872b0c6db077a28f5a8c7b8984b7c32029613d44cef95cfc0812", size = 17205, upload-time = "2026-02-20T04:02:07.299Z" },
+]
+
[[package]]
name = "et-xmlfile"
version = "2.0.0"
@@ -2065,7 +2261,7 @@ wheels = [
[[package]]
name = "exa-py"
-version = "2.11.0"
+version = "2.12.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "httpcore" },
@@ -2076,9 +2272,9 @@ dependencies = [
{ name = "requests" },
{ name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/c5/08/af21dace845b5cd67d728e9d7747e4d1024ec90bd83e007d78f969dc6e19/exa_py-2.11.0.tar.gz", hash = "sha256:989103cbd83aae6dbe88cb70e11522a4bb06026fdb54b8659e3a7922da41fc93", size = 54905, upload-time = "2026-04-04T00:04:32.455Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/ab/d2/22f8e5b83fb7ff1a5b19528b21bb908504c8b6a716309b169801881e64ff/exa_py-2.12.0.tar.gz", hash = "sha256:2cd5fe2d47d8e0221f87dcb2be0f007cc0a1f0a643b16dfc586ab1421998f4fc", size = 58731, upload-time = "2026-04-15T12:55:17.616Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/9b/c9/129dd486505e3c0dadda0d6c83c560060f76d4cf14ef4b7b93053846598a/exa_py-2.11.0-py3-none-any.whl", hash = "sha256:3b0070a6ce98e02895755f0f81752dff64e2e121cf9d9a82facf715a4b9a5238", size = 73424, upload-time = "2026-04-04T00:04:33.699Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/87/e5c458741a34c945d6b612ec54f00088a6869ffc4f3f8a7b06ae080ec6af/exa_py-2.12.0-py3-none-any.whl", hash = "sha256:78b954ca99151228e4b853bd25e58829048a9a601d6187001befa512e0143f8f", size = 73896, upload-time = "2026-04-15T12:55:16.03Z" },
]
[[package]]
@@ -2116,7 +2312,7 @@ wheels = [
[[package]]
name = "fastapi"
-version = "0.135.3"
+version = "0.136.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "annotated-doc" },
@@ -2125,9 +2321,9 @@ dependencies = [
{ name = "typing-extensions" },
{ name = "typing-inspection" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/f7/e6/7adb4c5fa231e82c35b8f5741a9f2d055f520c29af5546fd70d3e8e1cd2e/fastapi-0.135.3.tar.gz", hash = "sha256:bd6d7caf1a2bdd8d676843cdcd2287729572a1ef524fc4d65c17ae002a1be654", size = 396524, upload-time = "2026-04-01T16:23:58.188Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/4e/d9/e66315807e41e69e7f6a1b42a162dada2f249c5f06ad3f1a95f84ab336ef/fastapi-0.136.0.tar.gz", hash = "sha256:cf08e067cc66e106e102d9ba659463abfac245200752f8a5b7b1e813de4ff73e", size = 396607, upload-time = "2026-04-16T11:47:13.623Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/84/a4/5caa2de7f917a04ada20018eccf60d6cc6145b0199d55ca3711b0fc08312/fastapi-0.135.3-py3-none-any.whl", hash = "sha256:9b0f590c813acd13d0ab43dd8494138eb58e484bfac405db1f3187cfc5810d98", size = 117734, upload-time = "2026-04-01T16:23:59.328Z" },
+ { url = "https://files.pythonhosted.org/packages/26/a3/0bd5f0cdb0bbc92650e8dc457e9250358411ee5d1b65e42b6632387daf81/fastapi-0.136.0-py3-none-any.whl", hash = "sha256:8793d44ec7378e2be07f8a013cf7f7aa47d6327d0dfe9804862688ec4541a6b4", size = 117556, upload-time = "2026-04-16T11:47:11.922Z" },
]
[[package]]
@@ -2218,11 +2414,11 @@ wheels = [
[[package]]
name = "filelock"
-version = "3.25.2"
+version = "3.28.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/94/b8/00651a0f559862f3bb7d6f7477b192afe3f583cc5e26403b44e59a55ab34/filelock-3.25.2.tar.gz", hash = "sha256:b64ece2b38f4ca29dd3e810287aa8c48182bbecd1ae6e9ae126c9b35f1382694", size = 40480, upload-time = "2026-03-11T20:45:38.487Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/d6/17/6e8890271880903e3538660a21d63a6c1fea969ac71d0d6b608b78727fa9/filelock-3.28.0.tar.gz", hash = "sha256:4ed1010aae813c4ee8d9c660e4792475ee60c4a0ba76073ceaf862bd317e3ca6", size = 56474, upload-time = "2026-04-14T22:54:33.625Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl", hash = "sha256:ca8afb0da15f229774c9ad1b455ed96e85a81373065fb10446672f64444ddf70", size = 26759, upload-time = "2026-03-11T20:45:37.437Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/21/2f728888c45033d34a417bfcd248ea2564c9e08ab1bfd301377cf05d5586/filelock-3.28.0-py3-none-any.whl", hash = "sha256:de9af6712788e7171df1b28b15eba2446c69721433fa427a9bee07b17820a9db", size = 39189, upload-time = "2026-04-14T22:54:32.037Z" },
]
[[package]]
@@ -2236,7 +2432,7 @@ wheels = [
[[package]]
name = "firecrawl-py"
-version = "4.22.1"
+version = "4.22.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiohttp" },
@@ -2247,9 +2443,9 @@ dependencies = [
{ name = "requests" },
{ name = "websockets" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/64/87/08cd440a3b942be5983c1a2db921d55697bdb91f7ead9a925b75715039a0/firecrawl_py-4.22.1.tar.gz", hash = "sha256:fb44d4c63ba91c076ae2f0b688f1556327c971baea45e7fb67d6ed5d393542a2", size = 174394, upload-time = "2026-04-07T01:54:19.682Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/9d/03/fc714c52f156add4c58665ff3ede3ff2b07d96e32742507ed94769a94227/firecrawl_py-4.22.2.tar.gz", hash = "sha256:c1bf17f6faf3b9599291e56d4b1b1d367777dbcf35b28568dd07084f1b0c9149", size = 174536, upload-time = "2026-04-15T21:34:42.124Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/fb/a7/54199470a5bf8e09bdf9511f80e766a11b20daafc3b0e1e638ec04e24fc9/firecrawl_py-4.22.1-py3-none-any.whl", hash = "sha256:3df92a7888f9d5907a6fbbe50ade330d2925f5bf51f8efa507c2ab9891df9a0a", size = 217741, upload-time = "2026-04-07T01:54:18.403Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/35/adc7ff46b0f06261ce70b43ab0861c895d12bde7a7ceea95e45d45cb0a82/firecrawl_py-4.22.2-py3-none-any.whl", hash = "sha256:9f13f55ec7e8eb61a7fe91a2af09d5dd5c7539ec3f64f66280a7ceaa8b1bad10", size = 217823, upload-time = "2026-04-15T21:34:40.496Z" },
]
[[package]]
@@ -2872,7 +3068,7 @@ wheels = [
[[package]]
name = "huggingface-hub"
-version = "1.10.1"
+version = "1.11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "filelock" },
@@ -2885,9 +3081,9 @@ dependencies = [
{ name = "typer" },
{ name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/e4/28/baf5d745559503ce8d28cf5bc9551f5ac59158eafd7b6a6afff0bcdb0f50/huggingface_hub-1.10.1.tar.gz", hash = "sha256:696c53cf9c2ac9befbfb5dd41d05392a031c69fc6930d1ed9671debd405b6fff", size = 758094, upload-time = "2026-04-09T15:01:18.928Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/dc/89/e7aa12d8a6b9259bed10671abb25ae6fa437c0f88a86ecbf59617bae7759/huggingface_hub-1.11.0.tar.gz", hash = "sha256:15fb3713c7f9cdff7b808a94fd91664f661ab142796bb48c9cd9493e8d166278", size = 761749, upload-time = "2026-04-16T13:07:39.73Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/83/8c/c7a33f3efaa8d6a5bc40e012e5ecc2d72c2e6124550ca9085fe0ceed9993/huggingface_hub-1.10.1-py3-none-any.whl", hash = "sha256:6b981107a62fbe68c74374418983399c632e35786dcd14642a9f2972633c8b5a", size = 642630, upload-time = "2026-04-09T15:01:17.35Z" },
+ { url = "https://files.pythonhosted.org/packages/37/02/4f3f8997d1ea7fe0146b343e5e14bd065fa87af790d07e5576d31b31cc18/huggingface_hub-1.11.0-py3-none-any.whl", hash = "sha256:42a6de0afbfeb5e022222d36398f029679db4eb4778801aafda32257ae9131ab", size = 645499, upload-time = "2026-04-16T13:07:37.716Z" },
]
[[package]]
@@ -2904,7 +3100,7 @@ wheels = [
[[package]]
name = "hyperbrowser"
-version = "0.90.1"
+version = "0.90.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "httpx" },
@@ -2912,9 +3108,9 @@ dependencies = [
{ name = "pydantic" },
{ name = "websockets" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/6e/60/b651865b7154feb571980c7f3341c75275a7330d3980c6a328bd875eb1dc/hyperbrowser-0.90.1.tar.gz", hash = "sha256:987259a99a8fe740274bc87b9cd64430476588fb5467313537d746881703fe4c", size = 65524, upload-time = "2026-04-07T23:56:44.951Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/13/47/2709a71c27e3614147b8bd9df378474bf450da18fb4c16a03b25ebb641de/hyperbrowser-0.90.4.tar.gz", hash = "sha256:14272b7ad78b7a16ecdb0f992c830b3dc3099fcf99bf0c417e78b1f22f1cb946", size = 67090, upload-time = "2026-04-16T18:51:49.957Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/6c/49/cca92edcbace09135bf6c13a15c1856357c1cf68185d09088937b0bfe1f2/hyperbrowser-0.90.1-py3-none-any.whl", hash = "sha256:831c4e9b3143d713b64dd69034936763c5d92dfbf18f2936bc33d72c066b6551", size = 110792, upload-time = "2026-04-07T23:56:43.626Z" },
+ { url = "https://files.pythonhosted.org/packages/68/af/b781aa3ad78c85cb8fc10b13ef005ec1e75b691b1af4314e81e5a8318755/hyperbrowser-0.90.4-py3-none-any.whl", hash = "sha256:b0e19e67f80a32a59838ecd12427fd5f7a23279f3987f3d74da336b390af6f8b", size = 113577, upload-time = "2026-04-16T18:51:48.631Z" },
]
[[package]]
@@ -3122,11 +3318,11 @@ wheels = [
[[package]]
name = "importlib-resources"
-version = "6.5.2"
+version = "7.1.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/cf/8c/f834fbf984f691b4f7ff60f50b514cc3de5cc08abfc3295564dd89c5e2e7/importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c", size = 44693, upload-time = "2025-01-03T18:51:56.698Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/e4/06/b56dfa750b44e86157093bc8fca0ab81dccbf5260510de4eaf1cb69b5b99/importlib_resources-7.1.0.tar.gz", hash = "sha256:0722d4c6212489c530f2a145a34c0a7a3b4721bc96a15fada5930e2a0b760708", size = 44985, upload-time = "2026-04-12T16:36:09.232Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec", size = 37461, upload-time = "2025-01-03T18:51:54.306Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/db/55a262f3606bebcae07cc14095338471ad7c0bbcaa37707e6f0ee49725b7/importlib_resources-7.1.0-py3-none-any.whl", hash = "sha256:1bd7b48b4088eddb2cd16382150bb515af0bd2c70128194392725f82ad2c96a1", size = 37232, upload-time = "2026-04-12T16:36:08.219Z" },
]
[[package]]
@@ -3557,7 +3753,7 @@ wheels = [
[[package]]
name = "langchain-core"
-version = "1.2.28"
+version = "1.3.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "jsonpatch" },
@@ -3569,21 +3765,21 @@ dependencies = [
{ name = "typing-extensions" },
{ name = "uuid-utils" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/f8/a4/317a1a3ac1df33a64adb3670bf88bbe3b3d5baa274db6863a979db472897/langchain_core-1.2.28.tar.gz", hash = "sha256:271a3d8bd618f795fdeba112b0753980457fc90537c46a0c11998516a74dc2cb", size = 846119, upload-time = "2026-04-08T18:19:34.867Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/92/fe/20190232d9b513242899dbb0c2bb77e31b4d61e343743adbe90ebc2603d2/langchain_core-1.3.0.tar.gz", hash = "sha256:14a39f528bf459aa3aa40d0a7f7f1bae7520d435ef991ae14a4ceb74d8c49046", size = 860755, upload-time = "2026-04-17T14:51:38.298Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/a8/92/32f785f077c7e898da97064f113c73fbd9ad55d1e2169cf3a391b183dedb/langchain_core-1.2.28-py3-none-any.whl", hash = "sha256:80764232581eaf8057bcefa71dbf8adc1f6a28d257ebd8b95ba9b8b452e8c6ac", size = 508727, upload-time = "2026-04-08T18:19:32.823Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/e2/dbfa347aa072a6dc4cd38d6f9ebfc730b4c14c258c47f480f4c5c546f177/langchain_core-1.3.0-py3-none-any.whl", hash = "sha256:baf16ee028475df177b9ab8869a751c79406d64a6f12125b93802991b566cced", size = 515140, upload-time = "2026-04-17T14:51:36.274Z" },
]
[[package]]
name = "langchain-text-splitters"
-version = "1.1.1"
+version = "1.1.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "langchain-core" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/85/38/14121ead61e0e75f79c3a35e5148ac7c2fe754a55f76eab3eed573269524/langchain_text_splitters-1.1.1.tar.gz", hash = "sha256:34861abe7c07d9e49d4dc852d0129e26b32738b60a74486853ec9b6d6a8e01d2", size = 279352, upload-time = "2026-02-18T23:02:42.798Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/26/9f/6c545900fefb7b00ddfa3f16b80d61338a0ec68c31c5451eeeab99082760/langchain_text_splitters-1.1.2.tar.gz", hash = "sha256:782a723db0a4746ac91e251c7c1d57fd23636e4f38ed733074e28d7a86f41627", size = 293580, upload-time = "2026-04-16T14:20:39.162Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/84/66/d9e0c3b83b0ad75ee746c51ba347cacecb8d656b96e1d513f3e334d1ccab/langchain_text_splitters-1.1.1-py3-none-any.whl", hash = "sha256:5ed0d7bf314ba925041e7d7d17cd8b10f688300d5415fb26c29442f061e329dc", size = 35734, upload-time = "2026-02-18T23:02:41.913Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/26/1ef06f56198d631296d646a6223de35bcc6cf9795ceb2442816bc963b84c/langchain_text_splitters-1.1.2-py3-none-any.whl", hash = "sha256:a2de0d799ff31886429fd6e2e0032df275b60ec817c19059a7b46181cc1c2f10", size = 35903, upload-time = "2026-04-16T14:20:38.243Z" },
]
[[package]]
@@ -3597,7 +3793,7 @@ sdist = { url = "https://files.pythonhosted.org/packages/0e/72/a3add0e4eec4eb9e2
[[package]]
name = "langsmith"
-version = "0.7.31"
+version = "0.7.32"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "httpx" },
@@ -3610,18 +3806,18 @@ dependencies = [
{ name = "xxhash" },
{ name = "zstandard" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/e6/11/696019490992db5c87774dc20515529ef42a01e1d770fb754ed6d9b12fb0/langsmith-0.7.31.tar.gz", hash = "sha256:331ee4f7c26bb5be4022b9859b7d7b122cbf8c9d01d9f530114c1914b0349ffb", size = 1178480, upload-time = "2026-04-14T17:55:41.242Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/2f/b4/a0b4a501bee6b8a741ce29f8c48155b132118483cddc6f9247735ddb38fa/langsmith-0.7.32.tar.gz", hash = "sha256:b59b8e106d0e4c4842e158229296086e2aa7c561e3f602acda73d3ad0062e915", size = 1184518, upload-time = "2026-04-15T23:42:41.885Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/1d/a1/a013cf458c301cda86a213dd153ce0a01c93f1ab5833f951e6a44c9763ce/langsmith-0.7.31-py3-none-any.whl", hash = "sha256:0291d49203f6e80dda011af1afda61eb0595a4d697adb684590a8805e1d61fb6", size = 373276, upload-time = "2026-04-14T17:55:39.677Z" },
+ { url = "https://files.pythonhosted.org/packages/62/bc/148f98ac7dad73ac5e1b1c985290079cfeeb9ba13d760a24f25002beb2c9/langsmith-0.7.32-py3-none-any.whl", hash = "sha256:e1fde928990c4c52f47dc5132708cec674355d9101723d564183e965f383bf5f", size = 378272, upload-time = "2026-04-15T23:42:39.905Z" },
]
[[package]]
name = "latex2mathml"
-version = "3.79.0"
+version = "3.81.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/dd/8d/2161f46485d9c36c0fa0e1c997faf08bb7843027e59b549598e49f55f8bf/latex2mathml-3.79.0.tar.gz", hash = "sha256:11bde318c2d2d6fcdd105a07509d867cee2208f653278eb80243dec7ea77a0ce", size = 151103, upload-time = "2026-03-12T23:25:08.028Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/3b/62/35bb816c5c19d4d0cde5bdfb82ebb996306243d5f94e03f201658c629960/latex2mathml-3.81.0.tar.gz", hash = "sha256:4b959cdc3cac8686bc0e3e5aece8127dfb1b81ca1241bed8e00ef31b82bb4022", size = 77584, upload-time = "2026-04-15T00:55:27.977Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/fd/92/56a954dd59637dd2ee013581fa3beea0821f17f2c07f818fc51dcc11fd10/latex2mathml-3.79.0-py3-none-any.whl", hash = "sha256:9f10720d4fcf6b22d1b81f6628237832419a7a29783c13aa92fa8d680165e63d", size = 73945, upload-time = "2026-03-12T23:25:09.466Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/b1/c488b530994c4f68e46efa99a4d6ca6741aaf158e35779fe6c4d8a9a427d/latex2mathml-3.81.0-py3-none-any.whl", hash = "sha256:d317710393fe20579aea39cfe8928fa2ad9b8780896e585326c75e89c1d1d1a4", size = 79185, upload-time = "2026-04-15T00:55:29.301Z" },
]
[[package]]
@@ -3794,84 +3990,84 @@ wheels = [
[[package]]
name = "lxml"
-version = "5.3.2"
+version = "6.1.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/80/61/d3dc048cd6c7be6fe45b80cedcbdd4326ba4d550375f266d9f4246d0f4bc/lxml-5.3.2.tar.gz", hash = "sha256:773947d0ed809ddad824b7b14467e1a481b8976e87278ac4a730c2f7c7fcddc1", size = 3679948, upload-time = "2025-04-05T18:31:58.757Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/28/30/9abc9e34c657c33834eaf6cd02124c61bdf5944d802aa48e69be8da3585d/lxml-6.1.0.tar.gz", hash = "sha256:bfd57d8008c4965709a919c3e9a98f76c2c7cb319086b3d26858250620023b13", size = 4197006, upload-time = "2026-04-18T04:32:51.613Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/f7/9c/b015de0277a13d1d51924810b248b8a685a4e3dcd02d2ffb9b4e65cc37f4/lxml-5.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c4b84d6b580a9625dfa47269bf1fd7fbba7ad69e08b16366a46acb005959c395", size = 8144077, upload-time = "2025-04-05T18:25:05.832Z" },
- { url = "https://files.pythonhosted.org/packages/a7/6a/30467f6b66ae666d20b52dffa98c00f0f15e0567d1333d70db7c44a6939e/lxml-5.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b4c08ecb26e4270a62f81f81899dfff91623d349e433b126931c9c4577169666", size = 4423433, upload-time = "2025-04-05T18:25:10.126Z" },
- { url = "https://files.pythonhosted.org/packages/12/85/5a50121c0b57c8aba1beec30d324dc9272a193ecd6c24ad1efb5e223a035/lxml-5.3.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef926e9f11e307b5a7c97b17c5c609a93fb59ffa8337afac8f89e6fe54eb0b37", size = 5230753, upload-time = "2025-04-05T18:25:12.638Z" },
- { url = "https://files.pythonhosted.org/packages/81/07/a62896efbb74ff23e9d19a14713fb9c808dfd89d79eecb8a583d1ca722b1/lxml-5.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:017ceeabe739100379fe6ed38b033cd244ce2da4e7f6f07903421f57da3a19a2", size = 4945993, upload-time = "2025-04-05T18:25:15.63Z" },
- { url = "https://files.pythonhosted.org/packages/74/ca/c47bffbafcd98c53c2ccd26dcb29b2de8fa0585d5afae76e5c5a9dce5f96/lxml-5.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dae97d9435dc90590f119d056d233c33006b2fd235dd990d5564992261ee7ae8", size = 5562292, upload-time = "2025-04-05T18:25:18.744Z" },
- { url = "https://files.pythonhosted.org/packages/8f/79/f4ad46c00b72eb465be2032dad7922a14c929ae983e40cd9a179f1e727db/lxml-5.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:910f39425c6798ce63c93976ae5af5fff6949e2cb446acbd44d6d892103eaea8", size = 5000296, upload-time = "2025-04-05T18:25:21.268Z" },
- { url = "https://files.pythonhosted.org/packages/44/cb/c974078e015990f83d13ef00dac347d74b1d62c2e6ec6e8eeb40ec9a1f1a/lxml-5.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9780de781a0d62a7c3680d07963db3048b919fc9e3726d9cfd97296a65ffce1", size = 5114822, upload-time = "2025-04-05T18:25:24.401Z" },
- { url = "https://files.pythonhosted.org/packages/1b/c4/dde5d197d176f232c018e7dfd1acadf3aeb8e9f3effa73d13b62f9540061/lxml-5.3.2-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:1a06b0c6ba2e3ca45a009a78a4eb4d6b63831830c0a83dcdc495c13b9ca97d3e", size = 4941338, upload-time = "2025-04-05T18:25:27.402Z" },
- { url = "https://files.pythonhosted.org/packages/eb/8b/72f8df23f6955bb0f6aca635f72ec52799104907d6b11317099e79e1c752/lxml-5.3.2-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:4c62d0a34d1110769a1bbaf77871a4b711a6f59c4846064ccb78bc9735978644", size = 5586914, upload-time = "2025-04-05T18:25:30.604Z" },
- { url = "https://files.pythonhosted.org/packages/0f/93/7b5ff2971cc5cf017de8ef0e9fdfca6afd249b1e187cb8195e27ed40bb9a/lxml-5.3.2-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:8f961a4e82f411b14538fe5efc3e6b953e17f5e809c463f0756a0d0e8039b700", size = 5082388, upload-time = "2025-04-05T18:25:33.147Z" },
- { url = "https://files.pythonhosted.org/packages/a3/3e/f81d28bceb4e978a3d450098bdc5364d9c58473ad2f4ded04f679dc76e7e/lxml-5.3.2-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:3dfc78f5f9251b6b8ad37c47d4d0bfe63ceb073a916e5b50a3bf5fd67a703335", size = 5161925, upload-time = "2025-04-05T18:25:36.128Z" },
- { url = "https://files.pythonhosted.org/packages/4d/4b/1218fcfa0dfc8917ce29c66150cc8f6962d35579f412080aec480cc1a990/lxml-5.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10e690bc03214d3537270c88e492b8612d5e41b884f232df2b069b25b09e6711", size = 5022096, upload-time = "2025-04-05T18:25:38.949Z" },
- { url = "https://files.pythonhosted.org/packages/8c/de/8eb6fffecd9c5f129461edcdd7e1ac944f9de15783e3d89c84ed6e0374bc/lxml-5.3.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:aa837e6ee9534de8d63bc4c1249e83882a7ac22bd24523f83fad68e6ffdf41ae", size = 5652903, upload-time = "2025-04-05T18:25:41.991Z" },
- { url = "https://files.pythonhosted.org/packages/95/79/80f4102a08495c100014593680f3f0f7bd7c1333b13520aed855fc993326/lxml-5.3.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:da4c9223319400b97a2acdfb10926b807e51b69eb7eb80aad4942c0516934858", size = 5491813, upload-time = "2025-04-05T18:25:44.983Z" },
- { url = "https://files.pythonhosted.org/packages/15/f5/9b1f7edf6565ee31e4300edb1bcc61eaebe50a3cff4053c0206d8dc772f2/lxml-5.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:dc0e9bdb3aa4d1de703a437576007d366b54f52c9897cae1a3716bb44fc1fc85", size = 5227837, upload-time = "2025-04-05T18:25:47.433Z" },
- { url = "https://files.pythonhosted.org/packages/dd/53/a187c4ccfcd5fbfca01e6c96da39499d8b801ab5dcf57717db95d7a968a8/lxml-5.3.2-cp310-cp310-win32.win32.whl", hash = "sha256:dd755a0a78dd0b2c43f972e7b51a43be518ebc130c9f1a7c4480cf08b4385486", size = 3477533, upload-time = "2025-04-18T06:15:35.546Z" },
- { url = "https://files.pythonhosted.org/packages/f2/2c/397c5a9d76a7a0faf9e5b13143ae1a7e223e71d2197a45da71c21aacb3d4/lxml-5.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:d64ea1686474074b38da13ae218d9fde0d1dc6525266976808f41ac98d9d7980", size = 3805160, upload-time = "2025-04-05T18:25:52.007Z" },
- { url = "https://files.pythonhosted.org/packages/84/b8/2b727f5a90902f7cc5548349f563b60911ca05f3b92e35dfa751349f265f/lxml-5.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9d61a7d0d208ace43986a92b111e035881c4ed45b1f5b7a270070acae8b0bfb4", size = 8163457, upload-time = "2025-04-05T18:25:55.176Z" },
- { url = "https://files.pythonhosted.org/packages/91/84/23135b2dc72b3440d68c8f39ace2bb00fe78e3a2255f7c74f7e76f22498e/lxml-5.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:856dfd7eda0b75c29ac80a31a6411ca12209183e866c33faf46e77ace3ce8a79", size = 4433445, upload-time = "2025-04-05T18:25:57.631Z" },
- { url = "https://files.pythonhosted.org/packages/c9/1c/6900ade2294488f80598af7b3229669562166384bb10bf4c915342a2f288/lxml-5.3.2-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a01679e4aad0727bedd4c9407d4d65978e920f0200107ceeffd4b019bd48529", size = 5029603, upload-time = "2025-04-05T18:26:00.145Z" },
- { url = "https://files.pythonhosted.org/packages/2f/e9/31dbe5deaccf0d33ec279cf400306ad4b32dfd1a0fee1fca40c5e90678fe/lxml-5.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b6b37b4c3acb8472d191816d4582379f64d81cecbdce1a668601745c963ca5cc", size = 4771236, upload-time = "2025-04-05T18:26:02.656Z" },
- { url = "https://files.pythonhosted.org/packages/68/41/c3412392884130af3415af2e89a2007e00b2a782be6fb848a95b598a114c/lxml-5.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3df5a54e7b7c31755383f126d3a84e12a4e0333db4679462ef1165d702517477", size = 5369815, upload-time = "2025-04-05T18:26:05.842Z" },
- { url = "https://files.pythonhosted.org/packages/34/0a/ba0309fd5f990ea0cc05aba2bea225ef1bcb07ecbf6c323c6b119fc46e7f/lxml-5.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c09a40f28dcded933dc16217d6a092be0cc49ae25811d3b8e937c8060647c353", size = 4843663, upload-time = "2025-04-05T18:26:09.143Z" },
- { url = "https://files.pythonhosted.org/packages/b6/c6/663b5d87d51d00d4386a2d52742a62daa486c5dc6872a443409d9aeafece/lxml-5.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1ef20f1851ccfbe6c5a04c67ec1ce49da16ba993fdbabdce87a92926e505412", size = 4918028, upload-time = "2025-04-05T18:26:12.243Z" },
- { url = "https://files.pythonhosted.org/packages/75/5f/f6a72ccbe05cf83341d4b6ad162ed9e1f1ffbd12f1c4b8bc8ae413392282/lxml-5.3.2-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:f79a63289dbaba964eb29ed3c103b7911f2dce28c36fe87c36a114e6bd21d7ad", size = 4792005, upload-time = "2025-04-05T18:26:15.081Z" },
- { url = "https://files.pythonhosted.org/packages/37/7b/8abd5b332252239ffd28df5842ee4e5bf56e1c613c323586c21ccf5af634/lxml-5.3.2-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:75a72697d95f27ae00e75086aed629f117e816387b74a2f2da6ef382b460b710", size = 5405363, upload-time = "2025-04-05T18:26:17.618Z" },
- { url = "https://files.pythonhosted.org/packages/5a/79/549b7ec92b8d9feb13869c1b385a0749d7ccfe5590d1e60f11add9cdd580/lxml-5.3.2-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:b9b00c9ee1cc3a76f1f16e94a23c344e0b6e5c10bec7f94cf2d820ce303b8c01", size = 4932915, upload-time = "2025-04-05T18:26:20.269Z" },
- { url = "https://files.pythonhosted.org/packages/57/eb/4fa626d0bac8b4f2aa1d0e6a86232db030fd0f462386daf339e4a0ee352b/lxml-5.3.2-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:77cbcab50cbe8c857c6ba5f37f9a3976499c60eada1bf6d38f88311373d7b4bc", size = 4983473, upload-time = "2025-04-05T18:26:23.828Z" },
- { url = "https://files.pythonhosted.org/packages/1b/c8/79d61d13cbb361c2c45fbe7c8bd00ea6a23b3e64bc506264d2856c60d702/lxml-5.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:29424058f072a24622a0a15357bca63d796954758248a72da6d512f9bd9a4493", size = 4855284, upload-time = "2025-04-05T18:26:26.504Z" },
- { url = "https://files.pythonhosted.org/packages/80/16/9f84e1ef03a13136ab4f9482c9adaaad425c68b47556b9d3192a782e5d37/lxml-5.3.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7d82737a8afe69a7c80ef31d7626075cc7d6e2267f16bf68af2c764b45ed68ab", size = 5458355, upload-time = "2025-04-05T18:26:29.086Z" },
- { url = "https://files.pythonhosted.org/packages/aa/6d/f62860451bb4683e87636e49effb76d499773337928e53356c1712ccec24/lxml-5.3.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:95473d1d50a5d9fcdb9321fdc0ca6e1edc164dce4c7da13616247d27f3d21e31", size = 5300051, upload-time = "2025-04-05T18:26:31.723Z" },
- { url = "https://files.pythonhosted.org/packages/3f/5f/3b6c4acec17f9a57ea8bb89a658a70621db3fb86ea588e7703b6819d9b03/lxml-5.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2162068f6da83613f8b2a32ca105e37a564afd0d7009b0b25834d47693ce3538", size = 5033481, upload-time = "2025-04-05T18:26:34.312Z" },
- { url = "https://files.pythonhosted.org/packages/79/bd/3c4dd7d903bb9981f4876c61ef2ff5d5473e409ef61dc7337ac207b91920/lxml-5.3.2-cp311-cp311-win32.whl", hash = "sha256:f8695752cf5d639b4e981afe6c99e060621362c416058effd5c704bede9cb5d1", size = 3474266, upload-time = "2025-04-05T18:26:36.545Z" },
- { url = "https://files.pythonhosted.org/packages/1f/ea/9311fa1ef75b7d601c89600fc612838ee77ad3d426184941cba9cf62641f/lxml-5.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:d1a94cbb4ee64af3ab386c2d63d6d9e9cf2e256ac0fd30f33ef0a3c88f575174", size = 3815230, upload-time = "2025-04-05T18:26:39.486Z" },
- { url = "https://files.pythonhosted.org/packages/0d/7e/c749257a7fabc712c4df57927b0f703507f316e9f2c7e3219f8f76d36145/lxml-5.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:16b3897691ec0316a1aa3c6585f61c8b7978475587c5b16fc1d2c28d283dc1b0", size = 8193212, upload-time = "2025-04-05T18:26:42.692Z" },
- { url = "https://files.pythonhosted.org/packages/a8/50/17e985ba162c9f1ca119f4445004b58f9e5ef559ded599b16755e9bfa260/lxml-5.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a8d4b34a0eeaf6e73169dcfd653c8d47f25f09d806c010daf074fba2db5e2d3f", size = 4451439, upload-time = "2025-04-05T18:26:46.468Z" },
- { url = "https://files.pythonhosted.org/packages/c2/b5/4960ba0fcca6ce394ed4a2f89ee13083e7fcbe9641a91166e8e9792fedb1/lxml-5.3.2-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9cd7a959396da425022e1e4214895b5cfe7de7035a043bcc2d11303792b67554", size = 5052146, upload-time = "2025-04-05T18:26:49.737Z" },
- { url = "https://files.pythonhosted.org/packages/5f/d1/184b04481a5d1f5758916de087430752a7b229bddbd6c1d23405078c72bd/lxml-5.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cac5eaeec3549c5df7f8f97a5a6db6963b91639389cdd735d5a806370847732b", size = 4789082, upload-time = "2025-04-05T18:26:52.295Z" },
- { url = "https://files.pythonhosted.org/packages/7d/75/1a19749d373e9a3d08861addccdf50c92b628c67074b22b8f3c61997cf5a/lxml-5.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29b5f7d77334877c2146e7bb8b94e4df980325fab0a8af4d524e5d43cd6f789d", size = 5312300, upload-time = "2025-04-05T18:26:54.923Z" },
- { url = "https://files.pythonhosted.org/packages/fb/00/9d165d4060d3f347e63b219fcea5c6a3f9193e9e2868c6801e18e5379725/lxml-5.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13f3495cfec24e3d63fffd342cc8141355d1d26ee766ad388775f5c8c5ec3932", size = 4836655, upload-time = "2025-04-05T18:26:57.488Z" },
- { url = "https://files.pythonhosted.org/packages/b8/e9/06720a33cc155966448a19677f079100517b6629a872382d22ebd25e48aa/lxml-5.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e70ad4c9658beeff99856926fd3ee5fde8b519b92c693f856007177c36eb2e30", size = 4961795, upload-time = "2025-04-05T18:27:00.126Z" },
- { url = "https://files.pythonhosted.org/packages/2d/57/4540efab2673de2904746b37ef7f74385329afd4643ed92abcc9ec6e00ca/lxml-5.3.2-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:507085365783abd7879fa0a6fa55eddf4bdd06591b17a2418403bb3aff8a267d", size = 4779791, upload-time = "2025-04-05T18:27:03.061Z" },
- { url = "https://files.pythonhosted.org/packages/99/ad/6056edf6c9f4fa1d41e6fbdae52c733a4a257fd0d7feccfa26ae051bb46f/lxml-5.3.2-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:5bb304f67cbf5dfa07edad904732782cbf693286b9cd85af27059c5779131050", size = 5346807, upload-time = "2025-04-05T18:27:05.877Z" },
- { url = "https://files.pythonhosted.org/packages/a1/fa/5be91fc91a18f3f705ea5533bc2210b25d738c6b615bf1c91e71a9b2f26b/lxml-5.3.2-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:3d84f5c093645c21c29a4e972b84cb7cf682f707f8706484a5a0c7ff13d7a988", size = 4909213, upload-time = "2025-04-05T18:27:08.588Z" },
- { url = "https://files.pythonhosted.org/packages/f3/74/71bb96a3b5ae36b74e0402f4fa319df5559a8538577f8c57c50f1b57dc15/lxml-5.3.2-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:bdc13911db524bd63f37b0103af014b7161427ada41f1b0b3c9b5b5a9c1ca927", size = 4987694, upload-time = "2025-04-05T18:27:11.66Z" },
- { url = "https://files.pythonhosted.org/packages/08/c2/3953a68b0861b2f97234b1838769269478ccf872d8ea7a26e911238220ad/lxml-5.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1ec944539543f66ebc060ae180d47e86aca0188bda9cbfadff47d86b0dc057dc", size = 4862865, upload-time = "2025-04-05T18:27:14.194Z" },
- { url = "https://files.pythonhosted.org/packages/e0/9a/52e48f7cfd5a5e61f44a77e679880580dfb4f077af52d6ed5dd97e3356fe/lxml-5.3.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:59d437cc8a7f838282df5a199cf26f97ef08f1c0fbec6e84bd6f5cc2b7913f6e", size = 5423383, upload-time = "2025-04-05T18:27:16.988Z" },
- { url = "https://files.pythonhosted.org/packages/17/67/42fe1d489e4dcc0b264bef361aef0b929fbb2b5378702471a3043bc6982c/lxml-5.3.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e275961adbd32e15672e14e0cc976a982075208224ce06d149c92cb43db5b93", size = 5286864, upload-time = "2025-04-05T18:27:19.703Z" },
- { url = "https://files.pythonhosted.org/packages/29/e4/03b1d040ee3aaf2bd4e1c2061de2eae1178fe9a460d3efc1ea7ef66f6011/lxml-5.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:038aeb6937aa404480c2966b7f26f1440a14005cb0702078c173c028eca72c31", size = 5056819, upload-time = "2025-04-05T18:27:22.814Z" },
- { url = "https://files.pythonhosted.org/packages/83/b3/e2ec8a6378e4d87da3af9de7c862bcea7ca624fc1a74b794180c82e30123/lxml-5.3.2-cp312-cp312-win32.whl", hash = "sha256:3c2c8d0fa3277147bff180e3590be67597e17d365ce94beb2efa3138a2131f71", size = 3486177, upload-time = "2025-04-05T18:27:25.078Z" },
- { url = "https://files.pythonhosted.org/packages/d5/8a/6a08254b0bab2da9573735725caab8302a2a1c9b3818533b41568ca489be/lxml-5.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:77809fcd97dfda3f399102db1794f7280737b69830cd5c961ac87b3c5c05662d", size = 3817134, upload-time = "2025-04-05T18:27:27.481Z" },
- { url = "https://files.pythonhosted.org/packages/19/fe/904fd1b0ba4f42ed5a144fcfff7b8913181892a6aa7aeb361ee783d441f8/lxml-5.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:77626571fb5270ceb36134765f25b665b896243529eefe840974269b083e090d", size = 8173598, upload-time = "2025-04-05T18:27:31.229Z" },
- { url = "https://files.pythonhosted.org/packages/97/e8/5e332877b3ce4e2840507b35d6dbe1cc33b17678ece945ba48d2962f8c06/lxml-5.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:78a533375dc7aa16d0da44af3cf6e96035e484c8c6b2b2445541a5d4d3d289ee", size = 4441586, upload-time = "2025-04-05T18:27:33.883Z" },
- { url = "https://files.pythonhosted.org/packages/de/f4/8fe2e6d8721803182fbce2325712e98f22dbc478126070e62731ec6d54a0/lxml-5.3.2-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a6f62b2404b3f3f0744bbcabb0381c5fe186fa2a9a67ecca3603480f4846c585", size = 5038447, upload-time = "2025-04-05T18:27:36.426Z" },
- { url = "https://files.pythonhosted.org/packages/a6/ac/fa63f86a1a4b1ba8b03599ad9e2f5212fa813223ac60bfe1155390d1cc0c/lxml-5.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ea918da00091194526d40c30c4996971f09dacab032607581f8d8872db34fbf", size = 4783583, upload-time = "2025-04-05T18:27:39.492Z" },
- { url = "https://files.pythonhosted.org/packages/1a/7a/08898541296a02c868d4acc11f31a5839d80f5b21d4a96f11d4c0fbed15e/lxml-5.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c35326f94702a7264aa0eea826a79547d3396a41ae87a70511b9f6e9667ad31c", size = 5305684, upload-time = "2025-04-05T18:27:42.16Z" },
- { url = "https://files.pythonhosted.org/packages/0b/be/9a6d80b467771b90be762b968985d3de09e0d5886092238da65dac9c1f75/lxml-5.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3bef90af21d31c4544bc917f51e04f94ae11b43156356aff243cdd84802cbf2", size = 4830797, upload-time = "2025-04-05T18:27:45.071Z" },
- { url = "https://files.pythonhosted.org/packages/8d/1c/493632959f83519802637f7db3be0113b6e8a4e501b31411fbf410735a75/lxml-5.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52fa7ba11a495b7cbce51573c73f638f1dcff7b3ee23697467dc063f75352a69", size = 4950302, upload-time = "2025-04-05T18:27:47.979Z" },
- { url = "https://files.pythonhosted.org/packages/c7/13/01aa3b92a6b93253b90c061c7527261b792f5ae7724b420cded733bfd5d6/lxml-5.3.2-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:ad131e2c4d2c3803e736bb69063382334e03648de2a6b8f56a878d700d4b557d", size = 4775247, upload-time = "2025-04-05T18:27:51.174Z" },
- { url = "https://files.pythonhosted.org/packages/60/4a/baeb09fbf5c84809e119c9cf8e2e94acec326a9b45563bf5ae45a234973b/lxml-5.3.2-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:00a4463ca409ceacd20490a893a7e08deec7870840eff33dc3093067b559ce3e", size = 5338824, upload-time = "2025-04-05T18:27:54.15Z" },
- { url = "https://files.pythonhosted.org/packages/69/c7/a05850f169ad783ed09740ac895e158b06d25fce4b13887a8ac92a84d61c/lxml-5.3.2-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:87e8d78205331cace2b73ac8249294c24ae3cba98220687b5b8ec5971a2267f1", size = 4899079, upload-time = "2025-04-05T18:27:57.03Z" },
- { url = "https://files.pythonhosted.org/packages/de/48/18ca583aba5235582db0e933ed1af6540226ee9ca16c2ee2d6f504fcc34a/lxml-5.3.2-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:bf6389133bb255e530a4f2f553f41c4dd795b1fbb6f797aea1eff308f1e11606", size = 4978041, upload-time = "2025-04-05T18:27:59.918Z" },
- { url = "https://files.pythonhosted.org/packages/b6/55/6968ddc88554209d1dba0dca196360c629b3dfe083bc32a3370f9523a0c4/lxml-5.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b3709fc752b42fb6b6ffa2ba0a5b9871646d97d011d8f08f4d5b3ee61c7f3b2b", size = 4859761, upload-time = "2025-04-05T18:28:02.83Z" },
- { url = "https://files.pythonhosted.org/packages/2e/52/d2d3baa1e0b7d04a729613160f1562f466fb1a0e45085a33acb0d6981a2b/lxml-5.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:abc795703d0de5d83943a4badd770fbe3d1ca16ee4ff3783d7caffc252f309ae", size = 5418209, upload-time = "2025-04-05T18:28:05.851Z" },
- { url = "https://files.pythonhosted.org/packages/d3/50/6005b297ba5f858a113d6e81ccdb3a558b95a615772e7412d1f1cbdf22d7/lxml-5.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:98050830bb6510159f65d9ad1b8aca27f07c01bb3884ba95f17319ccedc4bcf9", size = 5274231, upload-time = "2025-04-05T18:28:08.849Z" },
- { url = "https://files.pythonhosted.org/packages/fb/33/6f40c09a5f7d7e7fcb85ef75072e53eba3fbadbf23e4991ca069ab2b1abb/lxml-5.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6ba465a91acc419c5682f8b06bcc84a424a7aa5c91c220241c6fd31de2a72bc6", size = 5051899, upload-time = "2025-04-05T18:28:11.729Z" },
- { url = "https://files.pythonhosted.org/packages/8b/3a/673bc5c0d5fb6596ee2963dd016fdaefaed2c57ede82c7634c08cbda86c1/lxml-5.3.2-cp313-cp313-win32.whl", hash = "sha256:56a1d56d60ea1ec940f949d7a309e0bff05243f9bd337f585721605670abb1c1", size = 3485315, upload-time = "2025-04-05T18:28:14.815Z" },
- { url = "https://files.pythonhosted.org/packages/8c/be/cab8dd33b0dbe3af5b5d4d24137218f79ea75d540f74eb7d8581195639e0/lxml-5.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:1a580dc232c33d2ad87d02c8a3069d47abbcdce974b9c9cc82a79ff603065dbe", size = 3814639, upload-time = "2025-04-05T18:28:17.268Z" },
- { url = "https://files.pythonhosted.org/packages/3d/1a/480682ac974e0f8778503300a61d96c3b4d992d2ae024f9db18d5fd895d1/lxml-5.3.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:521ab9c80b98c30b2d987001c3ede2e647e92eeb2ca02e8cb66ef5122d792b24", size = 3937182, upload-time = "2025-04-05T18:30:39.214Z" },
- { url = "https://files.pythonhosted.org/packages/74/e6/ac87269713e372b58c4334913601a65d7a6f3b7df9ac15a4a4014afea7ae/lxml-5.3.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f1231b0f9810289d41df1eacc4ebb859c63e4ceee29908a0217403cddce38d0", size = 4235148, upload-time = "2025-04-05T18:30:42.261Z" },
- { url = "https://files.pythonhosted.org/packages/75/ec/7d7af58047862fb59fcdec6e3abcffc7a98f7f7560e580485169ce28b706/lxml-5.3.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271f1a4d5d2b383c36ad8b9b489da5ea9c04eca795a215bae61ed6a57cf083cd", size = 4349974, upload-time = "2025-04-05T18:30:45.291Z" },
- { url = "https://files.pythonhosted.org/packages/ff/de/021ef34a57a372778f44182d2043fa3cae0b0407ac05fc35834f842586f2/lxml-5.3.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:6fca8a5a13906ba2677a5252752832beb0f483a22f6c86c71a2bb320fba04f61", size = 4238656, upload-time = "2025-04-05T18:30:48.383Z" },
- { url = "https://files.pythonhosted.org/packages/0a/96/00874cb83ebb2cf649f2a8cad191d8da64fe1cf15e6580d5a7967755d6a3/lxml-5.3.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:ea0c3b7922209160faef194a5b6995bfe7fa05ff7dda6c423ba17646b7b9de10", size = 4373836, upload-time = "2025-04-05T18:30:52.189Z" },
- { url = "https://files.pythonhosted.org/packages/6b/40/7d49ff503cc90b03253eba0768feec909b47ce92a90591b025c774a29a95/lxml-5.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0a006390834603e5952a2ff74b9a31a6007c7cc74282a087aa6467afb4eea987", size = 3487898, upload-time = "2025-04-05T18:30:55.122Z" },
+ { url = "https://files.pythonhosted.org/packages/02/6e/ee8fc0e01202eb3dd2b9e1ea4f0910d72425d35c66187c63931d7a3ea73f/lxml-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:41dcc4c7b10484257cbd6c37b83ddb26df2b0e5aff5ac00d095689015af868ec", size = 8540733, upload-time = "2026-04-18T04:27:33.185Z" },
+ { url = "https://files.pythonhosted.org/packages/54/e8/325fe9b942824c773dffe1baf0c35b046a763851fdff4393af4450bceeb7/lxml-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a31286dbb5e74c8e9a5344465b77ab4c5bd511a253b355b5ca2fae7e579fafec", size = 4602805, upload-time = "2026-04-18T04:27:36.097Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/81/221aa3ea4a40370bb0358fa454cbe7e5a837e522f7630c24dfef3f9a73b0/lxml-6.1.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1bc4cc83fb7f66ffb16f74d6dd0162e144333fc36ebcce32246f80c8735b2551", size = 5002652, upload-time = "2026-04-18T04:27:30.603Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/e1/fdbfb9019542f1875c093576df7f37adc2983c8ba7ecf17e5f14490bc107/lxml-6.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:20cf4d0651987c906a2f5cba4e3a8d6ba4bfdf973cfe2a96c0d6053888ea2ecd", size = 5155332, upload-time = "2026-04-18T04:27:33.507Z" },
+ { url = "https://files.pythonhosted.org/packages/56/b1/4087c782fff397cd03abf9c551069be59bb04a7e548c50fb7b9c4cdaca28/lxml-6.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ffb34ea45a82dd637c2c97ae1bbb920850c1e59bcae79ce1c15af531d83e7215", size = 5057226, upload-time = "2026-04-18T04:27:37.567Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/66/516c79dec8417f3a972327330254c0b5fac93d5c3ecfd8a5b43650a5a4d9/lxml-6.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a1d9b99e5b2597e4f5aed2484fef835256fa1b68a19e4265c97628ef4bf8bcf4", size = 5287588, upload-time = "2026-04-18T04:27:41.4Z" },
+ { url = "https://files.pythonhosted.org/packages/94/1d/e578f4cbeb42b9df9f29b0d44a45a7cdfa3a5ae300dd59ec68e3602d29bb/lxml-6.1.0-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:d43aa26dcda363f21e79afa0668f5029ed7394b3bb8c92a6927a3d34e8b610ea", size = 5412438, upload-time = "2026-04-18T04:27:45.589Z" },
+ { url = "https://files.pythonhosted.org/packages/47/5b/2aa68307d6d15959e84d4882f9c04f2da63127eac463e1594166f681ef77/lxml-6.1.0-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:6262b87f9e5c1e5fe501d6c153247289af42eb44ad7660b9b3de17baaf92d6f6", size = 4770997, upload-time = "2026-04-18T04:27:49.853Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/c9/3e51fc1228310a836b4eb32595ae00154ab12197fca944676a3ab3b163ea/lxml-6.1.0-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d1392c569c032f78a11a25d1de1c43fff13294c793b39e19d84fade3045cbbc3", size = 5359678, upload-time = "2026-04-18T04:31:56.184Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/91/ab8bc834f977fbbd310e697b120787c153db026f9151e02a88d2645d4e5b/lxml-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:045e387d1f4f42a418380930fa3f45c73c9b392faf67e495e58902e68e8f44a7", size = 5107890, upload-time = "2026-04-18T04:32:00.387Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/10/8a143cfa3ac99cb5b0523ff6d0429a9c9dddf25ffeae09caa3866c7964d9/lxml-6.1.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:9f93d5b8b07f73e8c77e3c6556a3db269918390c804b5e5fcdd4858232cc8f16", size = 4803977, upload-time = "2026-04-18T04:32:05.099Z" },
+ { url = "https://files.pythonhosted.org/packages/45/fd/ee02faf52fa39c2fe32f824628958b9aa86dff21343dc3161f0e3c6ccd15/lxml-6.1.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:de550d129f18d8ab819651ffe4f38b1b713c7e116707de3c0c6400d0ef34fbc1", size = 5350277, upload-time = "2026-04-18T04:32:09.176Z" },
+ { url = "https://files.pythonhosted.org/packages/85/8c/b3481364b8554b5d36d540189a87fc71e94b0b01c24f8f152bd662dd2e45/lxml-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c08da09dc003c9e8c70e06b53a11db6fb3b250c21c4236b03c7d7b443c318e7a", size = 5309717, upload-time = "2026-04-18T04:32:13.303Z" },
+ { url = "https://files.pythonhosted.org/packages/74/e8/a6b21927077a9127afa17473b6576b322616f34ac50ee4f577e763b75ec0/lxml-6.1.0-cp310-cp310-win32.whl", hash = "sha256:37448bf9c7d7adfc5254763901e2bbd6bb876228dfc1fc7f66e58c06368a7544", size = 3598491, upload-time = "2026-04-18T04:27:24.288Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/82/14dea800d041274d96c07d49ff9191f011d1427450850de19bf541e2cc12/lxml-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:2593a0a6621545b9095b71ad74ed4226eba438a7d9fc3712a99bdb15508cf93a", size = 4020906, upload-time = "2026-04-18T04:27:27.53Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/ba/d3539aaf4d9d21456b9a7b902816623227d05d63e7c5aafd8834c4b9bed6/lxml-6.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:e80807d72f96b96ad5588cb85c75616e4f2795a7737d4630784c51497beb7776", size = 3667787, upload-time = "2026-04-18T04:27:29.407Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/5d/3bccad330292946f97962df9d5f2d3ae129cce6e212732a781e856b91e07/lxml-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cec05be8c876f92a5aa07b01d60bbb4d11cfbdd654cad0561c0d7b5c043a61b9", size = 8526232, upload-time = "2026-04-18T04:27:40.389Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/51/adc8826570a112f83bb4ddb3a2ab510bbc2ccd62c1b9fe1f34fae2d90b57/lxml-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9c03e048b6ce8e77b09c734e931584894ecd58d08296804ca2d0b184c933ce50", size = 4595448, upload-time = "2026-04-18T04:27:44.208Z" },
+ { url = "https://files.pythonhosted.org/packages/54/84/5a9ec07cbe1d2334a6465f863b949a520d2699a755738986dcd3b6b89e3f/lxml-6.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:942454ff253da14218f972b23dc72fa4edf6c943f37edd19cd697618b626fac5", size = 4923771, upload-time = "2026-04-18T04:32:17.402Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/23/851cfa33b6b38adb628e45ad51fb27105fa34b2b3ba9d1d4aa7a9428dfe0/lxml-6.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d036ee7b99d5148072ac7c9b847193decdfeac633db350363f7bce4fff108f0e", size = 5068101, upload-time = "2026-04-18T04:32:21.437Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/38/41bf99c2023c6b79916ba057d83e9db21d642f473cac210201222882d38b/lxml-6.1.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ae5d8d5427f3cc317e7950f2da7ad276df0cfa37b8de2f5658959e618ea8512", size = 5002573, upload-time = "2026-04-18T04:32:25.373Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/20/053aa10bdc39747e1e923ce2d45413075e84f70a136045bb09e5eaca41d3/lxml-6.1.0-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:363e47283bde87051b821826e71dde47f107e08614e1aa312ba0c5711e77738c", size = 5202816, upload-time = "2026-04-18T04:32:29.393Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/da/bc710fad8bf04b93baee752c192eaa2210cd3a84f969d0be7830fea55802/lxml-6.1.0-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:f504d861d9f2a8f94020130adac88d66de93841707a23a86244263d1e54682f5", size = 5329999, upload-time = "2026-04-18T04:32:34.019Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/cb/bf035dedbdf7fab49411aa52e4236f3445e98d38647d85419e6c0d2806b9/lxml-6.1.0-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:23a5dc68e08ed13331d61815c08f260f46b4a60fdd1640bbeb82cf89a9d90289", size = 4659643, upload-time = "2026-04-18T04:32:37.932Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/4f/22be31f33727a5e4c7b01b0a874503026e50329b259d3587e0b923cf964b/lxml-6.1.0-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f15401d8d3dbf239e23c818afc10c7207f7b95f9a307e092122b6f86dd43209a", size = 5265963, upload-time = "2026-04-18T04:32:41.881Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/2b/d44d0e5c79226017f4ab8c87a802ebe4f89f97e6585a8e4166dffcdd7b6e/lxml-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fcf3da95e93349e0647d48d4b36a12783105bcc74cb0c416952f9988410846a3", size = 5045444, upload-time = "2026-04-18T04:32:44.512Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/c3/3f034fec1594c331a6dbf9491238fdcc9d66f68cc529e109ec75b97197e1/lxml-6.1.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:0d082495c5fcf426e425a6e28daaba1fcb6d8f854a4ff01effb1f1f381203eb9", size = 4712703, upload-time = "2026-04-18T04:32:47.16Z" },
+ { url = "https://files.pythonhosted.org/packages/12/16/0b83fccc158218aca75a7aa33e97441df737950734246b9fffa39301603d/lxml-6.1.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:e3c4f84b24a1fcba435157d111c4b755099c6ff00a3daee1ad281817de75ed11", size = 5252745, upload-time = "2026-04-18T04:32:50.427Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/ee/12e6c1b39a77666c02eaa77f94a870aaf63c4ac3a497b2d52319448b01c6/lxml-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:976a6b39b1b13e8c354ad8d3f261f3a4ac6609518af91bdb5094760a08f132c4", size = 5226822, upload-time = "2026-04-18T04:32:53.437Z" },
+ { url = "https://files.pythonhosted.org/packages/34/20/c7852904858b4723af01d2fc14b5d38ff57cb92f01934a127ebd9a9e51aa/lxml-6.1.0-cp311-cp311-win32.whl", hash = "sha256:857efde87d365706590847b916baff69c0bc9252dc5af030e378c9800c0b10e3", size = 3594026, upload-time = "2026-04-18T04:27:31.903Z" },
+ { url = "https://files.pythonhosted.org/packages/02/05/d60c732b56da5085175c07c74b2df4e6d181b0c9a61e1691474f06ef4b39/lxml-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:183bfb45a493081943be7ea2b5adfc2b611e1cf377cefa8b8a8be404f45ef9a7", size = 4025114, upload-time = "2026-04-18T04:27:34.077Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/df/c84dcc175fd690823436d15b41cb920cd5ba5e14cd8bfb00949d5903b320/lxml-6.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:19f4164243fc206d12ed3d866e80e74f5bc3627966520da1a5f97e42c32a3f39", size = 3667742, upload-time = "2026-04-18T04:27:38.45Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/d4/9326838b59dc36dfae42eec9656b97520f9997eee1de47b8316aaeed169c/lxml-6.1.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d2f17a16cd8751e8eb233a7e41aecdf8e511712e00088bf9be455f604cd0d28d", size = 8570663, upload-time = "2026-04-18T04:27:48.253Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/a4/053745ce1f8303ccbb788b86c0db3a91b973675cefc42566a188637b7c40/lxml-6.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f0cea5b1d3e6e77d71bd2b9972eb2446221a69dc52bb0b9c3c6f6e5700592d93", size = 4624024, upload-time = "2026-04-18T04:27:52.594Z" },
+ { url = "https://files.pythonhosted.org/packages/90/97/a517944b20f8fd0932ad2109482bee4e29fe721416387a363306667941f6/lxml-6.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fc46da94826188ed45cb53bd8e3fc076ae22675aea2087843d4735627f867c6d", size = 4930895, upload-time = "2026-04-18T04:32:56.29Z" },
+ { url = "https://files.pythonhosted.org/packages/94/7c/e08a970727d556caa040a44773c7b7e3ad0f0d73dedc863543e9a8b931f2/lxml-6.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9147d8e386ec3b82c3b15d88927f734f565b0aaadef7def562b853adca45784a", size = 5093820, upload-time = "2026-04-18T04:32:58.94Z" },
+ { url = "https://files.pythonhosted.org/packages/88/ee/2a5c2aa2c32016a226ca25d3e1056a8102ea6e1fe308bf50213586635400/lxml-6.1.0-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5715e0e28736a070f3f34a7ccc09e2fdcba0e3060abbcf61a1a5718ff6d6b105", size = 5005790, upload-time = "2026-04-18T04:33:01.272Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/38/a0db9be8f38ad6043ab9429487c128dd1d30f07956ef43040402f8da49e8/lxml-6.1.0-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4937460dc5df0cdd2f06a86c285c28afda06aefa3af949f9477d3e8df430c485", size = 5630827, upload-time = "2026-04-18T04:33:04.036Z" },
+ { url = "https://files.pythonhosted.org/packages/31/ba/3c13d3fc24b7cacf675f808a3a1baabf43a30d0cd24c98f94548e9aa58eb/lxml-6.1.0-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bc783ee3147e60a25aa0445ea82b3e8aabb83b240f2b95d32cb75587ff781814", size = 5240445, upload-time = "2026-04-18T04:33:06.87Z" },
+ { url = "https://files.pythonhosted.org/packages/55/ba/eeef4ccba09b2212fe239f46c1692a98db1878e0872ae320756488878a94/lxml-6.1.0-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:40d9189f80075f2e1f88db21ef815a2b17b28adf8e50aaf5c789bfe737027f32", size = 5350121, upload-time = "2026-04-18T04:33:09.365Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/01/1da87c7b587c38d0cbe77a01aae3b9c1c49ed47d76918ef3db8fc151b1ca/lxml-6.1.0-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:05b9b8787e35bec69e68daf4952b2e6dfcfb0db7ecf1a06f8cdfbbac4eb71aad", size = 4694949, upload-time = "2026-04-18T04:33:11.628Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/88/7db0fe66d5aaf128443ee1623dec3db1576f3e4c17751ec0ef5866468590/lxml-6.1.0-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0f0f08beb0182e3e9a86fae124b3c47a7b41b7b69b225e1377db983802404e54", size = 5243901, upload-time = "2026-04-18T04:33:13.95Z" },
+ { url = "https://files.pythonhosted.org/packages/00/a8/1346726af7d1f6fca1f11223ba34001462b0a3660416986d37641708d57c/lxml-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73becf6d8c81d4c76b1014dbd3584cb26d904492dcf73ca85dc8bff08dcd6d2d", size = 5048054, upload-time = "2026-04-18T04:33:16.965Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/b7/85057012f035d1a0c87e02f8c723ca3c3e6e0728bcf4cb62080b21b1c1e3/lxml-6.1.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1ae225f66e5938f4fa29d37e009a3bb3b13032ac57eb4eb42afa44f6e4054e69", size = 4777324, upload-time = "2026-04-18T04:33:19.832Z" },
+ { url = "https://files.pythonhosted.org/packages/75/6c/ad2f94a91073ef570f33718040e8e160d5fb93331cf1ab3ca1323f939e2d/lxml-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:690022c7fae793b0489aa68a658822cea83e0d5933781811cabbf5ea3bcfe73d", size = 5645702, upload-time = "2026-04-18T04:33:22.436Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/89/0bb6c0bd549c19004c60eea9dc554dd78fd647b72314ef25d460e0d208c6/lxml-6.1.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:63aeafc26aac0be8aff14af7871249e87ea1319be92090bfd632ec68e03b16a5", size = 5232901, upload-time = "2026-04-18T04:33:26.21Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/d9/d609a11fb567da9399f525193e2b49847b5a409cdebe737f06a8b7126bdc/lxml-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:264c605ab9c0e4aa1a679636f4582c4d3313700009fac3ec9c3412ed0d8f3e1d", size = 5261333, upload-time = "2026-04-18T04:33:28.984Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/3a/ac3f99ec8ac93089e7dd556f279e0d14c24de0a74a507e143a2e4b496e7c/lxml-6.1.0-cp312-cp312-win32.whl", hash = "sha256:56971379bc5ee8037c5a0f09fa88f66cdb7d37c3e38af3e45cf539f41131ac1f", size = 3596289, upload-time = "2026-04-18T04:27:42.819Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/a7/0a915557538593cb1bbeedcd40e13c7a261822c26fecbbdb71dad0c2f540/lxml-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:bba078de0031c219e5dd06cf3e6bf8fb8e6e64a77819b358f53bb132e3e03366", size = 3997059, upload-time = "2026-04-18T04:27:46.764Z" },
+ { url = "https://files.pythonhosted.org/packages/92/96/a5dc078cf0126fbfbc35611d77ecd5da80054b5893e28fb213a5613b9e1d/lxml-6.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:c3592631e652afa34999a088f98ba7dfc7d6aff0d535c410bea77a71743f3819", size = 3659552, upload-time = "2026-04-18T04:27:51.133Z" },
+ { url = "https://files.pythonhosted.org/packages/08/03/69347590f1cf4a6d5a4944bb6099e6d37f334784f16062234e1f892fdb1d/lxml-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a0092f2b107b69601adf562a57c956fbb596e05e3e6651cabd3054113b007e45", size = 8559689, upload-time = "2026-04-18T04:31:57.785Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/58/25e00bb40b185c974cfe156c110474d9a8a8390d5f7c92a4e328189bb60e/lxml-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fc7140d7a7386e6b545d41b7358f4d02b656d4053f5fa6859f92f4b9c2572c4d", size = 4617892, upload-time = "2026-04-18T04:32:01.78Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/54/92ad98a94ac318dc4f97aaac22ff8d1b94212b2ae8af5b6e9b354bf825f7/lxml-6.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:419c58fc92cc3a2c3fa5f78c63dbf5da70c1fa9c1b25f25727ecee89a96c7de2", size = 4923489, upload-time = "2026-04-18T04:33:31.401Z" },
+ { url = "https://files.pythonhosted.org/packages/15/3b/a20aecfab42bdf4f9b390590d345857ad3ffd7c51988d1c89c53a0c73faf/lxml-6.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:37fabd1452852636cf38ecdcc9dd5ca4bba7a35d6c53fa09725deeb894a87491", size = 5082162, upload-time = "2026-04-18T04:33:34.262Z" },
+ { url = "https://files.pythonhosted.org/packages/45/26/2cdb3d281ac1bd175603e290cbe4bad6eff127c0f8de90bafd6f8548f0fd/lxml-6.1.0-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2853c8b2170cc6cd54a6b4d50d2c1a8a7aeca201f23804b4898525c7a152cfc", size = 4993247, upload-time = "2026-04-18T04:33:36.674Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/05/d735aef963740022a08185c84821f689fc903acb3d50326e6b1e9886cc22/lxml-6.1.0-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8e369cbd690e788c8d15e56222d91a09c6a417f49cbc543040cba0fe2e25a79e", size = 5613042, upload-time = "2026-04-18T04:33:39.205Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/b8/ead7c10efff731738c72e59ed6eb5791854879fbed7ae98781a12006263a/lxml-6.1.0-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e69aa6805905807186eb00e66c6d97a935c928275182eb02ee40ba00da9623b2", size = 5228304, upload-time = "2026-04-18T04:33:41.647Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/10/e9842d2ec322ea65f0a7270aa0315a53abed06058b88ef1b027f620e7a5f/lxml-6.1.0-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:4bd1bdb8a9e0e2dd229de19b5f8aebac80e916921b4b2c6ef8a52bc131d0c1f9", size = 5341578, upload-time = "2026-04-18T04:33:44.596Z" },
+ { url = "https://files.pythonhosted.org/packages/89/54/40d9403d7c2775fa7301d3ddd3464689bfe9ba71acc17dfff777071b4fdc/lxml-6.1.0-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:cbd7b79cdcb4986ad78a2662625882747f09db5e4cd7b2ae178a88c9c51b3dfe", size = 4700209, upload-time = "2026-04-18T04:33:47.552Z" },
+ { url = "https://files.pythonhosted.org/packages/85/b2/bbdcc2cf45dfc7dfffef4fd97e5c47b15919b6a365247d95d6f684ef5e82/lxml-6.1.0-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:43e4d297f11080ec9d64a4b1ad7ac02b4484c9f0e2179d9c4ef78e886e747b88", size = 5232365, upload-time = "2026-04-18T04:33:50.249Z" },
+ { url = "https://files.pythonhosted.org/packages/48/5a/b06875665e53aaba7127611a7bed3b7b9658e20b22bc2dd217a0b7ab0091/lxml-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cc16682cc987a3da00aa56a3aa3075b08edb10d9b1e476938cfdbee8f3b67181", size = 5043654, upload-time = "2026-04-18T04:33:52.71Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/9c/e71a069d09641c1a7abeb30e693f828c7c90a41cbe3d650b2d734d876f85/lxml-6.1.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d6d8efe71429635f0559579092bb5e60560d7b9115ee38c4adbea35632e7fa24", size = 4769326, upload-time = "2026-04-18T04:33:55.244Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/06/7a9cd84b3d4ed79adf35f874750abb697dec0b4a81a836037b36e47c091a/lxml-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7e39ab3a28af7784e206d8606ec0e4bcad0190f63a492bca95e94e5a4aef7f6e", size = 5635879, upload-time = "2026-04-18T04:33:58.509Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/f0/9d57916befc1e54c451712c7ee48e9e74e80ae4d03bdce49914e0aee42cd/lxml-6.1.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:9eb667bf50856c4a58145f8ca2d5e5be160191e79eb9e30855a476191b3c3495", size = 5224048, upload-time = "2026-04-18T04:34:00.943Z" },
+ { url = "https://files.pythonhosted.org/packages/99/75/90c4eefda0c08c92221fe0753db2d6699a4c628f76ff4465ec20dea84cc1/lxml-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7f4a77d6f7edf9230cee3e1f7f6764722a41604ee5681844f18db9a81ea0ec33", size = 5250241, upload-time = "2026-04-18T04:34:03.365Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/73/16596f7e4e38fa33084b9ccbccc22a15f82a290a055126f2c1541236d2ff/lxml-6.1.0-cp313-cp313-win32.whl", hash = "sha256:28902146ffbe5222df411c5d19e5352490122e14447e98cd118907ee3fd6ee62", size = 3596938, upload-time = "2026-04-18T04:31:56.206Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/63/981401c5680c1eb30893f00a19641ac80db5d1e7086c62cb4b13ed813038/lxml-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:4a1503c56e4e2b38dc76f2f2da7bae69670c0f1933e27cfa34b2fa5876410b16", size = 3995728, upload-time = "2026-04-18T04:31:58.763Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/e8/c358a38ac3e541d16a1b527e4e9cb78c0419b0506a070ace11777e5e8404/lxml-6.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:e0af85773850417d994d019741239b901b22c6680206f46a34766926e466141d", size = 3658372, upload-time = "2026-04-18T04:32:03.629Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/88/55143966481409b1740a3ac669e611055f49efd68087a5ce41582325db3e/lxml-6.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:546b66c0dd1bb8d9fa89d7123e5fa19a8aff3a1f2141eb22df96112afb17b842", size = 3930134, upload-time = "2026-04-18T04:32:35.008Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/97/28b985c2983938d3cb696dd5501423afb90a8c3e869ef5d3c62569282c0f/lxml-6.1.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5cfa1a34df366d9dc0d5eaf420f4cf2bb1e1bebe1066d1c2fc28c179f8a4004c", size = 4210749, upload-time = "2026-04-18T04:36:03.626Z" },
+ { url = "https://files.pythonhosted.org/packages/29/67/dfab2b7d58214921935ccea7ce9b3df9b7d46f305d12f0f532ac7cf6b804/lxml-6.1.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:db88156fcf544cdbf0d95588051515cfdfd4c876fc66444eb98bceb5d6db76de", size = 4318463, upload-time = "2026-04-18T04:36:06.309Z" },
+ { url = "https://files.pythonhosted.org/packages/32/a2/4ac7eb32a4d997dd352c32c32399aae27b3f268d440e6f9cfa405b575d2f/lxml-6.1.0-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:07f98f5496f96bf724b1e3c933c107f0cbf2745db18c03d2e13a291c3afd2635", size = 4251124, upload-time = "2026-04-18T04:36:09.056Z" },
+ { url = "https://files.pythonhosted.org/packages/33/ef/d6abd850bb4822f9b720cfe36b547a558e694881010ff7d012191e8769c6/lxml-6.1.0-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4642e04449a1e164b5ff71ffd901ddb772dfabf5c9adf1b7be5dffe1212bc037", size = 4401758, upload-time = "2026-04-18T04:36:11.803Z" },
+ { url = "https://files.pythonhosted.org/packages/40/44/3ee09a5b60cb44c4f2fbc1c9015cfd6ff5afc08f991cab295d3024dcbf2d/lxml-6.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:7da13bb6fbadfafb474e0226a30570a3445cfd47c86296f2446dafbd77079ace", size = 3508860, upload-time = "2026-04-18T04:32:48.619Z" },
]
[[package]]
@@ -4306,6 +4502,32 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" },
]
+[[package]]
+name = "msal"
+version = "1.36.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "cryptography" },
+ { name = "pyjwt", extra = ["crypto"] },
+ { name = "requests" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/de/cb/b02b0f748ac668922364ccb3c3bff5b71628a05f5adfec2ba2a5c3031483/msal-1.36.0.tar.gz", hash = "sha256:3f6a4af2b036b476a4215111c4297b4e6e236ed186cd804faefba23e4990978b", size = 174217, upload-time = "2026-04-09T10:20:33.525Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2a/d3/414d1f0a5f6f4fe5313c2b002c54e78a3332970feb3f5fed14237aa17064/msal-1.36.0-py3-none-any.whl", hash = "sha256:36ecac30e2ff4322d956029aabce3c82301c29f0acb1ad89b94edcabb0e58ec4", size = 121547, upload-time = "2026-04-09T10:20:32.336Z" },
+]
+
+[[package]]
+name = "msal-extensions"
+version = "1.3.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "msal" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/01/99/5d239b6156eddf761a636bded1118414d161bd6b7b37a9335549ed159396/msal_extensions-1.3.1.tar.gz", hash = "sha256:c5b0fd10f65ef62b5f1d62f4251d51cbcaf003fcedae8c91b040a488614be1a4", size = 23315, upload-time = "2025-03-14T23:51:03.902Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5e/75/bd9b7bb966668920f06b200e84454c8f3566b102183bc55c5473d96cb2b9/msal_extensions-1.3.1-py3-none-any.whl", hash = "sha256:96d3de4d034504e969ac5e85bae8106c8373b5c6568e4c8fa7af2eca9dbe6bca", size = 20583, upload-time = "2025-03-14T23:51:03.016Z" },
+]
+
[[package]]
name = "msgpack"
version = "1.1.2"
@@ -4479,6 +4701,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/56/9e/b7f6b33222978688afc613e25e73776076e996cb5e545e37af8e373d3b3c/multion-1.1.0-py3-none-any.whl", hash = "sha256:6a4ffa2d71c5667e41492993e7136fa71eb4b52f0c11914f3a737ffd543195ca", size = 39968, upload-time = "2024-04-25T03:43:12.22Z" },
]
+[[package]]
+name = "multipart"
+version = "1.3.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/8e/d6/9c4f366d6f9bb8f8fb5eae3acac471335c39510c42b537fd515213d7d8c3/multipart-1.3.1.tar.gz", hash = "sha256:211d7cfc1a7a43e75c4d24ee0e8e0f4f61d522f1a21575303ae85333dea687bf", size = 38929, upload-time = "2026-02-27T10:17:13.7Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl", hash = "sha256:a82b59e1befe74d3d30b3d3f70efd5a2eba4d938f845dcff9faace968888ff29", size = 15061, upload-time = "2026-02-27T10:17:11.943Z" },
+]
+
[[package]]
name = "multiprocess"
version = "0.70.19"
@@ -4944,6 +5175,81 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/be/9c/92789c596b8df838baa98fa71844d84283302f7604ed565dafe5a6b5041a/oauthlib-3.3.1-py3-none-any.whl", hash = "sha256:88119c938d2b8fb88561af5f6ee0eec8cc8d552b7bb1f712743136eb7523b7a1", size = 160065, upload-time = "2025-06-19T22:48:06.508Z" },
]
+[[package]]
+name = "obstore"
+version = "0.8.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a3/8c/9ec984edd0f3b72226adfaa19b1c61b15823b35b52f311ca4af36d009d15/obstore-0.8.2.tar.gz", hash = "sha256:a467bc4e97169e2ba749981b4fd0936015428d9b8f3fb83a5528536b1b6f377f", size = 168852, upload-time = "2025-09-16T15:34:55.786Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e1/e9/0a1e340ef262f225ad71f556ccba257896f85ca197f02cd228fe5e20b45a/obstore-0.8.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:49104c0d72688c180af015b02c691fbb6cf6a45b03a9d71b84059ed92dbec704", size = 3622821, upload-time = "2025-09-16T15:32:53.79Z" },
+ { url = "https://files.pythonhosted.org/packages/24/86/2b53e8b0a838dbbf89ef5dfddde888770bc1a993c691698dae411a407228/obstore-0.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c49776abd416e4d80d003213522d82ad48ed3517bee27a6cf8ce0f0cf4e6337e", size = 3356349, upload-time = "2025-09-16T15:32:55.715Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/79/1ba6dc854d7de7704a2c474d723ffeb01b6884f72eea7cbe128efc472f4a/obstore-0.8.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1636372b5e171a98369612d122ea20b955661daafa6519ed8322f4f0cb43ff74", size = 3454842, upload-time = "2025-09-16T15:32:57.072Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/03/ca67ccc9b9e63cfc0cd069b84437807fed4ef880be1e445b3f29d11518e0/obstore-0.8.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2efed0d86ad4ebffcbe3d0c4d84f26c2c6b20287484a0a748499c169a8e1f2c4", size = 3688363, upload-time = "2025-09-16T15:32:58.164Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/2f/c78eb4352d8be64a072934fe3ff2af79a1d06f4571af7c70d96f9741766b/obstore-0.8.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00c5542616dc5608de82ab6f6820633c9dbab6ff048e770fb8a5fcd1d30cd656", size = 3960133, upload-time = "2025-09-16T15:32:59.614Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/34/9e828d19194e227fd9f1d2dd70710da99c2bd2cd728686d59ea80be10b7c/obstore-0.8.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4d9df46aaf25ce80fff48c53382572adc67b6410611660b798024450281a3129", size = 3925493, upload-time = "2025-09-16T15:33:00.923Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/7d/9ec5967f3e2915fbc441f72c3892a7f0fb3618e3ae5c8a44181ce4aa641c/obstore-0.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ccf0f03a7fe453fb8640611c922bce19f021c6aaeee6ee44d6d8fb57db6be48", size = 3769401, upload-time = "2025-09-16T15:33:02.373Z" },
+ { url = "https://files.pythonhosted.org/packages/85/bf/00b65013068bde630a7369610a2dae4579315cd6ce82d30e3d23315cf308/obstore-0.8.2-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:ddfbfadc88c5e9740b687ef0833384329a56cea07b34f44e1c4b00a0e97d94a9", size = 3534383, upload-time = "2025-09-16T15:33:03.903Z" },
+ { url = "https://files.pythonhosted.org/packages/52/39/1b684fd96c9a33974fc52f417c52b42c1d50df40b44e588853c4a14d9ab1/obstore-0.8.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:53ad53bb16e64102f39559ec470efd78a5272b5e3b84c53aa0423993ac5575c1", size = 3697939, upload-time = "2025-09-16T15:33:05.355Z" },
+ { url = "https://files.pythonhosted.org/packages/85/58/93a2c78935f17fde7e22842598a6373e46a9c32d0243ec3b26b5da92df27/obstore-0.8.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:b0b905b46354db0961ab818cad762b9c1ac154333ae5d341934c90635a6bd7ab", size = 3681746, upload-time = "2025-09-16T15:33:09.344Z" },
+ { url = "https://files.pythonhosted.org/packages/38/90/225c2972338d18f92e7a56f71e34df6935b0b1bd7458bb6a0d2bd4d48f92/obstore-0.8.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fee235694406ebb2dc4178752cf5587f471d6662659b082e9786c716a0a9465c", size = 3765156, upload-time = "2025-09-16T15:33:10.457Z" },
+ { url = "https://files.pythonhosted.org/packages/79/eb/aca27e895bfcbbcd2bf05ea6a2538a94b718e6f6d72986e16ab158b753ec/obstore-0.8.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6c36faf7ace17dd0832aa454118a63ea21862e3d34f71b9297d0c788d00f4985", size = 3941190, upload-time = "2025-09-16T15:33:11.59Z" },
+ { url = "https://files.pythonhosted.org/packages/33/ce/c8251a397e7507521768f05bc355b132a0daaff3739e861e51fa6abd821e/obstore-0.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:948a1db1d34f88cfc7ab7e0cccdcfd84cf3977365634599c95ba03b4ef80d1c4", size = 3970041, upload-time = "2025-09-16T15:33:13.035Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/c4/018f90701f1e5ea3fbd57f61463f42e1ef5218e548d3adcf12b6be021c34/obstore-0.8.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:2edaa97687c191c5324bb939d72f6fe86a7aa8191c410f1648c14e8296d05c1c", size = 3622568, upload-time = "2025-09-16T15:33:14.196Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/62/72dd1e7d52fc554bb1fdb1a9499bda219cf3facea5865a1d97fdc00b3a1b/obstore-0.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c4fb7ef8108f08d14edc8bec9e9a6a2e5c4d14eddb8819f5d0da498aff6e8888", size = 3356109, upload-time = "2025-09-16T15:33:15.315Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/ae/089fe5b9207091252fe5ce352551214f04560f85eb8f2cc4f716a6a1a57e/obstore-0.8.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fda8f658c0edf799ab1e264f9b12c7c184cd09a5272dc645d42e987810ff2772", size = 3454588, upload-time = "2025-09-16T15:33:16.421Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/10/1865ae2d1ba45e8ae85fb0c1aada2dc9533baf60c4dfe74dab905348d74a/obstore-0.8.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87fe2bc15ce4051ecb56abd484feca323c2416628beb62c1c7b6712114564d6e", size = 3688627, upload-time = "2025-09-16T15:33:17.604Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/09/5d7ba6d0aeac563ea5f5586401c677bace4f782af83522b1fdf15430e152/obstore-0.8.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2482aa2562ab6a4ca40250b26bea33f8375b59898a9b5615fd412cab81098123", size = 3959896, upload-time = "2025-09-16T15:33:18.789Z" },
+ { url = "https://files.pythonhosted.org/packages/16/15/2b3eda59914761a9ff4d840e2daec5697fd29b293bd18d3dc11c593aed06/obstore-0.8.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4153b928f5d2e9c6cb645e83668a53e0b42253d1e8bcb4e16571fc0a1434599a", size = 3933162, upload-time = "2025-09-16T15:33:19.935Z" },
+ { url = "https://files.pythonhosted.org/packages/14/7a/5fc63b41526587067537fb1498c59a210884664c65ccf0d1f8f823b0875a/obstore-0.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbfa9c38620cc191be98c8b5558c62071e495dc6b1cc724f38293ee439aa9f92", size = 3769605, upload-time = "2025-09-16T15:33:21.389Z" },
+ { url = "https://files.pythonhosted.org/packages/77/4e/2208ab6e1fc021bf8b7e117249a10ab75d0ed24e0f2de1a8d7cd67d885b5/obstore-0.8.2-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:0822836eae8d52499f10daef17f26855b4c123119c6eb984aa4f2d525ec2678d", size = 3534396, upload-time = "2025-09-16T15:33:22.574Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/8f/a0e2882edd6bd285c82b8a5851c4ecf386c93fe75b6e340d5d9d30e809fc/obstore-0.8.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8ef6435dfd586d83b4f778e7927a5d5b0d8b771e9ba914bc809a13d7805410e6", size = 3697777, upload-time = "2025-09-16T15:33:23.723Z" },
+ { url = "https://files.pythonhosted.org/packages/94/78/ebf0c33bed5c9a8eed3b00eefafbcc0a687eeb1e05451c76fcf199d29ff8/obstore-0.8.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:0f2cba91f4271ca95a932a51aa8dda1537160342b33f7836c75e1eb9d40621a2", size = 3681546, upload-time = "2025-09-16T15:33:24.935Z" },
+ { url = "https://files.pythonhosted.org/packages/af/21/9bf4fb9e53fd5f01af580b6538de2eae857e31d24b0ebfc4d916c306a1e4/obstore-0.8.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:23c876d603af0627627808d19a58d43eb5d8bfd02eecd29460bc9a58030fed55", size = 3765336, upload-time = "2025-09-16T15:33:26.069Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/3c/7f6895c23719482d231b2d6ed328e3223fdf99785f6850fba8d2fc5a86ee/obstore-0.8.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ff3c4b5d07629b70b9dee494cd6b94fff8465c3864752181a1cb81a77190fe42", size = 3941142, upload-time = "2025-09-16T15:33:27.275Z" },
+ { url = "https://files.pythonhosted.org/packages/93/a4/56ccdb756161595680a28f4b0def2c04f7048ffacf128029be8394367b26/obstore-0.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:aadb2cb72de7227d07f4570f82729625ffc77522fadca5cf13c3a37fbe8c8de9", size = 3970172, upload-time = "2025-09-16T15:33:28.393Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/dc/60fefbb5736e69eab56657bca04ca64dc07fdeccb3814164a31b62ad066b/obstore-0.8.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:bb70ce297a47392b1d9a3e310f18d59cd5ebbb9453428210fef02ed60e4d75d1", size = 3612955, upload-time = "2025-09-16T15:33:29.527Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/8b/844e8f382e5a12b8a3796a05d76a03e12c7aedc13d6900419e39207d7868/obstore-0.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1619bf618428abf1f607e0b219b2e230a966dcf697b717deccfa0983dd91f646", size = 3346564, upload-time = "2025-09-16T15:33:30.698Z" },
+ { url = "https://files.pythonhosted.org/packages/89/73/8537f99e09a38a54a6a15ede907aa25d4da089f767a808f0b2edd9c03cec/obstore-0.8.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a4605c3ed7c9515aeb4c619b5f7f2c9986ed4a79fe6045e536b5e59b804b1476", size = 3460809, upload-time = "2025-09-16T15:33:31.837Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/99/7714dec721e43f521d6325a82303a002cddad089437640f92542b84e9cc8/obstore-0.8.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce42670417876dd8668cbb8659e860e9725e5f26bbc86449fd259970e2dd9d18", size = 3692081, upload-time = "2025-09-16T15:33:33.028Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/bd/4ac4175fe95a24c220a96021c25c432bcc0c0212f618be0737184eebbaad/obstore-0.8.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4a3e893b2a06585f651c541c1972fe1e3bf999ae2a5fda052ee55eb7e6516f5", size = 3957466, upload-time = "2025-09-16T15:33:34.528Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/04/caa288fb735484fc5cb019bdf3d896eaccfae0ac4622e520d05692c46790/obstore-0.8.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08462b32f95a9948ed56ed63e88406e2e5a4cae1fde198f9682e0fb8487100ed", size = 3951293, upload-time = "2025-09-16T15:33:35.733Z" },
+ { url = "https://files.pythonhosted.org/packages/44/2f/d380239da2d6a1fda82e17df5dae600a404e8a93a065784518ff8325d5f6/obstore-0.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a0bf7763292a8fc47d01cd66e6f19002c5c6ad4b3ed4e6b2729f5e190fa8a0d", size = 3766199, upload-time = "2025-09-16T15:33:36.904Z" },
+ { url = "https://files.pythonhosted.org/packages/28/41/d391be069d3da82969b54266948b2582aeca5dd735abeda4d63dba36e07b/obstore-0.8.2-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:bcd47f8126cb192cbe86942b8f73b1c45a651ce7e14c9a82c5641dfbf8be7603", size = 3529678, upload-time = "2025-09-16T15:33:38.221Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/4c/4862fdd1a3abde459ee8eea699b1797df638a460af235b18ca82c8fffb72/obstore-0.8.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:57eda9fd8c757c3b4fe36cf3918d7e589cc1286591295cc10b34122fa36dd3fd", size = 3698079, upload-time = "2025-09-16T15:33:39.696Z" },
+ { url = "https://files.pythonhosted.org/packages/68/ca/014e747bc53b570059c27e3565b2316fbe5c107d4134551f4cd3e24aa667/obstore-0.8.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ea44442aad8992166baa69f5069750979e4c5d9ffce772e61565945eea5774b9", size = 3687154, upload-time = "2025-09-16T15:33:40.92Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/89/6db5f8edd93028e5b8bfbeee15e6bd3e56f72106107d31cb208b57659de4/obstore-0.8.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:41496a3ab8527402db4142aaaf0d42df9d7d354b13ba10d9c33e0e48dd49dd96", size = 3773444, upload-time = "2025-09-16T15:33:42.123Z" },
+ { url = "https://files.pythonhosted.org/packages/26/e5/c9e2cc540689c873beb61246e1615d6e38301e6a34dec424f5a5c63c1afd/obstore-0.8.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:43da209803f052df96c7c3cbec512d310982efd2407e4a435632841a51143170", size = 3939315, upload-time = "2025-09-16T15:33:43.252Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/c9/bb53280ca50103c1ffda373cdc9b0f835431060039c2897cbc87ddd92e42/obstore-0.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:1836f5dcd49f9f2950c75889ab5c51fb290d3ea93cdc39a514541e0be3af016e", size = 3978234, upload-time = "2025-09-16T15:33:44.393Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/5d/8c3316cc958d386d5e6ab03e9db9ddc27f8e2141cee4a6777ae5b92f3aac/obstore-0.8.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:212f033e53fe6e53d64957923c5c88949a400e9027f7038c705ec2e9038be563", size = 3612027, upload-time = "2025-09-16T15:33:45.6Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/4d/699359774ce6330130536d008bfc32827fab0c25a00238d015a5974a3d1d/obstore-0.8.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bee21fa4ba148d08fa90e47a96df11161661ed31e09c056a373cb2154b0f2852", size = 3344686, upload-time = "2025-09-16T15:33:47.185Z" },
+ { url = "https://files.pythonhosted.org/packages/82/37/55437341f10512906e02fd9fa69a8a95ad3f2f6a916d3233fda01763d110/obstore-0.8.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4c66594b59832ff1ced4c72575d9beb8b5f9b4e404ac1150a42bfb226617fd50", size = 3459860, upload-time = "2025-09-16T15:33:48.382Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/51/4245a616c94ee4851965e33f7a563ab4090cc81f52cc73227ff9ceca2e46/obstore-0.8.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:089f33af5c2fe132d00214a0c1f40601b28f23a38e24ef9f79fb0576f2730b74", size = 3691648, upload-time = "2025-09-16T15:33:49.524Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/f1/4e2fb24171e3ca3641a4653f006be826e7e17634b11688a5190553b00b83/obstore-0.8.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d87f658dfd340d5d9ea2d86a7c90d44da77a0db9e00c034367dca335735110cf", size = 3956867, upload-time = "2025-09-16T15:33:51.082Z" },
+ { url = "https://files.pythonhosted.org/packages/42/f5/b703115361c798c9c1744e1e700d5908d904a8c2e2bd38bec759c9ffb469/obstore-0.8.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6e2e4fa92828c4fbc2d487f3da2d3588701a1b67d9f6ca3c97cc2afc912e9c63", size = 3950599, upload-time = "2025-09-16T15:33:52.173Z" },
+ { url = "https://files.pythonhosted.org/packages/53/20/08c6dc0f20c1394e2324b9344838e4e7af770cdcb52c30757a475f50daeb/obstore-0.8.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab440e89c5c37a8ec230857dd65147d4b923e0cada33297135d05e0f937d696a", size = 3765865, upload-time = "2025-09-16T15:33:53.291Z" },
+ { url = "https://files.pythonhosted.org/packages/77/20/77907765e29b2eba6bd8821872284d91170d7084f670855b2dfcb249ea14/obstore-0.8.2-cp313-cp313-manylinux_2_24_aarch64.whl", hash = "sha256:b9beed107c5c9cd995d4a73263861fcfbc414d58773ed65c14f80eb18258a932", size = 3529807, upload-time = "2025-09-16T15:33:54.535Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/f5/f629d39cc30d050f52b1bf927e4d65c1cc7d7ffbb8a635cd546b5c5219a0/obstore-0.8.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b75b4e7746292c785e31edcd5aadc8b758238372a19d4c5e394db5c305d7d175", size = 3693629, upload-time = "2025-09-16T15:33:56.016Z" },
+ { url = "https://files.pythonhosted.org/packages/30/ff/106763fd10f2a1cb47f2ef1162293c78ad52f4e73223d8d43fc6b755445d/obstore-0.8.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:f33e6c366869d05ab0b7f12efe63269e631c5450d95d6b4ba4c5faf63f69de70", size = 3686176, upload-time = "2025-09-16T15:33:57.247Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/0c/d2ccb6f32feeca906d5a7c4255340df5262af8838441ca06c9e4e37b67d5/obstore-0.8.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:12c885a9ce5ceb09d13cc186586c0c10b62597eff21b985f6ce8ff9dab963ad3", size = 3773081, upload-time = "2025-09-16T15:33:58.475Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/79/40d1cc504cefc89c9b3dd8874287f3fddc7d963a8748d6dffc5880222013/obstore-0.8.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4accc883b93349a81c9931e15dd318cc703b02bbef2805d964724c73d006d00e", size = 3938589, upload-time = "2025-09-16T15:33:59.734Z" },
+ { url = "https://files.pythonhosted.org/packages/14/dd/916c6777222db3271e9fb3cf9a97ed92b3a9b3e465bdeec96de9ab809d53/obstore-0.8.2-cp313-cp313-win_amd64.whl", hash = "sha256:ec850adf9980e5788a826ccfd5819989724e2a2f712bfa3258e85966c8d9981e", size = 3977768, upload-time = "2025-09-16T15:34:01.25Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/37/14bae1f5bf4369027abc5315cdba2428ad4c16e2fd3bd5d35b7ee584aa0c/obstore-0.8.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6ea04118980a9c22fc8581225ff4507b6a161baf8949d728d96e68326ebaab59", size = 3624857, upload-time = "2025-09-16T15:34:35.601Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/c4/8cba91629aa20479ba86a57c2c2b3bc0a54fc6a31a4594014213603efae6/obstore-0.8.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5f33a7570b6001b54252260fbec18c3f6d21e25d3ec57e9b6c5e7330e8290eb2", size = 3355999, upload-time = "2025-09-16T15:34:36.954Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/10/3e40557d6d9c38c5a0f7bac1508209b9dbb8c4da918ddfa9326ba9a1de3f/obstore-0.8.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:11fa78dfb749edcf5a041cd6db20eae95b3e8b09dfdd9b38d14939da40e7c115", size = 3457322, upload-time = "2025-09-16T15:34:38.143Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/01/dcf7988350c286683698cbdd8c15498aec43cbca72eaabad06fd77f0f34a/obstore-0.8.2-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:872bc0921ff88305884546ba05e258ccd95672a03d77db123f0d0563fd3c000b", size = 3689452, upload-time = "2025-09-16T15:34:39.638Z" },
+ { url = "https://files.pythonhosted.org/packages/97/02/643eb2ede58933e47bdbc92786058c83d9aa569826d5bf6e83362d24a27a/obstore-0.8.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:72556a2fbf018edd921286283e5c7eec9f69a21c6d12516d8a44108eceaa526a", size = 3961171, upload-time = "2025-09-16T15:34:41.232Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/5d/c0b515df6089d0f54109de8031a6f6ed31271361948bee90ab8271d22f79/obstore-0.8.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75fa1abf21499dfcfb0328941a175f89a9aa58245bf00e3318fe928e4b10d297", size = 3935988, upload-time = "2025-09-16T15:34:42.501Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/97/114d7bc172bb846472181d6fa3e950172ee1b1ccd11291777303c499dbdd/obstore-0.8.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f54f72f30cd608c4399679781c884bf8a0e816c1977a2fac993bf5e1fb30609f", size = 3771781, upload-time = "2025-09-16T15:34:44.405Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/43/4aa6de6dc406ef5e109b21a5614c34999575de638254deb456703fae24aa/obstore-0.8.2-pp310-pypy310_pp73-manylinux_2_24_aarch64.whl", hash = "sha256:b044ebf1bf7b8f7b0ca309375c1cd9e140be79e072ae8c70bbd5d9b2ad1f7678", size = 3536689, upload-time = "2025-09-16T15:34:45.649Z" },
+ { url = "https://files.pythonhosted.org/packages/06/a5/870ce541aa1a9ee1d9c3e99c2187049bf5a4d278ee9678cc449aae0a4e68/obstore-0.8.2-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:b1326cd2288b64d6fe8857cc22d3a8003b802585fc0741eff2640a8dc35e8449", size = 3700560, upload-time = "2025-09-16T15:34:47.252Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/93/76a5fc3833aaa833b4152950d9cdfd328493a48316c24e32ddefe9b8870f/obstore-0.8.2-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:ba6863230648a9b0e11502d2745d881cf74262720238bc0093c3eabd22a3b24c", size = 3683450, upload-time = "2025-09-16T15:34:49.589Z" },
+ { url = "https://files.pythonhosted.org/packages/15/3c/4c389362c187630c42f61ef9214e67fc336e44b8aafc47cf49ba9ab8007d/obstore-0.8.2-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:887615da9eeefeb2df849d87c380e04877487aa29dbeb367efc3f17f667470d3", size = 3766628, upload-time = "2025-09-16T15:34:51.937Z" },
+ { url = "https://files.pythonhosted.org/packages/03/12/08547e63edf2239ec6660af434602208ab6f394955ef660a6edda13a0bee/obstore-0.8.2-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:4eec1fb32ffa4fb9fe9ad584611ff031927a5c22732b56075ee7204f0e35ebdf", size = 3944069, upload-time = "2025-09-16T15:34:54.108Z" },
+]
+
[[package]]
name = "ocrmac"
version = "1.0.1"
@@ -5056,7 +5362,7 @@ wheels = [
[[package]]
name = "openai"
-version = "2.31.0"
+version = "2.32.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio" },
@@ -5068,9 +5374,9 @@ dependencies = [
{ name = "tqdm" },
{ name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/94/fe/64b3d035780b3188f86c4f6f1bc202e7bb74757ef028802112273b9dcacf/openai-2.31.0.tar.gz", hash = "sha256:43ca59a88fc973ad1848d86b98d7fac207e265ebbd1828b5e4bdfc85f79427a5", size = 684772, upload-time = "2026-04-08T21:01:41.797Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/ed/59/bdcc6b759b8c42dd73afaf5bf8f902c04b37987a5514dbc1c64dba390fef/openai-2.32.0.tar.gz", hash = "sha256:c54b27a9e4cb8d51f0dd94972ffd1a04437efeb259a9e60d8922b8bd26fe55e0", size = 693286, upload-time = "2026-04-15T22:28:19.434Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/66/bc/a8f7c3aa03452fedbb9af8be83e959adba96a6b4a35e416faffcc959c568/openai-2.31.0-py3-none-any.whl", hash = "sha256:44e1344d87e56a493d649b17e2fac519d1368cbb0745f59f1957c4c26de50a0a", size = 1153479, upload-time = "2026-04-08T21:01:39.217Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/c1/d6e64ccd0536bf616556f0cad2b6d94a8125f508d25cfd814b1d2db4e2f1/openai-2.32.0-py3-none-any.whl", hash = "sha256:4dcc9badeb4bf54ad0d187453742f290226d30150890b7890711bda4f32f192f", size = 1162570, upload-time = "2026-04-15T22:28:17.714Z" },
]
[[package]]
@@ -5329,11 +5635,11 @@ wheels = [
[[package]]
name = "packaging"
-version = "26.0"
+version = "26.1"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/df/de/0d2b39fb4af88a0258f3bac87dfcbb48e73fbdea4a2ed0e2213f9a4c2f9a/packaging-26.1.tar.gz", hash = "sha256:f042152b681c4bfac5cae2742a55e103d27ab2ec0f3d88037136b6bfe7c9c5de", size = 215519, upload-time = "2026-04-14T21:12:49.362Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/c2/920ef838e2f0028c8262f16101ec09ebd5969864e5a64c4c05fad0617c56/packaging-26.1-py3-none-any.whl", hash = "sha256:5d9c0669c6285e491e0ced2eee587eaf67b670d94a19e94e3984a481aba6802f", size = 95831, upload-time = "2026-04-14T21:12:47.56Z" },
]
[[package]]
@@ -6729,14 +7035,14 @@ wheels = [
[[package]]
name = "pypdf"
-version = "6.10.1"
+version = "6.10.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/66/79/f2730c42ec7891a75a2fcea2eb4f356872bcbc671b711418060424796612/pypdf-6.10.1.tar.gz", hash = "sha256:62e6ca7f65aaa28b3d192addb44f97296e4be1748f57ed0f4efb2d4915841880", size = 5315704, upload-time = "2026-04-14T12:55:20.996Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/7b/3f/9f2167401c2e94833ca3b69535bad89e533b5de75fefe4197a2c224baec2/pypdf-6.10.2.tar.gz", hash = "sha256:7d09ce108eff6bf67465d461b6ef352dcb8d84f7a91befc02f904455c6eea11d", size = 5315679, upload-time = "2026-04-15T16:37:36.978Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/f0/04/e3aa7f1f14dbc53429cae34666261eb935d99bd61d24756ab94d7e0309da/pypdf-6.10.1-py3-none-any.whl", hash = "sha256:6331940d3bfe75b7e6601d35db7adabab5fc1d716efaeb384e3c0c3957d033de", size = 335606, upload-time = "2026-04-14T12:55:18.941Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/d6/1d5c60cc17bbdf37c1552d9c03862fc6d32c5836732a0415b2d637edc2d0/pypdf-6.10.2-py3-none-any.whl", hash = "sha256:aa53be9826655b51c96741e5d7983ca224d898ac0a77896e64636810517624aa", size = 336308, upload-time = "2026-04-15T16:37:34.851Z" },
]
[[package]]
@@ -6963,11 +7269,11 @@ wheels = [
[[package]]
name = "python-dotenv"
-version = "1.1.1"
+version = "1.2.2"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/f6/b0/4bc07ccd3572a2f9df7e6782f52b0c6c90dcbb803ac4a167702d7d0dfe1e/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab", size = 41978, upload-time = "2025-06-24T04:21:07.341Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" },
]
[[package]]
@@ -7237,7 +7543,7 @@ wheels = [
[[package]]
name = "rapidocr"
-version = "3.8.0"
+version = "3.8.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorlog" },
@@ -7254,7 +7560,7 @@ dependencies = [
{ name = "tqdm" },
]
wheels = [
- { url = "https://files.pythonhosted.org/packages/49/1f/5f815e17c0b02b8f937b5b680b85d0ec5f34b195314dfa8f11ed14a6de03/rapidocr-3.8.0-py3-none-any.whl", hash = "sha256:54abb10883d588120a3390bc447566f1590aea641e127f63a4ca44415fecd18a", size = 15082360, upload-time = "2026-04-08T13:42:15.89Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/4a/fa521d947f0fc7bb304bf11bec4cb66266bd81494588b4cb48dc01001719/rapidocr-3.8.1-py3-none-any.whl", hash = "sha256:650044b1fbce9e6bae5cae462dcf8be754cde11e2f23fc51f65dcc08deae2c46", size = 15080319, upload-time = "2026-04-11T07:13:22.56Z" },
]
[[package]]
@@ -7414,15 +7720,15 @@ wheels = [
[[package]]
name = "rich"
-version = "14.3.3"
+version = "15.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markdown-it-py" },
{ name = "pygments" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/b3/c6/f3b320c27991c46f43ee9d856302c70dc2d0fb2dba4842ff739d5f46b393/rich-14.3.3.tar.gz", hash = "sha256:b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b", size = 230582, upload-time = "2026-02-19T17:23:12.474Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl", hash = "sha256:793431c1f8619afa7d3b52b2cdec859562b950ea0d4b6b505397612db8d5362d", size = 310458, upload-time = "2026-02-19T17:23:13.732Z" },
+ { url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" },
]
[[package]]
@@ -7743,7 +8049,7 @@ wheels = [
[[package]]
name = "scrapfly-sdk"
-version = "0.8.28"
+version = "0.10.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "backoff" },
@@ -7753,14 +8059,14 @@ dependencies = [
{ name = "requests" },
{ name = "urllib3" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/7b/3e/a881968b866ed77cb8a5013aeb100a5a3dd2b502e9a9f955615e15157ad0/scrapfly_sdk-0.8.28.tar.gz", hash = "sha256:051f734ae10fd9b136527f3dc3344abb68ed64822c108b1caff6dc8399c197e0", size = 104208, upload-time = "2026-04-09T16:18:51.793Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/3d/7e/3dd57ac5b80c997fd9ee54a67b9a035eb2170a7fa8f5afa8486179401702/scrapfly_sdk-0.10.0.tar.gz", hash = "sha256:4b14a1a448b723771cbc9dba8bc07394c330028cfa77f656e9c182e7b8ab46ea", size = 105048, upload-time = "2026-04-15T17:31:10.335Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/c7/c6/97a5fbc9ff952c45783303add4c4e431b7a34a020f6dc3adb8f878af0c2a/scrapfly_sdk-0.8.28-py3-none-any.whl", hash = "sha256:116198df90cdbea224d6b0c92d4d74c9ee585fa63c1c5ec9f021b5fc9638fe3f", size = 117920, upload-time = "2026-04-09T16:18:50.356Z" },
+ { url = "https://files.pythonhosted.org/packages/73/9e/d6ebd1b3343bb966dabfe0191578db060417ce6d038c4a24ab96bf2a239f/scrapfly_sdk-0.10.0-py3-none-any.whl", hash = "sha256:26599ee9526196f531aa7e07d03bd6dfdd4172c470caf7ee0b56ce3d001d1768", size = 118828, upload-time = "2026-04-15T17:31:08.905Z" },
]
[[package]]
name = "selenium"
-version = "4.42.0"
+version = "4.43.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "certifi" },
@@ -7770,9 +8076,9 @@ dependencies = [
{ name = "urllib3" },
{ name = "websocket-client" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/33/46/fb93d37749ecf13853739c31c70bd95704310a7defbc57e7101dc4ab2513/selenium-4.42.0.tar.gz", hash = "sha256:4c8ebd84ff96505db4277223648f12e2799e92e13169bc69633a6b24eb066c72", size = 956304, upload-time = "2026-04-09T08:31:20.268Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/09/6a/fe950b498a3c570ab538ad1c2b60f18863eecf077a865eea4459f3fa78a9/selenium-4.43.0.tar.gz", hash = "sha256:bada5c08a989f812728a4b5bea884d8e91894e939a441cc3a025201ce718581e", size = 967747, upload-time = "2026-04-10T06:47:03.149Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/cf/47/9f094f1cffdb54b01da75b45cc29673869458a504b30002797c0c47ac985/selenium-4.42.0-py3-none-any.whl", hash = "sha256:bb29eababf54fa479c95d5fa3fba73889db5d532f3a76addc5b526bbff14fca7", size = 9559171, upload-time = "2026-04-09T08:31:17.38Z" },
+ { url = "https://files.pythonhosted.org/packages/82/c7/0c55fbb0275fc368676ea50514ce7d7839d799a8b3ff8425f380186c7626/selenium-4.43.0-py3-none-any.whl", hash = "sha256:4f97639055dcfa9eadf8ccf549ba7b0e49c655d4e2bde19b9a44e916b754e769", size = 9573091, upload-time = "2026-04-10T06:47:01.134Z" },
]
[[package]]
@@ -7799,15 +8105,15 @@ wheels = [
[[package]]
name = "sentry-sdk"
-version = "2.57.0"
+version = "2.58.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "certifi" },
{ name = "urllib3" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/4f/87/46c0406d8b5ddd026f73adaf5ab75ce144219c41a4830b52df4b9ab55f7f/sentry_sdk-2.57.0.tar.gz", hash = "sha256:4be8d1e71c32fb27f79c577a337ac8912137bba4bcbc64a4ec1da4d6d8dc5199", size = 435288, upload-time = "2026-03-31T09:39:29.264Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/26/b3/fb8291170d0e844173164709fc0fa0c221ed75a5da740c8746f2a83b4eb1/sentry_sdk-2.58.0.tar.gz", hash = "sha256:c1144d947352d54e5b7daa63596d9f848adf684989c06c4f5a659f0c85a18f6f", size = 438764, upload-time = "2026-04-13T17:23:26.265Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/c9/64/982e07b93219cb52e1cca5d272cb579e2f3eb001956c9e7a9a6d106c9473/sentry_sdk-2.57.0-py2.py3-none-any.whl", hash = "sha256:812c8bf5ff3d2f0e89c82f5ce80ab3a6423e102729c4706af7413fd1eb480585", size = 456489, upload-time = "2026-03-31T09:39:27.524Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/eb/d875669993b762556ae8b2efd86219943b4c0864d22204d622a9aee3052b/sentry_sdk-2.58.0-py2.py3-none-any.whl", hash = "sha256:688d1c704ddecf382ea3326f21a67453d4caa95592d722b7c780a36a9d23109e", size = 460919, upload-time = "2026-04-13T17:23:24.675Z" },
]
[[package]]
@@ -7894,7 +8200,7 @@ wheels = [
[[package]]
name = "singlestoredb"
-version = "1.16.9"
+version = "1.16.10"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "parsimonious" },
@@ -7904,14 +8210,14 @@ dependencies = [
{ name = "tomli", marker = "python_full_version < '3.11'" },
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/94/15/4ae4f961f939574f328db4a9d0de8698bdf8b174579274a47625f9f1002e/singlestoredb-1.16.9.tar.gz", hash = "sha256:92e72112268ec362c19b1923eeff7a8da31d756b9ae1060e0eaf8eb03db3596d", size = 376737, upload-time = "2026-02-05T19:28:50.234Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/23/1e/95b27d8a856f174dd33822db476340a207c75be6232b792d669881f2da18/singlestoredb-1.16.10.tar.gz", hash = "sha256:650f952d22e10552b71fac72b08f6df2c72ab71b353950bc43df05a2bdcb2f32", size = 382404, upload-time = "2026-04-13T22:01:51.696Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/75/a8/95612fb8d3fbf0dd7e624ff06e436920bea44365d5e525f388d0740c6c74/singlestoredb-1.16.9-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:d36d8daa58ad0bce924b479535a20c05a063627fdc5f48d680e1787ddf168802", size = 481162, upload-time = "2026-02-05T19:28:39.251Z" },
- { url = "https://files.pythonhosted.org/packages/80/74/014fa784fb27bed36d69bd4dd64b3c776c06c71c7b1b4a6a349d34aa05cf/singlestoredb-1.16.9-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e958dec4387a4f86c14a73167c120f6637281362e281c4329e3d5bdee55dc43", size = 938771, upload-time = "2026-02-05T19:28:40.899Z" },
- { url = "https://files.pythonhosted.org/packages/fe/6a/eb0893d555798582fb594d4dd0f722f4118d845e2f47ffa71866e908c9fd/singlestoredb-1.16.9-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab89d9b3b3c774e44fecb0a1fb179960150a0e56589f6305470c1db3b6404c2b", size = 939633, upload-time = "2026-02-05T19:28:42.988Z" },
- { url = "https://files.pythonhosted.org/packages/d9/80/d02c37233c6dbb7038ac44b1d6a26339e2425667ac813ea562303b23bac6/singlestoredb-1.16.9-cp38-abi3-win32.whl", hash = "sha256:c5141337497856e9c743cdfbf8501416e8dfffd5dbc3d3cc7578f00be0e6a7b9", size = 457977, upload-time = "2026-02-05T19:28:45.33Z" },
- { url = "https://files.pythonhosted.org/packages/00/0b/de8fcacc8e4dff819501401395aeccdb09138e7a2ba6947a7eac1b6f1823/singlestoredb-1.16.9-cp38-abi3-win_amd64.whl", hash = "sha256:7277e82f5900e261742b7476712953a214940ce52b623a7879c6589932be2f55", size = 456492, upload-time = "2026-02-05T19:28:47.146Z" },
- { url = "https://files.pythonhosted.org/packages/24/4b/dbfe36798b1349a231ee28c0791bc04f786701d49fdf77f22f8d265647df/singlestoredb-1.16.9-py3-none-any.whl", hash = "sha256:e632ce2fb3df19aa66f265110224372f5511e1aa995c1b661c8a46ef0bb7099d", size = 424420, upload-time = "2026-02-05T19:28:48.994Z" },
+ { url = "https://files.pythonhosted.org/packages/45/85/c0d2aa1f117c0e5abacee1cae2c25d889e77bc9251833663836c90bb2226/singlestoredb-1.16.10-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:026a12f3eff764b0a98a88694f2513d6d7f0b41106fa59b2d037cf70566538d0", size = 484460, upload-time = "2026-04-13T22:01:40.373Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/01/ab6a4f9904ce80c9864fa9b9b419b56f62edf0df91fbecea6459a6ab8290/singlestoredb-1.16.10-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bfe81d02e96720895d8b7cf92afd07e420244e72a6ed508d072dca41038b7141", size = 942625, upload-time = "2026-04-13T22:01:42.577Z" },
+ { url = "https://files.pythonhosted.org/packages/87/ca/4d64f355ef06dfdebb06afb5cbb29cfb62f1c6762822ff4f26d99c37347c/singlestoredb-1.16.10-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c548e80fd729a728b01496ef6bb474d41632b5940204ad068da3272518676094", size = 943492, upload-time = "2026-04-13T22:01:44.625Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/41/535f3986b37f72cabd3f82789ad8912c8e92f368e2c77b6dff538b1c82e6/singlestoredb-1.16.10-cp38-abi3-win32.whl", hash = "sha256:33fe4be668c99be4a6e7b26723b87732d75656a400598981b5bb684fa79677cf", size = 461298, upload-time = "2026-04-13T22:01:46.312Z" },
+ { url = "https://files.pythonhosted.org/packages/96/2f/4fee1cd75b8ba6c803d410722951b7a95b6f46529de99abab01e0a57df60/singlestoredb-1.16.10-cp38-abi3-win_amd64.whl", hash = "sha256:92afcd147e3cb8d8476f546cfa5f513df57416f314bdca9f99bb94cb32d24137", size = 459811, upload-time = "2026-04-13T22:01:47.814Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/33/c55c9218dd900be4c1692a5024fa3ba3f920e461b701598dc7e82ce2754c/singlestoredb-1.16.10-py3-none-any.whl", hash = "sha256:5df7222bebc34e73673d350f8aae293004fa4139e24bd890f546e7b9cf7af81c", size = 427717, upload-time = "2026-04-13T22:01:49.736Z" },
]
[[package]]
@@ -8442,7 +8748,7 @@ wheels = [
[[package]]
name = "transformers"
-version = "5.5.3"
+version = "5.5.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "huggingface-hub" },
@@ -8456,9 +8762,9 @@ dependencies = [
{ name = "tqdm" },
{ name = "typer" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/af/35/cd5b0d1288e65d2c12db4ce84c1ec1074f7ee9bced040de6c9d69e70d620/transformers-5.5.3.tar.gz", hash = "sha256:3f60128e840b40d352655903552e1eed4f94ed49369a4d43e1bc067bd32d3f50", size = 8226047, upload-time = "2026-04-09T15:52:56.231Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/a5/1e/1e244ab2ab50a863e6b52cc55761910567fa532b69a6740f6e99c5fdbd98/transformers-5.5.4.tar.gz", hash = "sha256:2e67cadba81fc7608cc07c4dd54f524820bc3d95b1cabd0ef3db7733c4f8b82e", size = 8227649, upload-time = "2026-04-13T16:55:55.181Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/a1/0b/f8524551ab2d896dfaca74ddb70a4453d515bbf4ab5451c100c7788ae155/transformers-5.5.3-py3-none-any.whl", hash = "sha256:e48f3ec31dd96505e96e66b63a1e43e1ad7a65749e108d9227caaf51051cdb02", size = 10236257, upload-time = "2026-04-09T15:52:52.866Z" },
+ { url = "https://files.pythonhosted.org/packages/29/fb/162a66789c65e5afa3b051309240c26bf37fbc8fea285b4546ae747995a2/transformers-5.5.4-py3-none-any.whl", hash = "sha256:0bd6281b82966fe5a7a16f553ea517a9db1dee6284d7cb224dfd88fc0dd1c167", size = 10236696, upload-time = "2026-04-13T16:55:51.497Z" },
]
[[package]]
@@ -8981,28 +9287,28 @@ wheels = [
[[package]]
name = "uv"
-version = "0.11.6"
+version = "0.11.7"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/dd/f3/8aceeab67ea69805293ab290e7ca8cc1b61a064d28b8a35c76d8eba063dd/uv-0.11.6.tar.gz", hash = "sha256:e3b21b7e80024c95ff339fcd147ac6fc3dd98d3613c9d45d3a1f4fd1057f127b", size = 4073298, upload-time = "2026-04-09T12:09:01.738Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/9b/7d/17750123a8c8e324627534fe1ae2e7a46689db8492f1a834ab4fd229a7d8/uv-0.11.7.tar.gz", hash = "sha256:46d971489b00bdb27e0aa715e4a5cd4ef2c28ea5b6ef78f2b67bf861eb44b405", size = 4083385, upload-time = "2026-04-15T21:42:55.474Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/1f/fe/4b61a3d5ad9d02e8a4405026ccd43593d7044598e0fa47d892d4dafe44c9/uv-0.11.6-py3-none-linux_armv6l.whl", hash = "sha256:ada04dcf89ddea5b69d27ac9cdc5ef575a82f90a209a1392e930de504b2321d6", size = 23780079, upload-time = "2026-04-09T12:08:56.609Z" },
- { url = "https://files.pythonhosted.org/packages/52/db/d27519a9e1a5ffee9d71af1a811ad0e19ce7ab9ae815453bef39dd479389/uv-0.11.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5be013888420f96879c6e0d3081e7bcf51b539b034a01777041934457dfbedf3", size = 23214721, upload-time = "2026-04-09T12:09:32.228Z" },
- { url = "https://files.pythonhosted.org/packages/a6/8f/4399fa8b882bd7e0efffc829f73ab24d117d490a93e6bc7104a50282b854/uv-0.11.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:ffa5dc1cbb52bdce3b8447e83d1601a57ad4da6b523d77d4b47366db8b1ceb18", size = 21750109, upload-time = "2026-04-09T12:09:24.357Z" },
- { url = "https://files.pythonhosted.org/packages/32/07/5a12944c31c3dda253632da7a363edddb869ed47839d4d92a2dc5f546c93/uv-0.11.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:bfb107b4dade1d2c9e572992b06992d51dd5f2136eb8ceee9e62dd124289e825", size = 23551146, upload-time = "2026-04-09T12:09:10.439Z" },
- { url = "https://files.pythonhosted.org/packages/79/5b/2ec8b0af80acd1016ed596baf205ddc77b19ece288473b01926c4a9cf6db/uv-0.11.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:9e2fe7ce12161d8016b7deb1eaad7905a76ff7afec13383333ca75e0c4b5425d", size = 23331192, upload-time = "2026-04-09T12:09:34.792Z" },
- { url = "https://files.pythonhosted.org/packages/62/7d/eea35935f2112b21c296a3e42645f3e4b1aa8bcd34dcf13345fbd55134b7/uv-0.11.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7ed9c6f70c25e8dfeedddf4eddaf14d353f5e6b0eb43da9a14d3a1033d51d915", size = 23337686, upload-time = "2026-04-09T12:09:18.522Z" },
- { url = "https://files.pythonhosted.org/packages/21/47/2584f5ab618f6ebe9bdefb2f765f2ca8540e9d739667606a916b35449eec/uv-0.11.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d68a013e609cebf82077cbeeb0809ed5e205257814273bfd31e02fc0353bbfc2", size = 25008139, upload-time = "2026-04-09T12:09:03.983Z" },
- { url = "https://files.pythonhosted.org/packages/95/81/497ae5c1d36355b56b97dc59f550c7e89d0291c163a3f203c6f341dff195/uv-0.11.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93f736dddca03dae732c6fdea177328d3bc4bf137c75248f3d433c57416a4311", size = 25712458, upload-time = "2026-04-09T12:09:07.598Z" },
- { url = "https://files.pythonhosted.org/packages/3c/1c/74083238e4fab2672b63575b9008f1ea418b02a714bcfcf017f4f6a309b6/uv-0.11.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e96a66abe53fced0e3389008b8d2eff8278cfa8bb545d75631ae8ceb9c929aba", size = 24915507, upload-time = "2026-04-09T12:08:50.892Z" },
- { url = "https://files.pythonhosted.org/packages/5a/ee/e14fe10ba455a823ed18233f12de6699a601890905420b5c504abf115116/uv-0.11.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b096311b2743b228df911a19532b3f18fa420bf9530547aecd6a8e04bbfaccd", size = 24971011, upload-time = "2026-04-09T12:08:54.016Z" },
- { url = "https://files.pythonhosted.org/packages/3c/a1/7b9c83eaadf98e343317ff6384a7227a4855afd02cdaf9696bcc71ee6155/uv-0.11.6-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:904d537b4a6e798015b4a64ff5622023bd4601b43b6cd1e5f423d63471f5e948", size = 23640234, upload-time = "2026-04-09T12:09:15.735Z" },
- { url = "https://files.pythonhosted.org/packages/d6/51/75ccdd23e76ff1703b70eb82881cd5b4d2a954c9679f8ef7e0136ef2cfab/uv-0.11.6-py3-none-manylinux_2_31_riscv64.musllinux_1_1_riscv64.whl", hash = "sha256:4ed8150c26b5e319381d75ae2ce6aba1e9c65888f4850f4e3b3fa839953c90a5", size = 24452664, upload-time = "2026-04-09T12:09:26.875Z" },
- { url = "https://files.pythonhosted.org/packages/4d/86/ace80fe47d8d48b5e3b5aee0b6eb1a49deaacc2313782870250b3faa36f5/uv-0.11.6-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:1c9218c8d4ac35ca6e617fb0951cc0ab2d907c91a6aea2617de0a5494cf162c0", size = 24494599, upload-time = "2026-04-09T12:09:37.368Z" },
- { url = "https://files.pythonhosted.org/packages/05/2d/4b642669b56648194f026de79bc992cbfc3ac2318b0a8d435f3c284934e8/uv-0.11.6-py3-none-musllinux_1_1_i686.whl", hash = "sha256:9e211c83cc890c569b86a4183fcf5f8b6f0c7adc33a839b699a98d30f1310d3a", size = 24159150, upload-time = "2026-04-09T12:09:13.17Z" },
- { url = "https://files.pythonhosted.org/packages/ae/24/7eecd76fe983a74fed1fc700a14882e70c4e857f1d562a9f2303d4286c12/uv-0.11.6-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:d2a1d2089afdf117ad19a4c1dd36b8189c00ae1ad4135d3bfbfced82342595cf", size = 25164324, upload-time = "2026-04-09T12:08:59.56Z" },
- { url = "https://files.pythonhosted.org/packages/27/e0/bbd4ba7c2e5067bbba617d87d306ec146889edaeeaa2081d3e122178ca08/uv-0.11.6-py3-none-win32.whl", hash = "sha256:6e8344f38fa29f85dcfd3e62dc35a700d2448f8e90381077ef393438dcd5012e", size = 22865693, upload-time = "2026-04-09T12:09:21.415Z" },
- { url = "https://files.pythonhosted.org/packages/a5/33/1983ce113c538a856f2d620d16e39691962ecceef091a84086c5785e32e5/uv-0.11.6-py3-none-win_amd64.whl", hash = "sha256:a28bea69c1186303d1200f155c7a28c449f8a4431e458fcf89360cc7ef546e40", size = 25371258, upload-time = "2026-04-09T12:09:40.52Z" },
- { url = "https://files.pythonhosted.org/packages/35/01/be0873f44b9c9bc250fcbf263367fcfc1f59feab996355bcb6b52fff080d/uv-0.11.6-py3-none-win_arm64.whl", hash = "sha256:a78f6d64b9950e24061bc7ec7f15ff8089ad7f5a976e7b65fcadce58fe02f613", size = 23869585, upload-time = "2026-04-09T12:09:29.425Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/5b/2bb2ab6fe6c78c2be10852482ef0cae5f3171460a6e5e24c32c9a0843163/uv-0.11.7-py3-none-linux_armv6l.whl", hash = "sha256:f422d39530516b1dfb28bb6e90c32bb7dacd50f6a383cd6e40c1a859419fbc8c", size = 23757265, upload-time = "2026-04-15T21:43:14.494Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/f5/36ff27b01e60a88712628c8a5a6003b8e418883c24e084e506095844a797/uv-0.11.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:8b2fe1ec6775dad10183e3fdce430a5b37b7857d49763c884f3a67eaa8ca6f8a", size = 23184529, upload-time = "2026-04-15T21:42:30.225Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/fa/f379be661316698f877e78f4c51e5044be0b6f390803387237ad92c4057f/uv-0.11.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:162fa961a9a081dcea6e889c79f738a5ae56507047e4672964972e33c301bea9", size = 21780167, upload-time = "2026-04-15T21:42:44.942Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/7f/fbed29775b0612f4f5679d3226268f1a347161abc1727b4080fb41d9f46f/uv-0.11.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:5985a15a92bd9a170fc1947abb1fbc3e9828c5a430ad85b5bed8356c20b67a71", size = 23609640, upload-time = "2026-04-15T21:42:22.57Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/de/989a69634a869a22322770120557c2d8cbba5b77ec7cfad326b4ec0f0547/uv-0.11.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:fab0bb43fbbc0ee5b5fee212078d2300c371b725faff7cf72eeaafa0bff0606b", size = 23322484, upload-time = "2026-04-15T21:43:26.52Z" },
+ { url = "https://files.pythonhosted.org/packages/24/08/c1af05ea602eb4eb75d86badb6b0594cc104c3ca83ccf06d9ed4dd2186ad/uv-0.11.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:23d457d6731ebdb83f1bffebe4894edab2ef43c1ec5488433c74300db4958924", size = 23326385, upload-time = "2026-04-15T21:42:41.32Z" },
+ { url = "https://files.pythonhosted.org/packages/68/99/e246962da06383e992ecab55000c62a50fb36efef855ea7264fad4816bf4/uv-0.11.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d6a17507b8139b8803f445a03fd097f732ce8356b1b7b13cdb4dd8ef7f4b2e0", size = 24985751, upload-time = "2026-04-15T21:42:37.777Z" },
+ { url = "https://files.pythonhosted.org/packages/45/2d/b0b68083859579ce811996c1480765ec6a2442b44c451eaef53e6218fbae/uv-0.11.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd48823ca4b505124389f49ae50626ba9f57212b9047738efc95126ed5f3844d", size = 25724160, upload-time = "2026-04-15T21:43:18.762Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/19/5970e89d9e458fd3c4966bbc586a685a1c0ab0a8bf334503f63fa20b925b/uv-0.11.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb91f52ee67e10d5290f2c2897e2171357f1a10966de38d83eefa93d96843b0c", size = 25028512, upload-time = "2026-04-15T21:43:02.721Z" },
+ { url = "https://files.pythonhosted.org/packages/83/eb/4e1557daf6693cb446ed28185664ad6682fd98c6dbac9e433cbc35df450a/uv-0.11.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e4d5e31bea86e1b6e0f5a0f95e14e80018e6f6c0129256d2915a4b3d793644d", size = 24933975, upload-time = "2026-04-15T21:42:18.828Z" },
+ { url = "https://files.pythonhosted.org/packages/68/55/3b517ec8297f110d6981f525cccf26f86e30883fbb9c282769cffbcdcfca/uv-0.11.7-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:ceae53b202ea92bc954759bc7c7570cdcd5c3512fce15701198c19fd2dfb8605", size = 23706403, upload-time = "2026-04-15T21:43:10.664Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/30/7d93a0312d60e147722967036dc8ea37baab4802784bddc22464cb707deb/uv-0.11.7-py3-none-manylinux_2_31_riscv64.musllinux_1_1_riscv64.whl", hash = "sha256:f97e9f4e4d44fb5c4dfaa05e858ef3414a96416a2e4af270ecd88a3e5fb049a9", size = 24495797, upload-time = "2026-04-15T21:42:26.538Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/89/d49480bdab7725d36982793857e461d471bde8e1b7f438ffccee677a7bf8/uv-0.11.7-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:750ee5b96959b807cf442b73dd8b55111862d63f258f896787ea5f06b68aaca9", size = 24580471, upload-time = "2026-04-15T21:42:52.871Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/9f/c57dc03b48be17b564e304eb9ff982890c12dfb888b1ce370788733329ab/uv-0.11.7-py3-none-musllinux_1_1_i686.whl", hash = "sha256:f394331f0507e80ee732cb3df737589de53bed999dd02a6d24682f08c2f8ac4f", size = 24113637, upload-time = "2026-04-15T21:42:34.094Z" },
+ { url = "https://files.pythonhosted.org/packages/13/ba/b87e358b629a68258527e3490e73b7b148770f4d2257842dea3b7981d4e8/uv-0.11.7-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:0df59ab0c6a4b14a763e8445e1c303af9abeb53cdfa4428daf9ff9642c0a3cce", size = 25119850, upload-time = "2026-04-15T21:43:22.529Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/74/16d229e1d8574bcbafa6dc643ac20b70c3e581f42ac31a6f4fd53035ffe3/uv-0.11.7-py3-none-win32.whl", hash = "sha256:553e67cc766d013ce24353fecd4ea5533d2aedcfd35f9fac430e07b1d1f23ed4", size = 22918454, upload-time = "2026-04-15T21:42:58.702Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/1d/b73e473da616ac758b8918fb218febcc46ddf64cba9e03894dfa226b28bd/uv-0.11.7-py3-none-win_amd64.whl", hash = "sha256:5674dfb5944513f4b3735b05c2deba6b1b01151f46729d533d413a9a905f8c5d", size = 25447744, upload-time = "2026-04-15T21:42:48.813Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/bb/e6bfdea92ed270f3445a5a3c17599d041b3f2dbc5026c09e02830a03bbaf/uv-0.11.7-py3-none-win_arm64.whl", hash = "sha256:6158b7e39464f1aa1e040daa0186cae4749a78b5cd80ac769f32ca711b8976b1", size = 23941816, upload-time = "2026-04-15T21:43:06.732Z" },
]
[[package]]
@@ -9088,7 +9394,7 @@ wheels = [
[[package]]
name = "virtualenv"
-version = "21.2.1"
+version = "21.2.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "distlib" },
@@ -9097,9 +9403,9 @@ dependencies = [
{ name = "python-discovery" },
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/97/c5/aff062c66b42e2183201a7ace10c6b2e959a9a16525c8e8ca8e59410d27a/virtualenv-21.2.1.tar.gz", hash = "sha256:b66ffe81301766c0d5e2208fc3576652c59d44e7b731fc5f5ed701c9b537fa78", size = 5844770, upload-time = "2026-04-09T18:47:11.482Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/0c/98/3a7e644e19cb26133488caff231be390579860bbbb3da35913c49a1d0a46/virtualenv-21.2.4.tar.gz", hash = "sha256:b294ef68192638004d72524ce7ef303e9d0cf5a44c95ce2e54a7500a6381cada", size = 5850742, upload-time = "2026-04-14T22:15:31.438Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/20/0e/f083a76cb590e60dff3868779558eefefb8dfb7c9ed020babc7aa014ccbf/virtualenv-21.2.1-py3-none-any.whl", hash = "sha256:bd16b49c53562b28cf1a3ad2f36edb805ad71301dee70ddc449e5c88a9f919a2", size = 5828326, upload-time = "2026-04-09T18:47:09.331Z" },
+ { url = "https://files.pythonhosted.org/packages/27/8d/edd0bd910ff803c308ee9a6b7778621af0d10252219ad9f19ef4d4982a61/virtualenv-21.2.4-py3-none-any.whl", hash = "sha256:29d21e941795206138d0f22f4e45ff7050e5da6c6472299fb7103318763861ac", size = 5831232, upload-time = "2026-04-14T22:15:29.342Z" },
]
[[package]]
@@ -9204,6 +9510,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/6e/d4/ed38dd3b1767193de971e694aa544356e63353c33a85d948166b5ff58b9e/watchfiles-1.1.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e6f39af2eab0118338902798b5aa6664f46ff66bc0280de76fca67a7f262a49", size = 457546, upload-time = "2025-10-14T15:06:13.372Z" },
]
+[[package]]
+name = "wcmatch"
+version = "10.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "bracex" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/79/3e/c0bdc27cf06f4e47680bd5803a07cb3dfd17de84cde92dd217dcb9e05253/wcmatch-10.1.tar.gz", hash = "sha256:f11f94208c8c8484a16f4f48638a85d771d9513f4ab3f37595978801cb9465af", size = 117421, upload-time = "2025-06-22T19:14:02.49Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/eb/d8/0d1d2e9d3fabcf5d6840362adcf05f8cf3cd06a73358140c3a97189238ae/wcmatch-10.1-py3-none-any.whl", hash = "sha256:5848ace7dbb0476e5e55ab63c6bbd529745089343427caa5537f230cc01beb8a", size = 39854, upload-time = "2025-06-22T19:14:00.978Z" },
+]
+
[[package]]
name = "wcwidth"
version = "0.6.0"
@@ -9349,51 +9667,66 @@ wheels = [
[[package]]
name = "wrapt"
-version = "1.17.3"
+version = "2.1.2"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/95/8f/aeb76c5b46e273670962298c23e7ddde79916cb74db802131d49a85e4b7d/wrapt-1.17.3.tar.gz", hash = "sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0", size = 55547, upload-time = "2025-08-12T05:53:21.714Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/2e/64/925f213fdcbb9baeb1530449ac71a4d57fc361c053d06bf78d0c5c7cd80c/wrapt-2.1.2.tar.gz", hash = "sha256:3996a67eecc2c68fd47b4e3c564405a5777367adfd9b8abb58387b63ee83b21e", size = 81678, upload-time = "2026-03-06T02:53:25.134Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/3f/23/bb82321b86411eb51e5a5db3fb8f8032fd30bd7c2d74bfe936136b2fa1d6/wrapt-1.17.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88bbae4d40d5a46142e70d58bf664a89b6b4befaea7b2ecc14e03cedb8e06c04", size = 53482, upload-time = "2025-08-12T05:51:44.467Z" },
- { url = "https://files.pythonhosted.org/packages/45/69/f3c47642b79485a30a59c63f6d739ed779fb4cc8323205d047d741d55220/wrapt-1.17.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b13af258d6a9ad602d57d889f83b9d5543acd471eee12eb51f5b01f8eb1bc2", size = 38676, upload-time = "2025-08-12T05:51:32.636Z" },
- { url = "https://files.pythonhosted.org/packages/d1/71/e7e7f5670c1eafd9e990438e69d8fb46fa91a50785332e06b560c869454f/wrapt-1.17.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd341868a4b6714a5962c1af0bd44f7c404ef78720c7de4892901e540417111c", size = 38957, upload-time = "2025-08-12T05:51:54.655Z" },
- { url = "https://files.pythonhosted.org/packages/de/17/9f8f86755c191d6779d7ddead1a53c7a8aa18bccb7cea8e7e72dfa6a8a09/wrapt-1.17.3-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f9b2601381be482f70e5d1051a5965c25fb3625455a2bf520b5a077b22afb775", size = 81975, upload-time = "2025-08-12T05:52:30.109Z" },
- { url = "https://files.pythonhosted.org/packages/f2/15/dd576273491f9f43dd09fce517f6c2ce6eb4fe21681726068db0d0467096/wrapt-1.17.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:343e44b2a8e60e06a7e0d29c1671a0d9951f59174f3709962b5143f60a2a98bd", size = 83149, upload-time = "2025-08-12T05:52:09.316Z" },
- { url = "https://files.pythonhosted.org/packages/0c/c4/5eb4ce0d4814521fee7aa806264bf7a114e748ad05110441cd5b8a5c744b/wrapt-1.17.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:33486899acd2d7d3066156b03465b949da3fd41a5da6e394ec49d271baefcf05", size = 82209, upload-time = "2025-08-12T05:52:10.331Z" },
- { url = "https://files.pythonhosted.org/packages/31/4b/819e9e0eb5c8dc86f60dfc42aa4e2c0d6c3db8732bce93cc752e604bb5f5/wrapt-1.17.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e6f40a8aa5a92f150bdb3e1c44b7e98fb7113955b2e5394122fa5532fec4b418", size = 81551, upload-time = "2025-08-12T05:52:31.137Z" },
- { url = "https://files.pythonhosted.org/packages/f8/83/ed6baf89ba3a56694700139698cf703aac9f0f9eb03dab92f57551bd5385/wrapt-1.17.3-cp310-cp310-win32.whl", hash = "sha256:a36692b8491d30a8c75f1dfee65bef119d6f39ea84ee04d9f9311f83c5ad9390", size = 36464, upload-time = "2025-08-12T05:53:01.204Z" },
- { url = "https://files.pythonhosted.org/packages/2f/90/ee61d36862340ad7e9d15a02529df6b948676b9a5829fd5e16640156627d/wrapt-1.17.3-cp310-cp310-win_amd64.whl", hash = "sha256:afd964fd43b10c12213574db492cb8f73b2f0826c8df07a68288f8f19af2ebe6", size = 38748, upload-time = "2025-08-12T05:53:00.209Z" },
- { url = "https://files.pythonhosted.org/packages/bd/c3/cefe0bd330d389c9983ced15d326f45373f4073c9f4a8c2f99b50bfea329/wrapt-1.17.3-cp310-cp310-win_arm64.whl", hash = "sha256:af338aa93554be859173c39c85243970dc6a289fa907402289eeae7543e1ae18", size = 36810, upload-time = "2025-08-12T05:52:51.906Z" },
- { url = "https://files.pythonhosted.org/packages/52/db/00e2a219213856074a213503fdac0511203dceefff26e1daa15250cc01a0/wrapt-1.17.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:273a736c4645e63ac582c60a56b0acb529ef07f78e08dc6bfadf6a46b19c0da7", size = 53482, upload-time = "2025-08-12T05:51:45.79Z" },
- { url = "https://files.pythonhosted.org/packages/5e/30/ca3c4a5eba478408572096fe9ce36e6e915994dd26a4e9e98b4f729c06d9/wrapt-1.17.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5531d911795e3f935a9c23eb1c8c03c211661a5060aab167065896bbf62a5f85", size = 38674, upload-time = "2025-08-12T05:51:34.629Z" },
- { url = "https://files.pythonhosted.org/packages/31/25/3e8cc2c46b5329c5957cec959cb76a10718e1a513309c31399a4dad07eb3/wrapt-1.17.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0610b46293c59a3adbae3dee552b648b984176f8562ee0dba099a56cfbe4df1f", size = 38959, upload-time = "2025-08-12T05:51:56.074Z" },
- { url = "https://files.pythonhosted.org/packages/5d/8f/a32a99fc03e4b37e31b57cb9cefc65050ea08147a8ce12f288616b05ef54/wrapt-1.17.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b32888aad8b6e68f83a8fdccbf3165f5469702a7544472bdf41f582970ed3311", size = 82376, upload-time = "2025-08-12T05:52:32.134Z" },
- { url = "https://files.pythonhosted.org/packages/31/57/4930cb8d9d70d59c27ee1332a318c20291749b4fba31f113c2f8ac49a72e/wrapt-1.17.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cccf4f81371f257440c88faed6b74f1053eef90807b77e31ca057b2db74edb1", size = 83604, upload-time = "2025-08-12T05:52:11.663Z" },
- { url = "https://files.pythonhosted.org/packages/a8/f3/1afd48de81d63dd66e01b263a6fbb86e1b5053b419b9b33d13e1f6d0f7d0/wrapt-1.17.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8a210b158a34164de8bb68b0e7780041a903d7b00c87e906fb69928bf7890d5", size = 82782, upload-time = "2025-08-12T05:52:12.626Z" },
- { url = "https://files.pythonhosted.org/packages/1e/d7/4ad5327612173b144998232f98a85bb24b60c352afb73bc48e3e0d2bdc4e/wrapt-1.17.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:79573c24a46ce11aab457b472efd8d125e5a51da2d1d24387666cd85f54c05b2", size = 82076, upload-time = "2025-08-12T05:52:33.168Z" },
- { url = "https://files.pythonhosted.org/packages/bb/59/e0adfc831674a65694f18ea6dc821f9fcb9ec82c2ce7e3d73a88ba2e8718/wrapt-1.17.3-cp311-cp311-win32.whl", hash = "sha256:c31eebe420a9a5d2887b13000b043ff6ca27c452a9a22fa71f35f118e8d4bf89", size = 36457, upload-time = "2025-08-12T05:53:03.936Z" },
- { url = "https://files.pythonhosted.org/packages/83/88/16b7231ba49861b6f75fc309b11012ede4d6b0a9c90969d9e0db8d991aeb/wrapt-1.17.3-cp311-cp311-win_amd64.whl", hash = "sha256:0b1831115c97f0663cb77aa27d381237e73ad4f721391a9bfb2fe8bc25fa6e77", size = 38745, upload-time = "2025-08-12T05:53:02.885Z" },
- { url = "https://files.pythonhosted.org/packages/9a/1e/c4d4f3398ec073012c51d1c8d87f715f56765444e1a4b11e5180577b7e6e/wrapt-1.17.3-cp311-cp311-win_arm64.whl", hash = "sha256:5a7b3c1ee8265eb4c8f1b7d29943f195c00673f5ab60c192eba2d4a7eae5f46a", size = 36806, upload-time = "2025-08-12T05:52:53.368Z" },
- { url = "https://files.pythonhosted.org/packages/9f/41/cad1aba93e752f1f9268c77270da3c469883d56e2798e7df6240dcb2287b/wrapt-1.17.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ab232e7fdb44cdfbf55fc3afa31bcdb0d8980b9b95c38b6405df2acb672af0e0", size = 53998, upload-time = "2025-08-12T05:51:47.138Z" },
- { url = "https://files.pythonhosted.org/packages/60/f8/096a7cc13097a1869fe44efe68dace40d2a16ecb853141394047f0780b96/wrapt-1.17.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9baa544e6acc91130e926e8c802a17f3b16fbea0fd441b5a60f5cf2cc5c3deba", size = 39020, upload-time = "2025-08-12T05:51:35.906Z" },
- { url = "https://files.pythonhosted.org/packages/33/df/bdf864b8997aab4febb96a9ae5c124f700a5abd9b5e13d2a3214ec4be705/wrapt-1.17.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6b538e31eca1a7ea4605e44f81a48aa24c4632a277431a6ed3f328835901f4fd", size = 39098, upload-time = "2025-08-12T05:51:57.474Z" },
- { url = "https://files.pythonhosted.org/packages/9f/81/5d931d78d0eb732b95dc3ddaeeb71c8bb572fb01356e9133916cd729ecdd/wrapt-1.17.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:042ec3bb8f319c147b1301f2393bc19dba6e176b7da446853406d041c36c7828", size = 88036, upload-time = "2025-08-12T05:52:34.784Z" },
- { url = "https://files.pythonhosted.org/packages/ca/38/2e1785df03b3d72d34fc6252d91d9d12dc27a5c89caef3335a1bbb8908ca/wrapt-1.17.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3af60380ba0b7b5aeb329bc4e402acd25bd877e98b3727b0135cb5c2efdaefe9", size = 88156, upload-time = "2025-08-12T05:52:13.599Z" },
- { url = "https://files.pythonhosted.org/packages/b3/8b/48cdb60fe0603e34e05cffda0b2a4adab81fd43718e11111a4b0100fd7c1/wrapt-1.17.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b02e424deef65c9f7326d8c19220a2c9040c51dc165cddb732f16198c168396", size = 87102, upload-time = "2025-08-12T05:52:14.56Z" },
- { url = "https://files.pythonhosted.org/packages/3c/51/d81abca783b58f40a154f1b2c56db1d2d9e0d04fa2d4224e357529f57a57/wrapt-1.17.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:74afa28374a3c3a11b3b5e5fca0ae03bef8450d6aa3ab3a1e2c30e3a75d023dc", size = 87732, upload-time = "2025-08-12T05:52:36.165Z" },
- { url = "https://files.pythonhosted.org/packages/9e/b1/43b286ca1392a006d5336412d41663eeef1ad57485f3e52c767376ba7e5a/wrapt-1.17.3-cp312-cp312-win32.whl", hash = "sha256:4da9f45279fff3543c371d5ababc57a0384f70be244de7759c85a7f989cb4ebe", size = 36705, upload-time = "2025-08-12T05:53:07.123Z" },
- { url = "https://files.pythonhosted.org/packages/28/de/49493f962bd3c586ab4b88066e967aa2e0703d6ef2c43aa28cb83bf7b507/wrapt-1.17.3-cp312-cp312-win_amd64.whl", hash = "sha256:e71d5c6ebac14875668a1e90baf2ea0ef5b7ac7918355850c0908ae82bcb297c", size = 38877, upload-time = "2025-08-12T05:53:05.436Z" },
- { url = "https://files.pythonhosted.org/packages/f1/48/0f7102fe9cb1e8a5a77f80d4f0956d62d97034bbe88d33e94699f99d181d/wrapt-1.17.3-cp312-cp312-win_arm64.whl", hash = "sha256:604d076c55e2fdd4c1c03d06dc1a31b95130010517b5019db15365ec4a405fc6", size = 36885, upload-time = "2025-08-12T05:52:54.367Z" },
- { url = "https://files.pythonhosted.org/packages/fc/f6/759ece88472157acb55fc195e5b116e06730f1b651b5b314c66291729193/wrapt-1.17.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a47681378a0439215912ef542c45a783484d4dd82bac412b71e59cf9c0e1cea0", size = 54003, upload-time = "2025-08-12T05:51:48.627Z" },
- { url = "https://files.pythonhosted.org/packages/4f/a9/49940b9dc6d47027dc850c116d79b4155f15c08547d04db0f07121499347/wrapt-1.17.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a30837587c6ee3cd1a4d1c2ec5d24e77984d44e2f34547e2323ddb4e22eb77", size = 39025, upload-time = "2025-08-12T05:51:37.156Z" },
- { url = "https://files.pythonhosted.org/packages/45/35/6a08de0f2c96dcdd7fe464d7420ddb9a7655a6561150e5fc4da9356aeaab/wrapt-1.17.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:16ecf15d6af39246fe33e507105d67e4b81d8f8d2c6598ff7e3ca1b8a37213f7", size = 39108, upload-time = "2025-08-12T05:51:58.425Z" },
- { url = "https://files.pythonhosted.org/packages/0c/37/6faf15cfa41bf1f3dba80cd3f5ccc6622dfccb660ab26ed79f0178c7497f/wrapt-1.17.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6fd1ad24dc235e4ab88cda009e19bf347aabb975e44fd5c2fb22a3f6e4141277", size = 88072, upload-time = "2025-08-12T05:52:37.53Z" },
- { url = "https://files.pythonhosted.org/packages/78/f2/efe19ada4a38e4e15b6dff39c3e3f3f73f5decf901f66e6f72fe79623a06/wrapt-1.17.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ed61b7c2d49cee3c027372df5809a59d60cf1b6c2f81ee980a091f3afed6a2d", size = 88214, upload-time = "2025-08-12T05:52:15.886Z" },
- { url = "https://files.pythonhosted.org/packages/40/90/ca86701e9de1622b16e09689fc24b76f69b06bb0150990f6f4e8b0eeb576/wrapt-1.17.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:423ed5420ad5f5529db9ce89eac09c8a2f97da18eb1c870237e84c5a5c2d60aa", size = 87105, upload-time = "2025-08-12T05:52:17.914Z" },
- { url = "https://files.pythonhosted.org/packages/fd/e0/d10bd257c9a3e15cbf5523025252cc14d77468e8ed644aafb2d6f54cb95d/wrapt-1.17.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e01375f275f010fcbf7f643b4279896d04e571889b8a5b3f848423d91bf07050", size = 87766, upload-time = "2025-08-12T05:52:39.243Z" },
- { url = "https://files.pythonhosted.org/packages/e8/cf/7d848740203c7b4b27eb55dbfede11aca974a51c3d894f6cc4b865f42f58/wrapt-1.17.3-cp313-cp313-win32.whl", hash = "sha256:53e5e39ff71b3fc484df8a522c933ea2b7cdd0d5d15ae82e5b23fde87d44cbd8", size = 36711, upload-time = "2025-08-12T05:53:10.074Z" },
- { url = "https://files.pythonhosted.org/packages/57/54/35a84d0a4d23ea675994104e667ceff49227ce473ba6a59ba2c84f250b74/wrapt-1.17.3-cp313-cp313-win_amd64.whl", hash = "sha256:1f0b2f40cf341ee8cc1a97d51ff50dddb9fcc73241b9143ec74b30fc4f44f6cb", size = 38885, upload-time = "2025-08-12T05:53:08.695Z" },
- { url = "https://files.pythonhosted.org/packages/01/77/66e54407c59d7b02a3c4e0af3783168fff8e5d61def52cda8728439d86bc/wrapt-1.17.3-cp313-cp313-win_arm64.whl", hash = "sha256:7425ac3c54430f5fc5e7b6f41d41e704db073309acfc09305816bc6a0b26bb16", size = 36896, upload-time = "2025-08-12T05:52:55.34Z" },
- { url = "https://files.pythonhosted.org/packages/1f/f6/a933bd70f98e9cf3e08167fc5cd7aaaca49147e48411c0bd5ae701bb2194/wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22", size = 23591, upload-time = "2025-08-12T05:53:20.674Z" },
+ { url = "https://files.pythonhosted.org/packages/da/d2/387594fb592d027366645f3d7cc9b4d7ca7be93845fbaba6d835a912ef3c/wrapt-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b7a86d99a14f76facb269dc148590c01aaf47584071809a70da30555228158c", size = 60669, upload-time = "2026-03-06T02:52:40.671Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/18/3f373935bc5509e7ac444c8026a56762e50c1183e7061797437ca96c12ce/wrapt-2.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a819e39017f95bf7aede768f75915635aa8f671f2993c036991b8d3bfe8dbb6f", size = 61603, upload-time = "2026-03-06T02:54:21.032Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/7a/32758ca2853b07a887a4574b74e28843919103194bb47001a304e24af62f/wrapt-2.1.2-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5681123e60aed0e64c7d44f72bbf8b4ce45f79d81467e2c4c728629f5baf06eb", size = 113632, upload-time = "2026-03-06T02:53:54.121Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/d5/eeaa38f670d462e97d978b3b0d9ce06d5b91e54bebac6fbed867809216e7/wrapt-2.1.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b8b28e97a44d21836259739ae76284e180b18abbb4dcfdff07a415cf1016c3e", size = 115644, upload-time = "2026-03-06T02:54:53.33Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/09/2a41506cb17affb0bdf9d5e2129c8c19e192b388c4c01d05e1b14db23c00/wrapt-2.1.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cef91c95a50596fcdc31397eb6955476f82ae8a3f5a8eabdc13611b60ee380ba", size = 112016, upload-time = "2026-03-06T02:54:43.274Z" },
+ { url = "https://files.pythonhosted.org/packages/64/15/0e6c3f5e87caadc43db279724ee36979246d5194fa32fed489c73643ba59/wrapt-2.1.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dad63212b168de8569b1c512f4eac4b57f2c6934b30df32d6ee9534a79f1493f", size = 114823, upload-time = "2026-03-06T02:54:29.392Z" },
+ { url = "https://files.pythonhosted.org/packages/56/b2/0ad17c8248f4e57bedf44938c26ec3ee194715f812d2dbbd9d7ff4be6c06/wrapt-2.1.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d307aa6888d5efab2c1cde09843d48c843990be13069003184b67d426d145394", size = 111244, upload-time = "2026-03-06T02:54:02.149Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/04/bcdba98c26f2c6522c7c09a726d5d9229120163493620205b2f76bd13c01/wrapt-2.1.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c87cf3f0c85e27b3ac7d9ad95da166bf8739ca215a8b171e8404a2d739897a45", size = 113307, upload-time = "2026-03-06T02:54:12.428Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/1b/5e2883c6bc14143924e465a6fc5a92d09eeabe35310842a481fb0581f832/wrapt-2.1.2-cp310-cp310-win32.whl", hash = "sha256:d1c5fea4f9fe3762e2b905fdd67df51e4be7a73b7674957af2d2ade71a5c075d", size = 57986, upload-time = "2026-03-06T02:54:26.823Z" },
+ { url = "https://files.pythonhosted.org/packages/42/5a/4efc997bccadd3af5749c250b49412793bc41e13a83a486b2b54a33e240c/wrapt-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:d8f7740e1af13dff2684e4d56fe604a7e04d6c94e737a60568d8d4238b9a0c71", size = 60336, upload-time = "2026-03-06T02:54:18Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/f5/a2bb833e20181b937e87c242645ed5d5aa9c373006b0467bfe1a35c727d0/wrapt-2.1.2-cp310-cp310-win_arm64.whl", hash = "sha256:1c6cc827c00dc839350155f316f1f8b4b0c370f52b6a19e782e2bda89600c7dc", size = 58757, upload-time = "2026-03-06T02:53:51.545Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/81/60c4471fce95afa5922ca09b88a25f03c93343f759aae0f31fb4412a85c7/wrapt-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:96159a0ee2b0277d44201c3b5be479a9979cf154e8c82fa5df49586a8e7679bb", size = 60666, upload-time = "2026-03-06T02:52:58.934Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/be/80e80e39e7cb90b006a0eaf11c73ac3a62bbfb3068469aec15cc0bc795de/wrapt-2.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:98ba61833a77b747901e9012072f038795de7fc77849f1faa965464f3f87ff2d", size = 61601, upload-time = "2026-03-06T02:53:00.487Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/be/d7c88cd9293c859fc74b232abdc65a229bb953997995d6912fc85af18323/wrapt-2.1.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:767c0dbbe76cae2a60dd2b235ac0c87c9cccf4898aef8062e57bead46b5f6894", size = 114057, upload-time = "2026-03-06T02:52:44.08Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/25/36c04602831a4d685d45a93b3abea61eca7fe35dab6c842d6f5d570ef94a/wrapt-2.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c691a6bc752c0cc4711cc0c00896fcd0f116abc253609ef64ef930032821842", size = 116099, upload-time = "2026-03-06T02:54:56.74Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/4e/98a6eb417ef551dc277bec1253d5246b25003cf36fdf3913b65cb7657a56/wrapt-2.1.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f3b7d73012ea75aee5844de58c88f44cf62d0d62711e39da5a82824a7c4626a8", size = 112457, upload-time = "2026-03-06T02:53:52.842Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/a6/a6f7186a5297cad8ec53fd7578533b28f795fdf5372368c74bd7e6e9841c/wrapt-2.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:577dff354e7acd9d411eaf4bfe76b724c89c89c8fc9b7e127ee28c5f7bcb25b6", size = 115351, upload-time = "2026-03-06T02:53:32.684Z" },
+ { url = "https://files.pythonhosted.org/packages/97/6f/06e66189e721dbebd5cf20e138acc4d1150288ce118462f2fcbff92d38db/wrapt-2.1.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3d7b6fd105f8b24e5bd23ccf41cb1d1099796524bcc6f7fbb8fe576c44befbc9", size = 111748, upload-time = "2026-03-06T02:53:08.455Z" },
+ { url = "https://files.pythonhosted.org/packages/ef/43/4808b86f499a51370fbdbdfa6cb91e9b9169e762716456471b619fca7a70/wrapt-2.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:866abdbf4612e0b34764922ef8b1c5668867610a718d3053d59e24a5e5fcfc15", size = 113783, upload-time = "2026-03-06T02:53:02.02Z" },
+ { url = "https://files.pythonhosted.org/packages/91/2c/a3f28b8fa7ac2cefa01cfcaca3471f9b0460608d012b693998cd61ef43df/wrapt-2.1.2-cp311-cp311-win32.whl", hash = "sha256:5a0a0a3a882393095573344075189eb2d566e0fd205a2b6414e9997b1b800a8b", size = 57977, upload-time = "2026-03-06T02:53:27.844Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/c3/2b1c7bd07a27b1db885a2fab469b707bdd35bddf30a113b4917a7e2139d2/wrapt-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:64a07a71d2730ba56f11d1a4b91f7817dc79bc134c11516b75d1921a7c6fcda1", size = 60336, upload-time = "2026-03-06T02:54:28.104Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/5c/76ece7b401b088daa6503d6264dd80f9a727df3e6042802de9a223084ea2/wrapt-2.1.2-cp311-cp311-win_arm64.whl", hash = "sha256:b89f095fe98bc12107f82a9f7d570dc83a0870291aeb6b1d7a7d35575f55d98a", size = 58756, upload-time = "2026-03-06T02:53:16.319Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/b6/1db817582c49c7fcbb7df6809d0f515af29d7c2fbf57eb44c36e98fb1492/wrapt-2.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ff2aad9c4cda28a8f0653fc2d487596458c2a3f475e56ba02909e950a9efa6a9", size = 61255, upload-time = "2026-03-06T02:52:45.663Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/16/9b02a6b99c09227c93cd4b73acc3678114154ec38da53043c0ddc1fba0dc/wrapt-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6433ea84e1cfacf32021d2a4ee909554ade7fd392caa6f7c13f1f4bf7b8e8748", size = 61848, upload-time = "2026-03-06T02:53:48.728Z" },
+ { url = "https://files.pythonhosted.org/packages/af/aa/ead46a88f9ec3a432a4832dfedb84092fc35af2d0ba40cd04aea3889f247/wrapt-2.1.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c20b757c268d30d6215916a5fa8461048d023865d888e437fab451139cad6c8e", size = 121433, upload-time = "2026-03-06T02:54:40.328Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/9f/742c7c7cdf58b59085a1ee4b6c37b013f66ac33673a7ef4aaed5e992bc33/wrapt-2.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79847b83eb38e70d93dc392c7c5b587efe65b3e7afcc167aa8abd5d60e8761c8", size = 123013, upload-time = "2026-03-06T02:53:26.58Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/44/2c3dd45d53236b7ed7c646fcf212251dc19e48e599debd3926b52310fafb/wrapt-2.1.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f8fba1bae256186a83d1875b2b1f4e2d1242e8fac0f58ec0d7e41b26967b965c", size = 117326, upload-time = "2026-03-06T02:53:11.547Z" },
+ { url = "https://files.pythonhosted.org/packages/74/e2/b17d66abc26bd96f89dec0ecd0ef03da4a1286e6ff793839ec431b9fae57/wrapt-2.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e3d3b35eedcf5f7d022291ecd7533321c4775f7b9cd0050a31a68499ba45757c", size = 121444, upload-time = "2026-03-06T02:54:09.5Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/62/e2977843fdf9f03daf1586a0ff49060b1b2fc7ff85a7ea82b6217c1ae36e/wrapt-2.1.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:6f2c5390460de57fa9582bc8a1b7a6c86e1a41dfad74c5225fc07044c15cc8d1", size = 116237, upload-time = "2026-03-06T02:54:03.884Z" },
+ { url = "https://files.pythonhosted.org/packages/88/dd/27fc67914e68d740bce512f11734aec08696e6b17641fef8867c00c949fc/wrapt-2.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7dfa9f2cf65d027b951d05c662cc99ee3bd01f6e4691ed39848a7a5fffc902b2", size = 120563, upload-time = "2026-03-06T02:53:20.412Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/9f/b750b3692ed2ef4705cb305bd68858e73010492b80e43d2a4faa5573cbe7/wrapt-2.1.2-cp312-cp312-win32.whl", hash = "sha256:eba8155747eb2cae4a0b913d9ebd12a1db4d860fc4c829d7578c7b989bd3f2f0", size = 58198, upload-time = "2026-03-06T02:53:37.732Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/b2/feecfe29f28483d888d76a48f03c4c4d8afea944dbee2b0cd3380f9df032/wrapt-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:1c51c738d7d9faa0b3601708e7e2eda9bf779e1b601dce6c77411f2a1b324a63", size = 60441, upload-time = "2026-03-06T02:52:47.138Z" },
+ { url = "https://files.pythonhosted.org/packages/44/e1/e328f605d6e208547ea9fd120804fcdec68536ac748987a68c47c606eea8/wrapt-2.1.2-cp312-cp312-win_arm64.whl", hash = "sha256:c8e46ae8e4032792eb2f677dbd0d557170a8e5524d22acc55199f43efedd39bf", size = 58836, upload-time = "2026-03-06T02:53:22.053Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/7a/d936840735c828b38d26a854e85d5338894cda544cb7a85a9d5b8b9c4df7/wrapt-2.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787fd6f4d67befa6fe2abdffcbd3de2d82dfc6fb8a6d850407c53332709d030b", size = 61259, upload-time = "2026-03-06T02:53:41.922Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/88/9a9b9a90ac8ca11c2fdb6a286cb3a1fc7dd774c00ed70929a6434f6bc634/wrapt-2.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4bdf26e03e6d0da3f0e9422fd36bcebf7bc0eeb55fdf9c727a09abc6b9fe472e", size = 61851, upload-time = "2026-03-06T02:52:48.672Z" },
+ { url = "https://files.pythonhosted.org/packages/03/a9/5b7d6a16fd6533fed2756900fc8fc923f678179aea62ada6d65c92718c00/wrapt-2.1.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bbac24d879aa22998e87f6b3f481a5216311e7d53c7db87f189a7a0266dafffb", size = 121446, upload-time = "2026-03-06T02:54:14.013Z" },
+ { url = "https://files.pythonhosted.org/packages/45/bb/34c443690c847835cfe9f892be78c533d4f32366ad2888972c094a897e39/wrapt-2.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:16997dfb9d67addc2e3f41b62a104341e80cac52f91110dece393923c0ebd5ca", size = 123056, upload-time = "2026-03-06T02:54:10.829Z" },
+ { url = "https://files.pythonhosted.org/packages/93/b9/ff205f391cb708f67f41ea148545f2b53ff543a7ac293b30d178af4d2271/wrapt-2.1.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:162e4e2ba7542da9027821cb6e7c5e068d64f9a10b5f15512ea28e954893a267", size = 117359, upload-time = "2026-03-06T02:53:03.623Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/3d/1ea04d7747825119c3c9a5e0874a40b33594ada92e5649347c457d982805/wrapt-2.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f29c827a8d9936ac320746747a016c4bc66ef639f5cd0d32df24f5eacbf9c69f", size = 121479, upload-time = "2026-03-06T02:53:45.844Z" },
+ { url = "https://files.pythonhosted.org/packages/78/cc/ee3a011920c7a023b25e8df26f306b2484a531ab84ca5c96260a73de76c0/wrapt-2.1.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:a9dd9813825f7ecb018c17fd147a01845eb330254dff86d3b5816f20f4d6aaf8", size = 116271, upload-time = "2026-03-06T02:54:46.356Z" },
+ { url = "https://files.pythonhosted.org/packages/98/fd/e5ff7ded41b76d802cf1191288473e850d24ba2e39a6ec540f21ae3b57cb/wrapt-2.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6f8dbdd3719e534860d6a78526aafc220e0241f981367018c2875178cf83a413", size = 120573, upload-time = "2026-03-06T02:52:50.163Z" },
+ { url = "https://files.pythonhosted.org/packages/47/c5/242cae3b5b080cd09bacef0591691ba1879739050cc7c801ff35c8886b66/wrapt-2.1.2-cp313-cp313-win32.whl", hash = "sha256:5c35b5d82b16a3bc6e0a04349b606a0582bc29f573786aebe98e0c159bc48db6", size = 58205, upload-time = "2026-03-06T02:53:47.494Z" },
+ { url = "https://files.pythonhosted.org/packages/12/69/c358c61e7a50f290958809b3c61ebe8b3838ea3e070d7aac9814f95a0528/wrapt-2.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:f8bc1c264d8d1cf5b3560a87bbdd31131573eb25f9f9447bb6252b8d4c44a3a1", size = 60452, upload-time = "2026-03-06T02:53:30.038Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/66/c8a6fcfe321295fd8c0ab1bd685b5a01462a9b3aa2f597254462fc2bc975/wrapt-2.1.2-cp313-cp313-win_arm64.whl", hash = "sha256:3beb22f674550d5634642c645aba4c72a2c66fb185ae1aebe1e955fae5a13baf", size = 58842, upload-time = "2026-03-06T02:52:52.114Z" },
+ { url = "https://files.pythonhosted.org/packages/da/55/9c7052c349106e0b3f17ae8db4b23a691a963c334de7f9dbd60f8f74a831/wrapt-2.1.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0fc04bc8664a8bc4c8e00b37b5355cffca2535209fba1abb09ae2b7c76ddf82b", size = 63075, upload-time = "2026-03-06T02:53:19.108Z" },
+ { url = "https://files.pythonhosted.org/packages/09/a8/ce7b4006f7218248dd71b7b2b732d0710845a0e49213b18faef64811ffef/wrapt-2.1.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a9b9d50c9af998875a1482a038eb05755dfd6fe303a313f6a940bb53a83c3f18", size = 63719, upload-time = "2026-03-06T02:54:33.452Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/e5/2ca472e80b9e2b7a17f106bb8f9df1db11e62101652ce210f66935c6af67/wrapt-2.1.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2d3ff4f0024dd224290c0eabf0240f1bfc1f26363431505fb1b0283d3b08f11d", size = 152643, upload-time = "2026-03-06T02:52:42.721Z" },
+ { url = "https://files.pythonhosted.org/packages/36/42/30f0f2cefca9d9cbf6835f544d825064570203c3e70aa873d8ae12e23791/wrapt-2.1.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3278c471f4468ad544a691b31bb856374fbdefb7fee1a152153e64019379f015", size = 158805, upload-time = "2026-03-06T02:54:25.441Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/67/d08672f801f604889dcf58f1a0b424fe3808860ede9e03affc1876b295af/wrapt-2.1.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a8914c754d3134a3032601c6984db1c576e6abaf3fc68094bb8ab1379d75ff92", size = 145990, upload-time = "2026-03-06T02:53:57.456Z" },
+ { url = "https://files.pythonhosted.org/packages/68/a7/fd371b02e73babec1de6ade596e8cd9691051058cfdadbfd62a5898f3295/wrapt-2.1.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ff95d4264e55839be37bafe1536db2ab2de19da6b65f9244f01f332b5286cfbf", size = 155670, upload-time = "2026-03-06T02:54:55.309Z" },
+ { url = "https://files.pythonhosted.org/packages/86/2d/9fe0095dfdb621009f40117dcebf41d7396c2c22dca6eac779f4c007b86c/wrapt-2.1.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:76405518ca4e1b76fbb1b9f686cff93aebae03920cc55ceeec48ff9f719c5f67", size = 144357, upload-time = "2026-03-06T02:54:24.092Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/b6/ec7b4a254abbe4cde9fa15c5d2cca4518f6b07d0f1b77d4ee9655e30280e/wrapt-2.1.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c0be8b5a74c5824e9359b53e7e58bef71a729bacc82e16587db1c4ebc91f7c5a", size = 150269, upload-time = "2026-03-06T02:53:31.268Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/6b/2fabe8ebf148f4ee3c782aae86a795cc68ffe7d432ef550f234025ce0cfa/wrapt-2.1.2-cp313-cp313t-win32.whl", hash = "sha256:f01277d9a5fc1862f26f7626da9cf443bebc0abd2f303f41c5e995b15887dabd", size = 59894, upload-time = "2026-03-06T02:54:15.391Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/fb/9ba66fc2dedc936de5f8073c0217b5d4484e966d87723415cc8262c5d9c2/wrapt-2.1.2-cp313-cp313t-win_amd64.whl", hash = "sha256:84ce8f1c2104d2f6daa912b1b5b039f331febfeee74f8042ad4e04992bd95c8f", size = 63197, upload-time = "2026-03-06T02:54:41.943Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/1c/012d7423c95d0e337117723eb8ecf73c622ce15a97847e84cf3f8f26cd7e/wrapt-2.1.2-cp313-cp313t-win_arm64.whl", hash = "sha256:a93cd767e37faeddbe07d8fc4212d5cba660af59bdb0f6372c93faaa13e6e679", size = 60363, upload-time = "2026-03-06T02:54:48.093Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/c7/8528ac2dfa2c1e6708f647df7ae144ead13f0a31146f43c7264b4942bf12/wrapt-2.1.2-py3-none-any.whl", hash = "sha256:b8fd6fa2b2c4e7621808f8c62e8317f4aae56e59721ad933bac5239d913cf0e8", size = 43993, upload-time = "2026-03-06T02:53:12.905Z" },
]
[[package]]
@@ -9633,11 +9966,11 @@ wheels = [
[[package]]
name = "zipp"
-version = "3.23.0"
+version = "3.23.1"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/30/21/093488dfc7cc8964ded15ab726fad40f25fd3d788fd741cc1c5a17d78ee8/zipp-3.23.1.tar.gz", hash = "sha256:32120e378d32cd9714ad503c1d024619063ec28aad2248dc6672ad13edfa5110", size = 25965, upload-time = "2026-04-13T23:21:46.6Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" },
+ { url = "https://files.pythonhosted.org/packages/08/8a/0861bec20485572fbddf3dfba2910e38fe249796cb73ecdeb74e07eeb8d3/zipp-3.23.1-py3-none-any.whl", hash = "sha256:0b3596c50a5c700c9cb40ba8d86d9f2cc4807e9bedb06bcdf7fac85633e444dc", size = 10378, upload-time = "2026-04-13T23:21:45.386Z" },
]
[[package]]