Skip to content

Add LLM server integration for connecting agents (claude, codex) to Ollama, vLLM, and other providers#48

Merged
nezhar merged 1 commit into
mainfrom
issue-11
Mar 17, 2026
Merged

Add LLM server integration for connecting agents (claude, codex) to Ollama, vLLM, and other providers#48
nezhar merged 1 commit into
mainfrom
issue-11

Conversation

@nezhar
Copy link
Copy Markdown
Collaborator

@nezhar nezhar commented Mar 17, 2026

Introduces first-class support for connecting VibePod agents to external LLM servers (such as Ollama and vLLM) via a new unified llm configuration section. It enables automatic injection of environment variables and CLI flags for supported agents (Claude Code and Codex), allowing users to run these agents against open-source models or compatible endpoints.

Summary by CodeRabbit

Release Notes

  • New Features

    • LLM configuration block added, enabling connections to local or remote LLM servers through base URL, API key, and model configuration.
    • LLM settings can be overridden via environment variables.
  • Documentation

    • Comprehensive LLM integration guide added, covering setup, configuration, and quick-start steps with compatible LLM endpoints.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 17, 2026

📝 Walkthrough

Walkthrough

This PR introduces LLM integration for VibePod, enabling agents to connect to local or remote LLM servers. It adds a new configuration schema (llm section with enabled, base_url, api_key, model), defines per-agent LLM metadata (environment variable mappings and model arguments for claude and codex), implements runtime injection of LLM environment variables and command arguments in the run command, and provides comprehensive documentation and test coverage.

Changes

Cohort / File(s) Summary
LLM Configuration Schema
src/vibepod/core/config.py, src/vibepod/core/agents.py
Added llm configuration group with enabled, base_url, api_key, and model fields; extended AgentSpec with llm_env_map and llm_model_args; configured Claude and Codex agents with environment variable mappings and model argument flags.
Runtime Implementation
src/vibepod/commands/run.py
Implemented LLM configuration loading and injection flow in run() to extract llm settings, prepare environment variable mappings based on agent specs, and append model arguments to the container launch command when applicable.
Documentation
docs/configuration.md, docs/llm.md, mkdocs.yml
Added comprehensive LLM configuration documentation including quick-start guides for Ollama, environment variable mappings, per-agent override behavior, and navigation entry in mkdocs.
Test Coverage
tests/test_agents.py, tests/test_config.py, tests/test_run.py
Added 23 tests for agent LLM metadata validation, 25 tests for LLM config defaults and environment variable overrides, and 312 tests for LLM environment variable injection and command construction behavior in the run command.

Sequence Diagram

sequenceDiagram
    participant User
    participant Config as Configuration
    participant Run as Run Command
    participant AgentSpec as Agent Metadata
    participant Container as Container

    User->>Config: Load config.yaml with llm settings
    Config->>Run: Pass llm config (enabled, base_url, api_key, model)
    Run->>AgentSpec: Query agent for llm_env_map and llm_model_args
    AgentSpec-->>Run: Return env mappings and model args
    alt LLM enabled and agent has mappings
        Run->>Run: Prepare environment variables<br/>(map config values to agent-specific vars)
        Run->>Run: Build command with model args<br/>(append --model, --oss, etc.)
    end
    Run->>Container: Launch container with<br/>injected env vars and command args
    Container-->>User: Agent runs with LLM integration
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related issues

Possibly related PRs

Poem

🐰 A model for every hare's affair,
Config flows with LLM care,
Claude and Codex now find their way,
To Ollama servers, come what may!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding LLM server integration for agents claude and codex to connect with Ollama, vLLM, and similar providers, which is the core objective of the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-11
📝 Coding Plan
  • Generate coding plan for human review comments

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 and usage tips.

Tip

CodeRabbit can use OpenGrep to find security vulnerabilities and bugs across 17+ programming languages.

OpenGrep is compatible with Semgrep configurations. Add an opengrep.yml or semgrep.yml configuration file to your project to enable OpenGrep analysis.

@nezhar nezhar changed the title Add LLM server integration for connecting agents (claude, codex) to O… Add LLM server integration for connecting agents (claude, codex) to Ollama, vLLM, and other providers Mar 17, 2026
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Mar 17, 2026

Greptile Summary

This PR introduces a unified llm configuration section that lets VibePod agents (currently Claude Code and Codex) connect to external LLM servers such as Ollama and vLLM by automatically injecting the appropriate environment variables and CLI flags at container startup.

Key changes:

  • AgentSpec gains two new optional fields — llm_env_map (maps LLM config keys to agent-specific env var names) and llm_model_args (prefix args for the model CLI flag). Claude maps to ANTHROPIC_BASE_URL/ANTHROPIC_API_KEY + --model; Codex maps to CODEX_OSS_BASE_URL + --oss -m.
  • run.py reads the llm config block after building merged_env and uses setdefault to inject LLM env vars, ensuring per-agent config and CLI --env flags always take precedence.
  • config.py adds the llm section to the default config and four VP_LLM_* environment variable overrides.
  • Documentation (docs/llm.md) is clear and comprehensive, including the important host.docker.internal guidance for Docker-hosted Ollama.
  • Test coverage is thorough across config, agents, and run scenarios; two test functions have copy-paste issues in their names/docstrings (referencing OPENAI instead of ANTHROPIC/CODEX_OSS).
  • llm.api_key is silently dropped for the Codex agent (no entry in its llm_env_map), which may surprise users running Codex against authenticated OSS endpoints.

Confidence Score: 4/5

  • This PR is safe to merge; the implementation is well-tested and the two issues found are style/usability concerns, not correctness bugs.
  • The core logic is correct — env precedence via setdefault is properly ordered, None-safe command building is handled, and all changed code paths are covered by tests. The two deductions are for misleading test names/docstrings (which could confuse future maintainers) and the silent drop of llm.api_key for Codex (a usability gap for authenticated OSS servers).
  • tests/test_run.py (misleading test names/docstrings) and src/vibepod/core/agents.py (codex api_key silently ignored)

Important Files Changed

Filename Overview
src/vibepod/commands/run.py Adds LLM env injection and CLI flag appending after ikwid processing; uses setdefault so per-agent and CLI env flags correctly take precedence. Logic is clean and well-ordered.
src/vibepod/core/agents.py Adds llm_env_map and llm_model_args to AgentSpec; codex silently drops api_key (by design) which may surprise users connecting to authenticated OSS servers.
src/vibepod/core/config.py Adds llm section to default config and four VP_LLM_* env-var overrides; consistent with existing patterns and correctly typed.
tests/test_run.py Good coverage of LLM injection scenarios; two test functions have names and docstrings referencing "OPENAI" vars that contradict the actual assertions (ANTHROPIC / CODEX_OSS).
tests/test_agents.py Adds accurate spec assertions for claude and codex LLM fields; agents-without-mapping test correctly covers remaining agents.
tests/test_config.py Two new config tests verify default LLM section and VP_LLM_* env overrides; both are correct and complete.
docs/llm.md New documentation page clearly explains Ollama/vLLM usage, per-agent overrides, and the important host.docker.internal note. Well structured.
docs/configuration.md Configuration reference updated with llm section YAML sample and VP_LLM_* env-var table entries; accurate and complete.
mkdocs.yml Single nav entry added for LLM Integration page; no issues.

Sequence Diagram

sequenceDiagram
    participant User
    participant run.py
    participant config.py
    participant agents.py
    participant DockerManager
    participant LLM Server

    User->>run.py: vp run claude (or codex)
    run.py->>config.py: get_config()
    config.py-->>run.py: merged config (default + global YAML + project YAML + VP_LLM_* env)

    run.py->>agents.py: get_agent_spec(agent)
    agents.py-->>run.py: AgentSpec (llm_env_map, llm_model_args)

    Note over run.py: Build merged_env from spec.extra_env,<br/>per-agent config env, CLI --env flags

    alt llm.enabled AND spec.llm_env_map present
        run.py->>run.py: setdefault(ANTHROPIC_BASE_URL, base_url)<br/>setdefault(ANTHROPIC_API_KEY, api_key)
        run.py->>run.py: llm_command_extra = [--model, model]
    end

    run.py->>DockerManager: run_agent(env=merged_env, command=[claude, --model, qwen3:14b])
    DockerManager->>LLM Server: HTTP requests via ANTHROPIC_BASE_URL
    LLM Server-->>DockerManager: model responses
Loading

Last reviewed commit: d36daa2

Comment thread tests/test_run.py
Comment thread tests/test_run.py
Comment thread src/vibepod/core/agents.py
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
tests/test_run.py (2)

711-766: Rename tests/docstrings to match asserted env namespace.

At Line 711 and Line 764, the names/docstrings say “OPENAI env vars”, but Claude assertions check ANTHROPIC_* and Codex checks CODEX_OSS_*. This is a small clarity mismatch that can confuse future debugging.

✏️ Suggested rename
-def test_llm_enabled_injects_openai_env_vars(monkeypatch, tmp_path: Path) -> None:
-    """When llm.enabled=true, OPENAI_BASE_URL/API_KEY/MODEL are injected."""
+def test_llm_enabled_injects_claude_llm_env_vars(monkeypatch, tmp_path: Path) -> None:
+    """When llm.enabled=true, Claude receives ANTHROPIC_* env vars and --model args."""

-def test_llm_enabled_injects_openai_env_vars_for_codex(monkeypatch, tmp_path: Path) -> None:
-    """When llm.enabled=true, codex gets OPENAI_* env vars."""
+def test_llm_enabled_injects_codex_llm_env_vars(monkeypatch, tmp_path: Path) -> None:
+    """When llm.enabled=true, Codex receives CODEX_OSS_* env vars and --oss model args."""
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_run.py` around lines 711 - 766, Rename the misleading test
names/docstrings so they match the environment variables actually asserted:
update test_llm_enabled_injects_openai_env_vars (and its docstring) to reference
"ANTHROPIC env vars" (or "Anthropic env vars") since the assertions check
ANTHROPIC_* and update test_llm_enabled_injects_openai_env_vars_for_codex (and
its docstring) to reference "CODEX_OSS env vars" (or "Codex OSS env vars") to
match the CODEX_OSS_* assertions; change only the function names and docstring
strings (keep behavior and assertions in run_cmd.run, _CapturingDockerManager,
captured, and env checks unchanged).

715-1005: Extract duplicated _CapturingDockerManager test stub into a helper.

The same stub class is repeated many times in this changed section. A shared helper will reduce noise and drift risk.

♻️ Suggested consolidation
+def _make_capturing_manager(captured: dict, container_name: str):
+    class _CapturingDockerManager:
+        def ensure_network(self, name: str) -> None:
+            pass
+        def networks_with_running_containers(self) -> list[str]:
+            return []
+        def pull_image(self, image: str) -> None:
+            pass
+        def ensure_proxy(self, **kwargs) -> None:  # type: ignore[no-untyped-def]
+            pass
+        def run_agent(self, **kwargs) -> object:  # type: ignore[no-untyped-def]
+            captured.update(kwargs)
+            return type(
+                "_Container",
+                (),
+                {
+                    "name": container_name,
+                    "id": "abc123",
+                    "status": "running",
+                    "attrs": {"NetworkSettings": {"Networks": {}}},
+                    "reload": lambda self: None,
+                    "labels": {},
+                    "logs": lambda self, **kw: b"",
+                },
+            )()
+    return _CapturingDockerManager
-    class _CapturingDockerManager:
-        ...
-    monkeypatch.setattr(run_cmd, "DockerManager", _CapturingDockerManager)
+    monkeypatch.setattr(
+        run_cmd,
+        "DockerManager",
+        _make_capturing_manager(captured, "vibepod-claude-test"),
+    )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_run.py` around lines 715 - 1005, Multiple tests duplicate the
_CapturingDockerManager stub; extract it into a single helper (or pytest
fixture) to reduce repetition. Create a helper function or class (e.g.,
_make_capturing_docker_manager or a pytest fixture named
capturing_docker_manager) that accepts the shared captured dict and returns a
DockerManager-like object implementing ensure_network,
networks_with_running_containers, pull_image, ensure_proxy, and run_agent (which
updates the provided captured dict and returns the container object used in
tests). Replace each inline _CapturingDockerManager in the tests with calls to
this helper or the fixture and wire monkeypatch.setattr(run_cmd,
"DockerManager", ...) to use the helper to keep existing test behavior (preserve
container attrs, name/id/status, and logs/reload lambdas). Ensure tests that
need per-agent differences still pass a modified container name or env via
parameters to the helper.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@tests/test_run.py`:
- Around line 711-766: Rename the misleading test names/docstrings so they match
the environment variables actually asserted: update
test_llm_enabled_injects_openai_env_vars (and its docstring) to reference
"ANTHROPIC env vars" (or "Anthropic env vars") since the assertions check
ANTHROPIC_* and update test_llm_enabled_injects_openai_env_vars_for_codex (and
its docstring) to reference "CODEX_OSS env vars" (or "Codex OSS env vars") to
match the CODEX_OSS_* assertions; change only the function names and docstring
strings (keep behavior and assertions in run_cmd.run, _CapturingDockerManager,
captured, and env checks unchanged).
- Around line 715-1005: Multiple tests duplicate the _CapturingDockerManager
stub; extract it into a single helper (or pytest fixture) to reduce repetition.
Create a helper function or class (e.g., _make_capturing_docker_manager or a
pytest fixture named capturing_docker_manager) that accepts the shared captured
dict and returns a DockerManager-like object implementing ensure_network,
networks_with_running_containers, pull_image, ensure_proxy, and run_agent (which
updates the provided captured dict and returns the container object used in
tests). Replace each inline _CapturingDockerManager in the tests with calls to
this helper or the fixture and wire monkeypatch.setattr(run_cmd,
"DockerManager", ...) to use the helper to keep existing test behavior (preserve
container attrs, name/id/status, and logs/reload lambdas). Ensure tests that
need per-agent differences still pass a modified container name or env via
parameters to the helper.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0ae59b23-3e7c-4d29-82a6-5f7490526acd

📥 Commits

Reviewing files that changed from the base of the PR and between e01acab and d36daa2.

📒 Files selected for processing (9)
  • docs/configuration.md
  • docs/llm.md
  • mkdocs.yml
  • src/vibepod/commands/run.py
  • src/vibepod/core/agents.py
  • src/vibepod/core/config.py
  • tests/test_agents.py
  • tests/test_config.py
  • tests/test_run.py

@nezhar nezhar merged commit 0250331 into main Mar 17, 2026
20 checks passed
@nezhar nezhar deleted the issue-11 branch March 20, 2026 13:54
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