feat(files): use FileInput type for all input_files parameters

This commit is contained in:
Greyson LaLonde
2026-01-23 09:21:22 -05:00
parent cd0a2c3900
commit 343ad02c88
5 changed files with 45 additions and 34 deletions

View File

@@ -8,6 +8,7 @@ from hashlib import md5
import json
import re
from typing import (
TYPE_CHECKING,
Any,
cast,
)
@@ -31,6 +32,10 @@ from rich.console import Console
from rich.panel import Panel
from typing_extensions import Self
if TYPE_CHECKING:
from crewai_files import FileInput
from crewai.agent import Agent
from crewai.agents.agent_builder.base_agent import BaseAgent
from crewai.agents.cache.cache_handler import CacheHandler
@@ -679,7 +684,7 @@ class Crew(FlowTrackable, BaseModel):
def kickoff(
self,
inputs: dict[str, Any] | None = None,
input_files: dict[str, Any] | None = None,
input_files: dict[str, FileInput] | None = None,
) -> CrewOutput | CrewStreamingOutput:
"""Execute the crew's workflow.
@@ -751,7 +756,7 @@ class Crew(FlowTrackable, BaseModel):
def kickoff_for_each(
self,
inputs: list[dict[str, Any]],
input_files: dict[str, Any] | None = None,
input_files: dict[str, FileInput] | None = None,
) -> list[CrewOutput | CrewStreamingOutput]:
"""Executes the Crew's workflow for each input and aggregates results.
@@ -787,7 +792,7 @@ class Crew(FlowTrackable, BaseModel):
async def kickoff_async(
self,
inputs: dict[str, Any] | None = None,
input_files: dict[str, Any] | None = None,
input_files: dict[str, FileInput] | None = None,
) -> CrewOutput | CrewStreamingOutput:
"""Asynchronous kickoff method to start the crew execution.
@@ -834,7 +839,7 @@ class Crew(FlowTrackable, BaseModel):
async def kickoff_for_each_async(
self,
inputs: list[dict[str, Any]],
input_files: dict[str, Any] | None = None,
input_files: dict[str, FileInput] | None = None,
) -> list[CrewOutput | CrewStreamingOutput] | CrewStreamingOutput:
"""Executes the Crew's workflow for each input asynchronously.
@@ -860,7 +865,7 @@ class Crew(FlowTrackable, BaseModel):
async def akickoff(
self,
inputs: dict[str, Any] | None = None,
input_files: dict[str, Any] | None = None,
input_files: dict[str, FileInput] | None = None,
) -> CrewOutput | CrewStreamingOutput:
"""Native async kickoff method using async task execution throughout.
@@ -936,7 +941,7 @@ class Crew(FlowTrackable, BaseModel):
async def akickoff_for_each(
self,
inputs: list[dict[str, Any]],
input_files: dict[str, Any] | None = None,
input_files: dict[str, FileInput] | None = None,
) -> list[CrewOutput | CrewStreamingOutput] | CrewStreamingOutput:
"""Native async execution of the Crew's workflow for each input.

View File

@@ -35,6 +35,8 @@ except ImportError:
if TYPE_CHECKING:
from crewai_files import FileInput
from crewai.crew import Crew
@@ -225,7 +227,7 @@ def _extract_files_from_inputs(inputs: dict[str, Any]) -> dict[str, Any]:
def prepare_kickoff(
crew: Crew,
inputs: dict[str, Any] | None,
input_files: dict[str, Any] | None = None,
input_files: dict[str, FileInput] | None = None,
) -> dict[str, Any] | None:
"""Prepare crew for kickoff execution.

View File

@@ -83,6 +83,8 @@ from crewai.flow.utils import (
if TYPE_CHECKING:
from crewai_files import FileInput
from crewai.flow.async_feedback.types import PendingFeedbackContext
from crewai.flow.human_feedback import HumanFeedbackResult
from crewai.llms.base_llm import BaseLLM
@@ -1414,7 +1416,7 @@ class Flow(Generic[T], metaclass=FlowMeta):
def kickoff(
self,
inputs: dict[str, Any] | None = None,
input_files: dict[str, Any] | None = None,
input_files: dict[str, FileInput] | None = None,
) -> Any | FlowStreamingOutput:
"""Start the flow execution in a synchronous context.
@@ -1475,7 +1477,7 @@ class Flow(Generic[T], metaclass=FlowMeta):
async def kickoff_async(
self,
inputs: dict[str, Any] | None = None,
input_files: dict[str, Any] | None = None,
input_files: dict[str, FileInput] | None = None,
) -> Any | FlowStreamingOutput:
"""Start the flow execution asynchronously.
@@ -1720,7 +1722,7 @@ class Flow(Generic[T], metaclass=FlowMeta):
async def akickoff(
self,
inputs: dict[str, Any] | None = None,
input_files: dict[str, Any] | None = None,
input_files: dict[str, FileInput] | None = None,
) -> Any | FlowStreamingOutput:
"""Native async method to start the flow execution. Alias for kickoff_async.

View File

@@ -3,6 +3,7 @@ from collections.abc import Callable
import inspect
import json
from typing import (
TYPE_CHECKING,
Any,
Literal,
cast,
@@ -23,6 +24,10 @@ from pydantic import (
)
from typing_extensions import Self
if TYPE_CHECKING:
from crewai_files import FileInput
from crewai.agents.agent_builder.base_agent import BaseAgent
from crewai.agents.agent_builder.utilities.base_token_process import TokenProcess
from crewai.agents.cache.cache_handler import CacheHandler
@@ -296,7 +301,7 @@ class LiteAgent(FlowTrackable, BaseModel):
self,
messages: str | list[LLMMessage],
response_format: type[BaseModel] | None = None,
input_files: dict[str, Any] | None = None,
input_files: dict[str, FileInput] | None = None,
) -> LiteAgentOutput:
"""Execute the agent with the given messages.
@@ -470,7 +475,7 @@ class LiteAgent(FlowTrackable, BaseModel):
self,
messages: str | list[LLMMessage],
response_format: type[BaseModel] | None = None,
input_files: dict[str, Any] | None = None,
input_files: dict[str, FileInput] | None = None,
) -> LiteAgentOutput:
"""Execute the agent asynchronously with the given messages.
@@ -492,7 +497,7 @@ class LiteAgent(FlowTrackable, BaseModel):
self,
messages: str | list[LLMMessage],
response_format: type[BaseModel] | None = None,
input_files: dict[str, Any] | None = None,
input_files: dict[str, FileInput] | None = None,
) -> LiteAgentOutput:
"""Async version of kickoff. Alias for kickoff_async.
@@ -548,7 +553,7 @@ class LiteAgent(FlowTrackable, BaseModel):
self,
messages: str | list[LLMMessage],
response_format: type[BaseModel] | None = None,
input_files: dict[str, Any] | None = None,
input_files: dict[str, FileInput] | None = None,
) -> list[LLMMessage]:
"""Format messages for the LLM.

View File

@@ -10,6 +10,7 @@ import logging
from pathlib import Path
import threading
from typing import (
TYPE_CHECKING,
Any,
ClassVar,
cast,
@@ -30,6 +31,10 @@ from pydantic import (
from pydantic_core import PydanticCustomError
from typing_extensions import Self
if TYPE_CHECKING:
from crewai_files import FileInput
from crewai.agents.agent_builder.base_agent import BaseAgent
from crewai.events.event_bus import crewai_event_bus
from crewai.events.types.task_events import (
@@ -52,10 +57,7 @@ from crewai.utilities.file_store import (
try:
from crewai_files import (
FilePath,
normalize_input_files,
)
from crewai_files import FilePath
HAS_CREWAI_FILES = True
except ImportError:
@@ -158,9 +160,9 @@ class Task(BaseModel):
default_factory=list,
description="Tools the agent is limited to use for this task.",
)
input_files: list[Any] = Field(
default_factory=list,
description="List of input files for this task. Accepts paths, bytes, or File objects.",
input_files: dict[str, FileInput] = Field(
default_factory=dict,
description="Named input files for this task. Keys are reference names, values are paths or File objects.",
)
security_config: SecurityConfig = Field(
default_factory=SecurityConfig,
@@ -379,7 +381,7 @@ class Task(BaseModel):
@field_validator("input_files", mode="before")
@classmethod
def _normalize_input_files(cls, v: list[Any]) -> list[Any]:
def _normalize_input_files(cls, v: dict[str, Any]) -> dict[str, Any]:
"""Convert string paths to FilePath objects."""
if not v:
return v
@@ -387,12 +389,12 @@ class Task(BaseModel):
if not HAS_CREWAI_FILES:
return v
result = []
for item in v:
if isinstance(item, str):
result.append(FilePath(path=Path(item)))
result = {}
for key, value in v.items():
if isinstance(value, str):
result[key] = FilePath(path=Path(value))
else:
result.append(item)
result[key] = value
return result
@field_validator("output_file")
@@ -1038,16 +1040,11 @@ Follow these guidelines:
return
def _store_input_files(self) -> None:
"""Store task input files in the file store.
Converts input_files list to a named dict and stores under task ID.
"""
"""Store task input files in the file store."""
if not HAS_CREWAI_FILES or not self.input_files:
return
files_dict = normalize_input_files(self.input_files)
if files_dict:
store_task_files(self.id, files_dict)
store_task_files(self.id, self.input_files)
def __repr__(self) -> str:
return f"Task(description={self.description}, expected_output={self.expected_output})"