Skip to content

Accept prebuilt agent objects and let agents declare dependencies - #48

Closed
nickhuo wants to merge 1 commit into
mainfrom
jiajunh/ventis-accept-prebuilt-agents-and-declared-deps
Closed

Accept prebuilt agent objects and let agents declare dependencies#48
nickhuo wants to merge 1 commit into
mainfrom
jiajunh/ventis-accept-prebuilt-agents-and-declared-deps

Conversation

@nickhuo

@nickhuo nickhuo commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator

Draft. Two changes that let a LangChain / LangGraph / CrewAI project run on Ventis without being rewritten.

1. _load_agent no longer requires a class

agent_class = getattr(module, self.agent_name)
agent_instance = agent_class()

This requires agent.name to be a class with a no-arg constructor. What the frameworks actually export is an object:

Framework Exported Type
LangGraph graph = builder.compile() CompiledStateGraph
LangChain LCEL chain = prompt | llm | parser RunnableSequence
CrewAI crew = Crew(agents=..., tasks=...) Crew

Calling one raises TypeError, _load_agent swallows it, and every request answers "No agent loaded". The only way through was an adapter class that exists purely to hold a reference and forward one call.

Now:

target = getattr(module, self.agent_name)
agent_instance = target() if isinstance(target, type) else target

Two consequences:

  • The adapter disappears. A yaml can name the exported graph directly and the port needs no Python for the agent at all.
  • Configuration gets somewhere to live. agent_class() takes no arguments, so a configured agent previously had nowhere to receive its config except environment variables read inside __init__. A project can now export agent = MyAgent(model="gpt-4.1") and Ventis uses it as-is.

Backward compatible: isinstance(target, type) is true for classes, so all four existing examples take the same path as before.

2. Agents and workflows can declare dependencies

generate_docker and generate_workflow_docker each wrote a fixed requirements.txt (hard code)

  - name: email_assistant
    entrypoint: src/email_assistant.py
    requirements:
      - langchain>=1.0.0
      - langgraph>=1.0.0
      - python-dotenv

Declared entries are appended to the runtime's own list. An entry naming a runtime dependency is dropped rather than appended, so a project cannot repin something the controller has to run against (redis>=5.0 is ignored, not added).

Two limits currently stop mainstream agent projects from running on
Ventis. Each is a hardcoded assumption with no way to override it.

_load_agent did getattr(module, agent_name) followed by agent_class().
That requires the yaml's agent.name to point at a class with a no-arg
constructor. LangGraph exports a compiled graph, LCEL exports a
RunnableSequence, CrewAI exports a Crew -- all instances. Calling one
raises TypeError, which _load_agent swallows, so the replica comes up,
reports healthy, and answers "No agent loaded" on every request. The
only way through was an adapter class whose entire job was to hold a
reference and forward one call.

It now calls the target only when it is a class. Classes behave exactly
as before, so every existing example is unaffected. Two things follow:
a project can name its exported graph directly and need no adapter at
all, and a project can export an already-configured instance, which is
the first place configuration has had to live other than environment
variables read inside __init__.

generate_docker and generate_workflow_docker wrote a fixed
requirements.txt with no hook of any kind, so nothing outside grpcio,
redis, pyyaml, boto3, yfinance, psutil, ipdb and ipython could reach an
agent image -- langchain, langgraph and crewai included. Agent and
workflow entries in global_controller.yaml now take a `requirements`
list, appended to the runtime's own. Entries naming a runtime dependency
are dropped rather than added, so a project cannot repin something the
controller has to run against.

Verified against a LangGraph email assistant: with agent.name pointing
at the compiled graph and its dependencies declared, the port is one
8-line workflow and two yaml files, no adapter, and langchain,
langgraph, langchain-openai, dotenv and html2text all import inside the
built image.

Tests cover both paths, including the constructor-argument case and the
repinning guard. The three pre-existing failures in
test_telemetry_logging.py reproduce on unmodified main.
@coderabbitai

coderabbitai Bot commented Aug 25, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@nickhuo nickhuo closed this Aug 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant