Skip to content

feat(langchain): Add Google Gemini , Vertex AI and Ollama model support#30

Open
Thareesha98 wants to merge 7 commits into
wso2:mainfrom
Thareesha98:feat/add-model-support
Open

feat(langchain): Add Google Gemini , Vertex AI and Ollama model support#30
Thareesha98 wants to merge 7 commits into
wso2:mainfrom
Thareesha98:feat/add-model-support

Conversation

@Thareesha98

@Thareesha98 Thareesha98 commented May 27, 2026

Copy link
Copy Markdown

Purpose

The Python execution backend (afm-langchain) currently only supports OpenAI and Anthropic models out of the box. With the recent rapid adoption of Google Gemini models, enterprise-grade architecture migrations across Google Cloud Platform (GCP), and the growing demand for completely local, privacy-focused execution using open-source weights, developers using Agent-Flavored Markdown (AFM) lack a native mechanism to route their agent definitions to either Google's GenAI ecosystem or local endpoints like Ollama.

Furthermore, enterprise configurations often require provisioning models within strict cloud compliance boundaries (e.g., Google Vertex AI) which demand declarative parameters such as specific project identifiers and localized cloud regions straight from the source file metadata rather than scattered across global system environment settings.

Resolves #6

Goals

  • Introduce a native, lazy-loaded initialization factory engine for Google Gemini models via langchain-google-genai.
  • Introduce a native, zero-configuration local initialization factory engine for open-source models via langchain-ollama.
  • Extend the structural components of the core AFM data models to recognize, validate, and safely process declarative model-level properties.
  • Enable automatic backend detection capable of running standard developer keys (Google AI Studio), switching dynamically into enterprise regional nodes (Vertex AI Platform) with support for Application Default Credentials (ADC), or executing completely offline via Ollama purely based on structural properties written within the AFM Markdown layout.
  • Extend the Ballerina interpreter to support offline local models via the ballerinax/ai.ollama connector, mirroring the Python provider structure.
  • Gracefully handle unimplemented model providers (like Gemini) in the Ballerina runtime with descriptive, actionable error boundaries.

Approach

  1. Schema Enhancements (packages/afm-core/src/afm/models.py):
    Modified the strict Model Pydantic class to include optional project: str | None and location: str | None properties, allowing these keys to bypass the extra="forbid" structural layout validation block cleanly.
  2. Dependency Updates (packages/afm-langchain/pyproject.toml):
    Added production runtime tracking for both langchain-google-genai and langchain-ollama inside package dependencies to safely tie model availability into the workspace toolchain layer.
  3. Provider Factory Construction (packages/afm-langchain/src/afm_langchain/providers.py):
    • Implemented _create_gemini_model(afm_model: Model) and _create_ollama_model(afm_model: Model) utilizing safe lazy-import parsing to shield the runner from boot overhead unless explicitly called.
    • Wired an absolute keyword argument compiler that maps initialization keys, regional targets, and routes base URL structures accurately.
    • Built an explicit toggle (kwargs["vertexai"] = True) triggered instantly upon discovering a declared project metadata string, ensuring data traffic smoothly hits GCP compliance zones.
    • Credential Fallback Optimization: Refined the Gemini client builder to conditionally bypass strict api_key extraction if project is defined, natively enabling Google Cloud Application Default Credentials (ADC) fallbacks for enterprise deployments.
  4. Ballerina Interpreter Alignment (ballerina-interpreter/agent_creator.bal):
    Wired the ollama match block to initialize ollama:ModelProvider with custom URL fallbacks, and explicitly mapped gemini to raise a descriptive "not yet supported" error.

User stories

  • As an AI Engineer, I want to define an AFM model provider block as gemini with model configurations like gemini-2.5-flash so that my agent uses Google's latest reasoning engines seamlessly.
  • As an Enterprise Architect, I want to declaratively state my GCP project and location properties right inside my agent's .md file frontmatter so that execution logic runs deterministically in a secured cloud space using API keys or Application Default Credentials (ADC) without modifying system-level variables.
  • As a Privacy-Focused Developer, I want to set my model provider to ollama and run models like llama3 completely locally and offline without requiring API keys or incurring external transactional costs.

Release note

Introduced native Google Gemini and local Ollama model support within the Python LangChain execution backend (afm-langchain). This includes complete support for the Gemini Developer API (Google AI Studio), declarative metadata-driven onboarding for the enterprise Google Cloud Vertex AI Platform (supporting both explicit API keys and native Application Default Credentials), and zero-dependency local execution for open-source weights using Ollama.

Unit tests

  • Python Interpreter (packages/afm-langchain/tests/test_providers.py):
    Implemented mock-isolated pytest suites utilizing unittest.mock.patch to verify configuration mapping logic (OpenAI, Anthropic, Gemini AI Studio, Vertex ADC, and Ollama) completely offline without invoking actual runtime sockets.

    Run via:

    uv run pytest packages/afm-langchain/tests/test_providers.py
    
    

Security checks

Sample 1 : Enterprise Cloud Infrastructure Access (Google Cloud Vertex AI Platform)

---
name: "Gemini Enterprise Assistant"
model:
  provider: "gemini"
  name: "gemini-2.5-flash"
  project: "my-gcp-enterprise-project"
  location: "us-central1"
---

Sample 2 : Standard Developer Access (Google AI Studio / Gemini Developer API)

---
name: "Math Tutor"
model:
  provider: "gemini"
  name: "gemini-2.5-flash"
  authentication:
    type: "api-key"
    api_key: "${env:GOOGLE_API_KEY}"
---

Sample 3 : Ollama Model Access

---
name: "Local Offline Assistant"
model:
  provider: "ollama"
  name: "llama3"
  url: "http://host.docker.internal:11434"
---

@Thareesha98 Thareesha98 requested a review from MaryamZi as a code owner May 27, 2026 17:37
@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This pull request extends AFM's model provider support by adding Gemini and Ollama integrations. The Model schema is extended with optional project and location fields to support Vertex AI configuration. The LangChain package gains Gemini and Ollama factory implementations with conditional Vertex AI credential handling and discovery-based API key injection. Comprehensive unit tests cover all provider paths including environment variable fallback and missing-package scenarios. The Ballerina agent is wired to resolve Ollama model providers and explicitly handle unsupported Gemini requests. Ballerina integration tests validate both default and custom Ollama endpoint configurations.

Sequence Diagram

sequenceDiagram
  participant Client
  participant create_model_provider
  participant _create_gemini_model
  participant _create_ollama_model
  participant ChatGoogleGenerativeAI
  participant ChatOllama
  Client->>create_model_provider: Model with provider="gemini"
  create_model_provider->>_create_gemini_model: afm_model
  _create_gemini_model->>ChatGoogleGenerativeAI: model, base_url, project, location, vertexai, api_key
  ChatGoogleGenerativeAI-->>Client: ChatGoogleGenerativeAI instance
  Client->>create_model_provider: Model with provider="ollama"
  create_model_provider->>_create_ollama_model: afm_model
  _create_ollama_model->>ChatOllama: model, base_url
  ChatOllama-->>Client: ChatOllama instance
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.19% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main changes: adding Google Gemini, Vertex AI, and Ollama model support to the LangChain backend.
Description check ✅ Passed The description addresses most template sections with relevant details. Security checks and unit tests are confirmed; samples are provided. Documentation and training sections are not included, but other critical sections are substantially complete.
Linked Issues check ✅ Passed Code changes fully implement issue #6 objectives: support for Google Gemini (Developer API and Vertex AI) and Ollama providers is added with declarative configuration support in AFM models.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #6 requirements: extending provider support, schema enhancements for provider-specific configuration, and interpreter updates for new providers.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{}

@CLAassistant

CLAassistant commented May 27, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@python-interpreter/packages/afm-langchain/src/afm_langchain/providers.py`:
- Around line 130-143: In _create_gemini_model, avoid unconditionally calling
_get_api_key and always injecting "api_key" into kwargs: only call
_get_api_key(api sources) when afm_model.project is falsy (non-Vertex path) so
Vertex (afm_model.project → vertexai=True) can rely on ADC; update kwargs
construction to include "api_key" only if a value was returned; alternatively
check GEMINI_API_KEY as a fallback env var before calling _get_api_key or simply
omit "api_key" when using Vertex so ChatGoogleGenerativeAI initialization can
handle its own credential fallback. Ensure changes reference
_create_gemini_model, afm_model.project, api_key, kwargs, _get_api_key, and
ChatGoogleGenerativeAI.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4faf53c3-0919-477b-9c2c-39873b5686f3

📥 Commits

Reviewing files that changed from the base of the PR and between 9c1fd1c and f486733.

⛔ Files ignored due to path filters (1)
  • python-interpreter/uv.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • python-interpreter/packages/afm-core/src/afm/models.py
  • python-interpreter/packages/afm-langchain/pyproject.toml
  • python-interpreter/packages/afm-langchain/src/afm_langchain/providers.py

Comment thread python-interpreter/packages/afm-langchain/src/afm_langchain/providers.py Outdated
@Thareesha98 Thareesha98 force-pushed the feat/add-model-support branch from f486733 to 2294d7b Compare May 28, 2026 06:05
@Thareesha98 Thareesha98 changed the title feat(langchain): Add Google Gemini and Vertex AI support feat(langchain): Add Google Gemini , Vertex AI and Ollama model support May 28, 2026

@MaryamZi MaryamZi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Shall we stick to imperative mood for commit messages?

import ballerinax/ai.anthropic;
import ballerinax/ai.openai;

import ballerinax/ai.ollama;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
import ballerinax/ai.ollama;
import ballerinax/ai.ollama;

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks. I added a new line

import ballerina/io;
import ballerina/lang.runtime;
import ballerina/test;
import ballerina/ai;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's add in alphabetic order.

Comment on lines +361 to +362
// ============================================
// Array Schema End-to-End Tests
// ============================================

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

WOuldn't change unrelated code.

};
var result = getModel(model);
test:assertTrue(result is ai:ModelProvider);
} No newline at end of file

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's add an error test for Gemini also.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Error test for gemini is already added before. (332 - 341 Lines)

Comment thread ballerina-interpreter/agent.bal Outdated
Comment on lines +131 to +134
return new ollama:ModelProvider(
check name.ensureType(),
model.url ?: "http://localhost:11434"
);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
return new ollama:ModelProvider(
check name.ensureType(),
model.url ?: "http://localhost:11434"
);
string? url = model.url;
return url is string ?
new ollama:ModelProvider(check name.ensureType(), url) :
new ollama:ModelProvider(check name.ensureType());

to rely on the default from the model provider itself.

Comment thread ballerina-interpreter/Dependencies.toml Outdated
[ballerina]
dependencies-toml-version = "2"
distribution-version = "2201.12.10"
distribution-version = "2201.13.4"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's not bump the Ballerina version for now.

Comment on lines +66 to +67
project: str | None = None
location: str | None = None

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Since these are relevant only for Gemini, adding them in the base Model is not quite correct. Let's consider an alternative to this.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I think we can set extra="allow" in model_config = ConfigDict(extra="allow") and access those extra fields by extra_attrs = afm_model.model_extra

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
python-interpreter/packages/afm-langchain/tests/test_providers.py (2)

177-195: ⚡ Quick win

Assert location in the explicit Vertex test.

This test pins project, vertexai, and api_key, but it does not verify that location is still forwarded on the explicit-credentials Vertex path. Adding that assertion would fully cover the Vertex contract exercised here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python-interpreter/packages/afm-langchain/tests/test_providers.py` around
lines 177 - 195, Update the test_create_gemini_vertex_with_explicit_credentials
test to also assert that the forwarded location is correct: after calling
create_model_provider and grabbing kwargs = mock_chat_gemini.call_args[1], add
an assertion that kwargs["location"] == "us-central1" so the
explicit-credentials Vertex path verifies the location is passed through; the
change is in the test function that references Model, ClientAuthentication,
create_model_provider and mock_chat_gemini.

82-124: ⚡ Quick win

Add no-credential failure coverage for Anthropic and Gemini Studio.

Only the OpenAI path currently verifies the expected ProviderError when neither AFM metadata nor environment variables provide credentials. Adding the same negative-path test for Anthropic and Gemini Studio would catch provider-specific regressions such as an incorrect env var lookup or an unintended silent fallback.

Also applies to: 126-157

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python-interpreter/packages/afm-langchain/tests/test_providers.py` around
lines 82 - 124, Add negative-path unit tests for Anthropic and Gemini Studio
mirroring the OpenAI no-credential test: create Model(provider="anthropic",
name="claude-sonnet-4-5") and Model(provider="gemini-studio", name="...") with
no authentication, use patch.dict(os.environ, {}, clear=True) to ensure no env
creds, then assert that create_model_provider(...) raises ProviderError; name
the tests test_anthropic_no_credentials_failure and
test_gemini_studio_no_credentials_failure and reference create_model_provider
and ProviderError so CI will catch missing env-var lookups or silent fallbacks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@python-interpreter/packages/afm-langchain/tests/test_providers.py`:
- Around line 177-195: Update the
test_create_gemini_vertex_with_explicit_credentials test to also assert that the
forwarded location is correct: after calling create_model_provider and grabbing
kwargs = mock_chat_gemini.call_args[1], add an assertion that kwargs["location"]
== "us-central1" so the explicit-credentials Vertex path verifies the location
is passed through; the change is in the test function that references Model,
ClientAuthentication, create_model_provider and mock_chat_gemini.
- Around line 82-124: Add negative-path unit tests for Anthropic and Gemini
Studio mirroring the OpenAI no-credential test: create
Model(provider="anthropic", name="claude-sonnet-4-5") and
Model(provider="gemini-studio", name="...") with no authentication, use
patch.dict(os.environ, {}, clear=True) to ensure no env creds, then assert that
create_model_provider(...) raises ProviderError; name the tests
test_anthropic_no_credentials_failure and
test_gemini_studio_no_credentials_failure and reference create_model_provider
and ProviderError so CI will catch missing env-var lookups or silent fallbacks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5f4066d4-20b5-493c-833c-3a73196991d2

📥 Commits

Reviewing files that changed from the base of the PR and between 3ba3efd and f1b5511.

📒 Files selected for processing (3)
  • ballerina-interpreter/Dependencies.toml
  • ballerina-interpreter/tests/agent_test.bal
  • python-interpreter/packages/afm-langchain/tests/test_providers.py
✅ Files skipped from review due to trivial changes (1)
  • ballerina-interpreter/Dependencies.toml

@Thareesha98 Thareesha98 force-pushed the feat/add-model-support branch 2 times, most recently from bd1f791 to bfb9410 Compare June 8, 2026 06:56

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@python-interpreter/packages/afm-core/src/afm/models.py`:
- Line 60: The Model class has been relaxed by setting model_config =
ConfigDict(extra="allow"), which permits unknown keys and hides frontmatter
typos; revert this to keep Model strict by removing or changing the model_config
to the default (no extra="allow") so only the explicit Vertex fields (e.g.,
project, location) are accepted; update the Model class definition (inspect the
model_config variable and ConfigDict usage) to restore strict validation and
rely on the explicit fields consumed downstream (see providers that read project
and location).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 884aaa3e-079c-4b9f-a5df-d2536cde24c3

📥 Commits

Reviewing files that changed from the base of the PR and between f1b5511 and bfb9410.

📒 Files selected for processing (3)
  • ballerina-interpreter/agent.bal
  • ballerina-interpreter/tests/agent_test.bal
  • python-interpreter/packages/afm-core/src/afm/models.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • ballerina-interpreter/agent.bal


class Model(BaseModel):
model_config = ConfigDict(extra="forbid")
model_config = ConfigDict(extra="allow")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep Model strict and rely on the explicit Vertex fields.

Changing Model to extra="allow" broadens the AFM schema from rejecting unknown keys to silently accepting them. In this PR, the downstream Gemini path only reads the explicit project and location fields, so relaxing validation is not needed for the new provider support and makes frontmatter typos harder to catch. Cross-file evidence: python-interpreter/packages/afm-langchain/src/afm_langchain/providers.py:125-160 only consumes those explicit fields.

Suggested change
 class Model(BaseModel):
-    model_config = ConfigDict(extra="allow")
+    model_config = ConfigDict(extra="forbid")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
model_config = ConfigDict(extra="allow")
model_config = ConfigDict(extra="forbid")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python-interpreter/packages/afm-core/src/afm/models.py` at line 60, The Model
class has been relaxed by setting model_config = ConfigDict(extra="allow"),
which permits unknown keys and hides frontmatter typos; revert this to keep
Model strict by removing or changing the model_config to the default (no
extra="allow") so only the explicit Vertex fields (e.g., project, location) are
accepted; update the Model class definition (inspect the model_config variable
and ConfigDict usage) to restore strict validation and rely on the explicit
fields consumed downstream (see providers that read project and location).

@Thareesha98 Thareesha98 force-pushed the feat/add-model-support branch from bfb9410 to 85a487c Compare June 8, 2026 08:53
@Thareesha98 Thareesha98 force-pushed the feat/add-model-support branch from 4909811 to 24659e9 Compare June 10, 2026 15:57
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.

Support more model providers

3 participants