Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 71 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,62 +8,104 @@
[![codecov](https://codecov.io/github/mokksy/ai-mocks/graph/badge.svg?token=449G80QY5S)](https://codecov.io/github/mokksy/ai-mocks)
![CodeRabbit Pull Request Reviews](https://img.shields.io/coderabbit/prs/github/mokksy/ai-mocks?utm_source=oss&utm_medium=github&utm_campaign=mokksy%2Fai-mocks&color=FF570A&link=https%3A%2F%2Fcoderabbit.ai&label=CodeRabbit+Reviews)

[![Documentation](https://img.shields.io/badge/docs-website-blue)](https://mokksy.dev/)
[![API Reference](https://img.shields.io/badge/api-reference-blue)](https://mokksy.dev/apidocs/)
[![Documentation](https://img.shields.io/badge/docs-website-blue)](https://mokksy.dev/docs/ai-mocks/)
[![API Reference](https://img.shields.io/badge/api-reference-blue)](https://mokksy.github.io/ai-mocks/)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/mokksy/ai-mocks)

![Kotlin API](https://img.shields.io/badge/Kotlin-2.2-%237F52FF.svg?logo=kotlin&logoColor=white)
![Java](https://img.shields.io/badge/JVM-17-%23ED8B00.svg)

_AI-Mocks_ are mock LLM (Large Language Model) servers built on [Mokksy](https://github.com/mokksy/mokksy/), a mock server inspired by WireMock, with support for
response streaming and Server-Side Events (SSE). They are designed to build, test, and mock LLM responses for development purposes.
**AI-Mocks** provides provider-compatible mock servers for AI integration testing in Kotlin and Java. Test clients for OpenAI, Anthropic, Gemini, Ollama, and the Agent-to-Agent (A2A) protocol through real HTTP and streaming behavior, without sending requests to live provider APIs.

AI-Mocks is built on [Mokksy](https://github.com/mokksy/mokksy), the HTTP and SSE mock server for deterministic integration testing.
Use [Mokksy](https://mokksy.dev/docs/mokksy/) for general HTTP APIs, streaming APIs, and failure simulation.
Use AI-Mocks when the service under test exposes an AI provider-compatible or A2A API.

- Documentation: [mokksy.dev/docs/ai-mocks](https://mokksy.dev/docs/ai-mocks/)
- Integration guides: [mokksy.dev/docs/integrations](https://mokksy.dev/docs/integrations/)
- API reference: [mokksy.github.io/ai-mocks](https://mokksy.github.io/ai-mocks/)
- Core HTTP/SSE mock server: [github.com/mokksy/mokksy](https://github.com/mokksy/mokksy)

[![Buy me a Coffee](https://cdn.buymeacoffee.com/buttons/default-orange.png)](https://buymeacoffee.com/mailsk)

## Mokksy
## Choose the right layer

**[Mokksy](https://github.com/mokksy/mokksy)** is a mock HTTP server built with [Kotlin](https://kotlinlang.org/)
and [Ktor](https://ktor.io/). It addresses the limitations of WireMock by supporting true SSE and streaming responses,
making it extreamly useful for integration testing LLM clients.
| What you need to test | Start with |
|-----------------------|------------|
| General HTTP endpoints, Server-Sent Events (SSE), streamed responses, delays, or status/error scenarios | [Mokksy](https://mokksy.dev/docs/mokksy/) |
| Provider- or protocol-shaped AI requests and responses using SDKs or frameworks | [AI-Mocks](https://mokksy.dev/docs/ai-mocks/) |
| An application that combines business HTTP integrations with AI providers | Mokksy for general dependencies and AI-Mocks for provider APIs |

# AI-Mocks
## Supported providers and protocols

| Provider or protocol | Module | Supported surface | Documentation |
|----------------------|--------|-------------------|---------------|
| OpenAI | `ai-mocks-openai` | Chat Completions, Responses, streaming, embeddings, moderation | [OpenAI](https://mokksy.dev/docs/ai-mocks/openai/) |
| Anthropic | `ai-mocks-anthropic` | Messages and streaming | [Anthropic](https://mokksy.dev/docs/ai-mocks/anthropic/) |
| Google Gemini | `ai-mocks-gemini` | Generate Content and streaming | [Gemini](https://mokksy.dev/docs/ai-mocks/gemini/) |
| Ollama | `ai-mocks-ollama` | Chat, generate, streaming, embeddings | [Ollama](https://mokksy.dev/docs/ai-mocks/ollama/) |
| Agent-to-Agent (A2A) | `ai-mocks-a2a` | A2A protocol behavior and streaming | [A2A](https://mokksy.dev/docs/ai-mocks/a2a/) |

## Tested integrations

The repository integration tests exercise these client and framework combinations:

| AI-Mocks module | Tested clients and frameworks |
|-----------------|-------------------------------|
| OpenAI | Official OpenAI Java SDK, LangChain4j, Spring AI |
| Anthropic | Official Anthropic Java SDK, LangChain4j |
| Gemini | Google Gen AI Java SDK, LangChain4j, Spring AI |
| Ollama | LangChain4j, Spring AI |

## Quick start with OpenAI

**AI-Mocks** is a set of specialized mock server implementations (e.g., mocking OpenAI API) built using Mokksy.
Add the OpenAI test dependency:

It supports mocking following AI services:
1. [OpenAI](https://platform.openai.com/docs/api-reference/) - [ai-mocks-openai](https://mokksy.dev/docs/ai-mocks/openai/)
2. [Anthropic](https://docs.anthropic.com/en/api) - [ai-mocks-anthropic](https://mokksy.dev/docs/ai-mocks/anthropic/)
3. [Google VertexAI Gemini](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference) - [ai-mocks-gemini](https://mokksy.dev/docs/ai-mocks/gemini/)
4. [Ollama](https://github.com/ollama/ollama/blob/main/docs/api.md) - [ai-mocks-ollama](https://mokksy.dev/docs/ai-mocks/ollama/)
5. [Agent-to-Agent (A2A) Protocol](https://a2a-protocol.org/latest/specification/) - [ai-mocks-a2a](https://mokksy.dev/docs/ai-mocks/a2a/)
```kotlin
dependencies {
testImplementation("dev.mokksy.aimocks:ai-mocks-openai-jvm:$latestVersion")
}
```

Declare a deterministic completion response and point the client under test to `openai.baseUrl()`:

## Feature Support Matrix
```kotlin
import dev.mokksy.aimocks.openai.MockOpenai

| Feature | OpenAI | Anthropic | Gemini | Ollama | A2A |
|----------------------|-----------|-----------|--------|----------|--------------------------------------|
| **Chat Completions** | ✅ | ✅ | ✅ | ✅ | ✅ |
| **Streaming** | ✅ | ✅ | ✅ | ✅ | ✅ |
| **Embeddings** | ✅ | ❌ | ❌ | ✅ | ❌ |
| **Moderation** | ✅ | ❌ | ❌ | ❌ | ❌ |
| **Additional APIs** | Responses | - | - | Generate | Full A2A Protocol<br/>(11 endpoints) |
val openai = MockOpenai(verbose = true)

openai.completion {
model = "gpt-4o-mini"
userMessageContains("Hello")
} responds {
assistantContent = "Hello from the mock"
finishReason = "stop"
}

// Configure the OpenAI SDK or framework under test to use openai.baseUrl().
```

## How to build
The DSL and `baseUrl()` configuration pattern are exercised by the official OpenAI SDK integration tests in this repository. For complete SDK and framework examples, see the [AI-Mocks documentation](https://mokksy.dev/docs/ai-mocks/) and [integration guides](https://mokksy.dev/docs/integrations/).

Building project locally:
## Why AI-Mocks?

- Exercise provider-compatible requests and responses with the real HTTP client configuration used by your application.
- Test streaming responses deterministically in CI without live provider credentials, network dependence, quotas, or provider rate limits.
- Verify application behavior for provider responses and streamed events before relying on live external services.
- Keep provider-specific behavior in AI-Mocks while using [Mokksy](https://mokksy.dev/docs/mokksy/) for other HTTP dependencies and failure scenarios.

## Build locally

```shell
./gradlew build
```

or using Make:
or:

```shell
make
```

## Contributing

I do welcome contributions! Please see the [Contributing Guidelines](CONTRIBUTING.md) for details.

Contributions are welcome. See the [Contributing Guidelines](CONTRIBUTING.md) for details.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import dev.mokksy.aimocks.ollama.embed.OllamaEmbedRequestSpecification
import dev.mokksy.aimocks.ollama.generate.GenerateRequest
import dev.mokksy.aimocks.ollama.generate.OllamaGenerateBuildingStep
import dev.mokksy.aimocks.ollama.generate.OllamaGenerateRequestSpecification
import dev.mokksy.mokksy.InternalMokksyApi
import dev.mokksy.mokksy.ServerConfiguration
import dev.mokksy.mokksy.utils.highlight.Highlighting
import io.kotest.assertions.json.containJsonKeyValue
import io.kotest.matchers.string.contain
import io.ktor.serialization.kotlinx.json.json
Expand All @@ -30,6 +32,7 @@ import kotlinx.serialization.json.Json
* @param verbose Controls whether the mock server's operations are logged in detail. Defaults to true.
* @author Konstantin Pavlov
*/
@OptIn(InternalMokksyApi::class)
public open class MockOllama(
port: Int = 0,
verbose: Boolean = true,
Expand All @@ -48,6 +51,10 @@ public open class MockOllama(
)
},
) {
init {
Highlighting.registerJsonContentType("application/x-ndjson")
}

/**
* Sets up a mock handler for the Ollama `/api/generate` completion endpoint.
*
Expand Down Expand Up @@ -246,7 +253,7 @@ public open class MockOllama(
/**
* Returns the base URL of the mock Ollama server.
*
* @return The server URL in the format `http://localhost:<port>`.
* @return The server base URL.
*/
override fun baseUrl(): String = "http://localhost:${port()}"
override fun baseUrl(): String = mokksy.baseUrl()
Comment on lines 253 to +258

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.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Document the new baseUrl() behaviour explicitly in KDoc.

baseUrl() now delegates to the parent mock server configuration, but the KDoc still describes it generically. Please add a brief behaviour note and a small usage example (e.g. wiring client .baseUrl(mock.baseUrl())) so callers understand host/port resolution expectations.

As per coding guidelines, "Ensure all public APIs have proper KDoc/Javadoc comments including examples, parameters, return values, exceptions, and behavior explanation" and "Update KDocs when API is changed".

🤖 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
`@ai-mocks-ollama/src/commonMain/kotlin/dev/mokksy/aimocks/ollama/MockOllama.kt`
around lines 253 - 258, Update the KDoc for MockOllama.baseUrl() to explicitly
state that it delegates to the parent mock server configuration by calling
mokksy.baseUrl(), describe that host and port are resolved from the parent mock
instance, and add a brief one-line usage example such as wiring a client with
client.baseUrl(mock.baseUrl()); retain `@return` and behavior notes so callers
understand delegation and resolution semantics.

}
Loading