finagent / crew /agents.py
emmanuelakbi's picture
Swap ChatOpenAI for crewai.LLM so newer crewai versions accept the llm
24cf535
"""Agent factory functions for creating configured CrewAI Agent instances."""
from crewai import Agent, LLM
from crew.config import LLMConfig
def create_llm(config: LLMConfig) -> LLM:
"""Create a shared crewai.LLM instance pointing to the vLLM endpoint.
Newer versions of crewai validate ``Agent(llm=...)`` strictly and only
accept a :class:`crewai.LLM` (or a plain model-name string). A raw
``langchain_openai.ChatOpenAI`` is rejected. crewai.LLM delegates to
litellm under the hood, and litellm needs an explicit provider prefix
for self-hosted OpenAI-compatible endpoints — hence the
``hosted_vllm/`` prefix on the model name.
``api_key`` is a required positional for the OpenAI provider flow even
when the upstream server (vLLM) does not enforce auth; any non-empty
value is accepted.
"""
model_name = config.model_name
if not model_name.startswith("hosted_vllm/"):
model_name = f"hosted_vllm/{model_name}"
return LLM(
model=model_name,
base_url=config.base_url,
api_key="not-needed",
temperature=config.temperature,
max_tokens=config.max_tokens,
timeout=config.request_timeout,
)
def create_market_scanner(llm: LLM, tools: list) -> Agent:
"""Create the Market Scanner agent.
Args:
llm: Shared LLM instance
tools: [search_news, get_price_change, get_volume]
"""
return Agent(
role="Market Scanner",
goal="Detect significant market events, price movements, and volume anomalies for the given ticker",
backstory=(
"You are an experienced market surveillance specialist who monitors "
"news feeds, price action, and trading volumes 24/7. You have a keen "
"eye for detecting material events that could impact stock prices."
),
llm=llm,
tools=tools,
max_iter=5,
verbose=True,
)
def create_fundamental_analyst(llm: LLM, tools: list) -> Agent:
"""Create the Fundamental Analyst agent.
Args:
llm: Shared LLM instance
tools: [get_financials, get_earnings, get_peers]
"""
return Agent(
role="Fundamental Analyst",
goal="Determine the intrinsic value of the company by analyzing financial metrics, earnings trends, and peer comparisons",
backstory=(
"You are a seasoned equity research analyst with 15 years of experience "
"in fundamental valuation. You specialize in dissecting financial statements, "
"identifying earnings quality, and comparing companies against their peers."
),
llm=llm,
tools=tools,
max_iter=5,
verbose=True,
)
def create_technical_analyst(llm: LLM, tools: list) -> Agent:
"""Create the Technical Analyst agent.
Args:
llm: Shared LLM instance
tools: [get_price_history, calculate_indicators]
"""
return Agent(
role="Technical Analyst",
goal="Identify optimal entry and exit points using price patterns and technical indicators",
backstory=(
"You are a quantitative technical analyst who combines classical chart "
"patterns with modern indicator analysis. You focus on RSI, MACD, "
"Bollinger Bands, and moving average crossovers to time entries precisely."
),
llm=llm,
tools=tools,
max_iter=5,
verbose=True,
)
def create_risk_manager(llm: LLM, tools: list) -> Agent:
"""Create the Risk Manager agent.
Args:
llm: Shared LLM instance
tools: [calculate_position_size, set_stop_loss]
"""
return Agent(
role="Risk Manager",
goal="Protect capital through optimal position sizing and stop-loss placement based on volatility",
backstory=(
"You are a portfolio risk specialist who never lets a single trade "
"risk more than the defined threshold. You use ATR-based stop-losses "
"and position sizing formulas to ensure consistent risk management."
),
llm=llm,
tools=tools,
max_iter=5,
verbose=True,
)
def create_chief_strategist(llm: LLM) -> Agent:
"""Create the Chief Strategist agent (no tools, pure reasoning)."""
return Agent(
role="Chief Strategist",
goal="Synthesize all agent analyses into a single, actionable trading signal with confidence level",
backstory=(
"You are the head of trading strategy with decades of experience "
"integrating fundamental, technical, and risk perspectives into "
"decisive trading calls. You weigh conflicting signals and produce "
"clear BUY/SELL/HOLD recommendations with calibrated confidence."
),
llm=llm,
tools=[],
max_iter=5,
verbose=True,
)