Compare commits

..

15 Commits

Author SHA1 Message Date
Lucas Gomide
1de749d192 Merge branch 'main' into devin/1750789857-fix-trailing-slash-project-creation 2025-06-26 11:02:51 -03:00
Lucas Gomide
6a171190f9 Merge branch 'main' into devin/1750789857-fix-trailing-slash-project-creation 2025-06-26 10:32:43 -03:00
Devin AI
911e02da8e fix: correct folder name validation logic to match test expectations
- Fix validation regex to catch names starting with invalid characters like '@#/'
- Ensure validation properly raises ValueError for cases expected by tests
- Maintain support for valid cases like 'my.project/' -> 'myproject'
- Address lucasgomide's comment about valid Python module names

Co-Authored-By: João <joao@crewai.com>
2025-06-26 13:18:41 +00:00
Devin AI
eddeacebcc Merge branch 'devin/1750789857-fix-trailing-slash-project-creation' of https://git-manager.devin.ai/proxy/github.com/crewAIInc/crewAI into devin/1750789857-fix-trailing-slash-project-creation 2025-06-26 13:00:28 +00:00
Devin AI
5b5b462238 feat: add folder name validation for Python module names
- Implement validation to ensure folder_name is valid Python identifier
- Check that folder names don't start with digits
- Validate folder names are not Python keywords
- Sanitize invalid characters from folder names
- Raise ValueError with descriptive messages for invalid cases
- Update tests to validate both folder and class name requirements
- Addresses GitHub comment requiring folder names to be valid Python module names

Co-Authored-By: João <joao@crewai.com>
2025-06-26 12:59:49 +00:00
Lucas Gomide
3af61f428d Merge branch 'main' into devin/1750789857-fix-trailing-slash-project-creation 2025-06-24 17:56:09 -03:00
Devin AI
a3416f4301 fix: remove unused os import to resolve lint failure
- Remove unused 'import os' statement from test_create_crew.py
- All tests still pass locally after removing unused import
- Should resolve F401 lint error in CI

Co-Authored-By: João <joao@crewai.com>
2025-06-24 20:14:06 +00:00
Devin AI
b58f375b54 fix: eliminate os.chdir() usage in tests to prevent working directory corruption
- Replace os.chdir() with parent_folder parameter for create_folder_structure tests
- Mock create_folder_structure directly for create_crew tests to avoid directory changes
- All 12 tests now pass locally without working directory corruption
- Should resolve the 103 failing tests in Python 3.12 CI

Co-Authored-By: João <joao@crewai.com>
2025-06-24 20:07:51 +00:00
Devin AI
12342ce41c fix: standardize working directory handling in tests to prevent corruption
Co-Authored-By: João <joao@crewai.com>
2025-06-24 19:57:28 +00:00
Devin AI
babcd1d712 fix: add working directory safety checks to prevent test interference
Co-Authored-By: João <joao@crewai.com>
2025-06-24 19:56:09 +00:00
Devin AI
cabdfafb4a refactor: change class name validation to raise errors instead of generating defaults
- Remove default value generation (Crew prefix/suffix, DefaultCrew fallback)
- Raise ValueError with descriptive messages for invalid class names
- Update tests to expect validation errors instead of default corrections
- Addresses GitHub comment feedback from lucasgomide about strict validation

Co-Authored-By: João <joao@crewai.com>
2025-06-24 19:30:10 +00:00
Devin AI
dc25c32ca0 feat: add comprehensive class name validation for Python identifiers
- Ensure generated class names are always valid Python identifiers
- Handle edge cases: names starting with numbers, special characters, keywords, built-ins
- Add sanitization logic to remove invalid characters and prefix with 'Crew' when needed
- Add comprehensive test coverage for class name validation edge cases
- Addresses GitHub PR comment from lucasgomide about class name validity

Fixes include:
- Names starting with numbers: '123project' -> 'Crew123Project'
- Python built-ins: 'True' -> 'TrueCrew', 'False' -> 'FalseCrew'
- Special characters: 'hello@world' -> 'HelloWorld'
- Empty/whitespace: '   ' -> 'DefaultCrew'
- All generated class names pass isidentifier() and keyword checks

Co-Authored-By: João <joao@crewai.com>
2025-06-24 19:17:52 +00:00
Devin AI
bc4fd6a39b fix: resolve circular import in CLI authentication module
- Move ToolCommand import to be local inside _poll_for_token method
- Update test mock to patch ToolCommand at correct location
- Resolves Python 3.11 test collection failure in CI

Co-Authored-By: João <joao@crewai.com>
2025-06-24 19:08:00 +00:00
Devin AI
842311a52b trigger CI re-run to check for flaky test issue
Co-Authored-By: João <joao@crewai.com>
2025-06-24 18:49:52 +00:00
Devin AI
e7872f02c4 fix: normalize project names by stripping trailing slashes in crew creation
- Strip trailing slashes from project names in create_folder_structure
- Add comprehensive tests for trailing slash scenarios
- Fixes #3059

The issue occurred because trailing slashes in project names like 'hello/'
were directly incorporated into pyproject.toml, creating invalid package
names and script entries. This fix silently normalizes project names by
stripping trailing slashes before processing, maintaining backward
compatibility while fixing the invalid template generation.

Co-Authored-By: João <joao@crewai.com>
2025-06-24 18:49:52 +00:00
4 changed files with 7 additions and 71 deletions

View File

@@ -684,28 +684,6 @@ In this section, you'll find detailed examples that help you select, configure,
- openrouter/deepseek/deepseek-chat
</Info>
</Accordion>
<Accordion title="Nebius AI Studio">
Set the following environment variables in your `.env` file:
```toml Code
NEBIUS_API_KEY=<your-api-key>
```
Example usage in your CrewAI project:
```python Code
llm = LLM(
model="nebius/Qwen/Qwen3-30B-A3B"
)
```
<Info>
Nebius AI Studio features:
- Large collection of open source models
- Higher rate limits
- Competitive pricing
- Good balance of speed and quality
</Info>
</Accordion>
</AccordionGroup>
## Streaming Responses

View File

@@ -34,7 +34,6 @@ LiteLLM supports a wide range of providers, including but not limited to:
- DeepInfra
- Groq
- SambaNova
- Nebius AI Studio
- [NVIDIA NIMs](https://docs.api.nvidia.com/nim/reference/models-1)
- And many more!

View File

@@ -34,7 +34,7 @@ class PydanticSchemaParser(BaseModel):
key_type, value_type = get_args(field_type)
return f"Dict[{key_type.__name__}, {value_type.__name__}]"
if origin is Union or (origin is None and len(get_args(field_type)) > 0):
if origin is Union:
return self._format_union_type(field_type, depth)
if isinstance(field_type, type) and issubclass(field_type, BaseModel):
@@ -42,10 +42,7 @@ class PydanticSchemaParser(BaseModel):
nested_indent = " " * 4 * depth
return f"{field_type.__name__}\n{nested_indent}{{\n{nested_schema}\n{nested_indent}}}"
if hasattr(field_type, '__name__'):
return field_type.__name__
else:
return str(field_type)
return field_type.__name__
def _format_list_type(self, list_item_type, depth: int) -> str:
if isinstance(list_item_type, type) and issubclass(list_item_type, BaseModel):
@@ -86,13 +83,10 @@ class PydanticSchemaParser(BaseModel):
if origin in {dict, Dict}:
key_type, value_type = get_args(annotation)
return f"Dict[{key_type.__name__}, {value_type.__name__}]"
if origin is Union or (origin is None and len(get_args(annotation)) > 0):
if origin is Union:
return self._format_union_type(annotation, depth)
if isinstance(annotation, type) and issubclass(annotation, BaseModel):
nested_schema = self._get_model_schema(annotation, depth)
nested_indent = " " * 4 * depth
return f"{annotation.__name__}\n{nested_indent}{{\n{nested_schema}\n{nested_indent}}}"
if hasattr(annotation, '__name__'):
return annotation.__name__
else:
return str(annotation)
return annotation.__name__

View File

@@ -1,6 +1,7 @@
from typing import Dict, List, Optional, Union
from typing import Any, Dict, List, Optional, Set, Tuple, Union
from pydantic import BaseModel
import pytest
from pydantic import BaseModel, Field
from crewai.utilities.pydantic_schema_parser import PydanticSchemaParser
@@ -91,39 +92,3 @@ def test_model_with_dict():
dict_field: Dict[str, int]
}"""
assert schema.strip() == expected_schema.strip()
def test_model_with_python310_union_syntax():
class UnionTypeModel(BaseModel):
union_field: str | None
multi_union_field: int | str | None
non_optional_union: int | str
parser = PydanticSchemaParser(model=UnionTypeModel)
schema = parser.get_schema()
expected_schema = """{
union_field: str | None,
multi_union_field: int | str | None,
non_optional_union: int | str
}"""
assert schema.strip() == expected_schema.strip()
def test_mixed_union_syntax():
class MixedUnionModel(BaseModel):
traditional_optional: Optional[str]
new_union_syntax: str | None
traditional_union: Union[int, str]
new_multi_union: int | str | float
parser = PydanticSchemaParser(model=MixedUnionModel)
schema = parser.get_schema()
expected_schema = """{
traditional_optional: Optional[str],
new_union_syntax: str | None,
traditional_union: Union[int, str],
new_multi_union: int | str | float
}"""
assert schema.strip() == expected_schema.strip()