Skip to content

Commit eb3885f

Browse files
authored
Add Koog Framework Examples (#379)
# Add Koog Framework Examples to Samples This PR introduces comprehensive examples demonstrating A2A protocol implementation using [Koog](https://koog.ai/), JetBrains' open-source agentic framework for building enterprise-ready AI agents, targeting JVM backend, Android, iOS, JS, and WasmJS. ## What's Added Two progressive examples showing different A2A communication patterns: ### 1. Simple Joke Agent (`simplejoke`) - Basic message-based A2A communication - Direct request-response pattern using `sendMessage()` - Demonstrates minimal A2A server setup with AgentCard and message storage ### 2. Advanced Joke Agent (`advancedjoke`) - Full task-based A2A workflow implementation - Graph-based agent architecture using Koog's `GraphAIAgent` - Complete task lifecycle: Submitted → Working → InputRequired → Completed - Interactive clarifications via InputRequired state - Streaming task events and artifact delivery - Structured LLM outputs with type-safe parsing ## Key Features Demonstrated - **A2A Protocol Integration**: Both simple message-based and advanced task-based workflows - **Graph-based Agent Design**: Maintainable, visual agent logic using nodes and edges - **Koog's Prompt DSL**: Type-safe prompt building with automatic context management ## Why Koog? Adds diversity to A2A samples by showcasing: - JVM/Kotlin ecosystem representation - Type-safe agent development with compile-time guarantees - Multi-platform deployment options beyond Node.js/Python Each example includes detailed inline documentation and runnable Gradle tasks for immediate testing.
1 parent 8684c27 commit eb3885f

File tree

18 files changed

+1540
-0
lines changed

18 files changed

+1540
-0
lines changed

.editorconfig

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
root = true
2+
3+
[*.{kt,kts}]
4+
charset = utf-8
5+
end_of_line = lf
6+
insert_final_newline = true
7+
indent_style = space
8+
indent_size = 4
9+
max_line_length = 120
10+
11+
ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL
12+
13+
# Disable wildcard imports entirely
14+
ij_kotlin_name_count_to_use_star_import = 2147483647
15+
ij_kotlin_name_count_to_use_star_import_for_members = 2147483647
16+
ij_kotlin_packages_to_use_import_on_demand = unset
17+
18+
ktlint_code_style = ktlint_official
19+
ktlint_standard_annotation = disabled
20+
ktlint_standard_class-naming = disabled
21+
ktlint_standard_class-signature = disabled
22+
ktlint_standard_filename = disabled
23+
ktlint_standard_function-expression-body = disabled
24+
ktlint_standard_function-signature = disabled
25+
ktlint_standard_if-else-bracing = enabled
26+
ktlint_standard_if-else-wrapping = enabled
27+
ktlint_standard_no-consecutive-comments = disabled
28+
ktlint_standard_no-single-line-block-comment = disabled
29+
ktlint_standard_property-naming = disabled
30+
ktlint_standard_trailing-comma-on-call-site = disabled
31+
ktlint_standard_trailing-comma-on-declaration-site = disabled
32+
ktlint_standard_try-catch-finally-spacing = enabled
33+
ktlint_standard_backing-property-naming = disabled
34+
35+
[**/build/**/*]
36+
ktlint = disabled

samples/java/koog/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/.gradle
2+
/build
3+
/.kotlin

samples/java/koog/README.md

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# Agent-to-Agent (A2A) with Koog Framework Examples
2+
3+
This project demonstrates how to build A2A-enabled agents using [Koog](https://github.com/JetBrains/koog), the official JetBrains' framework for building predictable,
4+
fault-tolerant, and enterprise-ready AI agents, targeting JVM backend, Android, iOS, JS, and WasmJS.
5+
6+
## What is Koog?
7+
8+
Koog is JetBrains' open-source agentic framework that empowers developers to build AI agents using Kotlin. It provides:
9+
10+
- **Graph-based agent architecture**: Define agent behavior as a graph of nodes and edges with type-safe inputs and outputs,
11+
making complex workflows easier to understand and maintain
12+
- **Multi-platform support**: Deploy agents across JVM, Android, native iOS, JS, and WasmJS using Kotlin Multiplatform
13+
- **Fault tolerance**: Built-in retry mechanisms and agent state persistence for reliable execution, allowing to recover
14+
crashed agents even on another machine.
15+
- **Prompt DSL**: Clean, type-safe DSL for building LLM prompts and automatically managing conversation context
16+
- **Enterprise integrations**: Works seamlessly with Spring Boot, Ktor, and other JVM frameworks
17+
- **Advanced Observability**: Built-in integrations with enterprise observability tools like Langfuse and W&B Weave via OpenTelemetry
18+
- **A2A protocol support**: Built-in support for Agent-to-Agent communication via the A2A protocol
19+
20+
Learn more at [koog.ai](https://koog.ai/)
21+
22+
## Prerequisites
23+
24+
- JDK 17 or higher
25+
- Set `GOOGLE_API_KEY` environment variable (or configure other LLM providers in the code)
26+
27+
## Examples
28+
29+
### Simple Joke Agent: [simplejoke](./src/main/kotlin/ai/koog/example/simplejoke)
30+
31+
A basic example demonstrating message-based A2A communication without task workflows.
32+
33+
**What it demonstrates:**
34+
- Creating an `AgentExecutor` that wraps LLM calls using Koog's prompt DSL
35+
- Setting up an A2A server with an `AgentCard` that describes agent capabilities
36+
- Managing conversation context with message storage
37+
- Simple request-response pattern using `sendMessage()`
38+
39+
**Run:**
40+
```bash
41+
# Terminal 1: Start server (port 9998)
42+
./gradlew runExampleSimpleJokeServer
43+
44+
# Terminal 2: Run client
45+
./gradlew runExampleSimpleJokeClient
46+
```
47+
48+
### Advanced Joke Agent: [advancedjoke](./src/main/kotlin/ai/koog/example/advancedjoke)
49+
50+
A sophisticated example showcasing task-based A2A workflows using Koog's graph-based agent architecture.
51+
52+
**What it demonstrates:**
53+
- **Graph-based agent design**: Uses Koog's `GraphAIAgent` with nodes and edges to create a maintainable workflow
54+
- **Task lifecycle management**: Full A2A task states (Submitted → Working → InputRequired → Completed)
55+
- **Interactive clarification**: Agent can request additional information using the InputRequired state
56+
- **Structured LLM outputs**: Uses sealed interfaces with `nodeLLMRequestStructured` for type-safe agent decisions
57+
- **Artifact delivery**: Returns final results as A2A artifacts
58+
- **Streaming events**: Sends real-time task updates via `sendTaskEvent()`
59+
60+
**Run:**
61+
```bash
62+
# Terminal 1: Start server (port 9999)
63+
./gradlew runExampleAdvancedJokeServer
64+
65+
# Terminal 2: Run client
66+
./gradlew runExampleAdvancedJokeClient
67+
```
68+
69+
## Key Patterns & Koog Concepts
70+
71+
### A2A Communication Patterns
72+
73+
**Simple Agent:** `sendMessage()` → single response
74+
**Advanced Agent:** `sendMessageStreaming()` → Flow of events (Task, TaskStatusUpdateEvent, TaskArtifactUpdateEvent)
75+
76+
**Task States:** Submitted → Working → InputRequired (optional) → Completed
77+
78+
### Koog Framework Concepts Used
79+
80+
**AgentExecutor**: The entry point for A2A requests. Receives the request context and event processor for sending responses.
81+
82+
**GraphAIAgent**: Koog's graph-based agent implementation. Define your agent logic as nodes (processing steps) connected by edges (transitions).
83+
84+
**Prompt DSL**: Type-safe Kotlin DSL for building prompts:
85+
```kotlin
86+
prompt("joke-generation") {
87+
system { +"You are a helpful assistant" }
88+
user { +"Tell me a joke" }
89+
}
90+
```
91+
92+
**MultiLLMPromptExecutor**: Unified interface for executing prompts across different LLM providers (OpenAI, Anthropic, Google, etc.).
93+
94+
**nodeLLMRequestStructured**: Creates a graph node that calls the LLM and parses the response into a structured Kotlin data class using the `@LLMDescription` annotation.
95+
96+
**A2AAgentServer plugin**: Koog plugin that integrates A2A functionality into your GraphAIAgent, providing access to message storage, task storage, and event processors.
97+
98+
### Getting Started with Koog
99+
100+
To build your own A2A agent with Koog:
101+
102+
1. **Add Koog dependencies** (see [build.gradle.kts](./build.gradle.kts))
103+
2. **Create an AgentExecutor** to handle incoming A2A requests
104+
3. **Define an AgentCard** describing your agent's capabilities
105+
4. **Set up the A2A server** with HTTP transport
106+
5. **For simple agents**: Use prompt executor directly with message storage
107+
6. **For complex agents**: Use GraphAIAgent with the A2AAgentServer plugin
108+
109+
See the code comments in `JokeWriterAgentExecutor.kt` for detailed implementation guidance.
110+
111+
## Learn More
112+
113+
- [Koog GitHub Repository](https://github.com/JetBrains/koog)
114+
- [Koog Documentation](https://koog.ai/)

samples/java/koog/build.gradle.kts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
plugins {
2+
alias(libs.plugins.kotlin.jvm)
3+
alias(libs.plugins.kotlin.serialization)
4+
alias(libs.plugins.ktlint)
5+
}
6+
7+
dependencies {
8+
implementation(platform(libs.kotlin.bom))
9+
implementation(platform(libs.kotlinx.coroutines.bom))
10+
11+
implementation(libs.koog.agents)
12+
implementation(libs.koog.agents.features.a2a.server)
13+
implementation(libs.koog.agents.features.a2a.client)
14+
implementation(libs.koog.a2a.transport.server.jsonrpc.http)
15+
implementation(libs.koog.a2a.transport.client.jsonrpc.http)
16+
17+
implementation(libs.kotlinx.datetime)
18+
implementation(libs.kotlinx.coroutines.core)
19+
20+
implementation(libs.ktor.server.cio)
21+
22+
runtimeOnly(libs.logback.classic)
23+
}
24+
25+
fun registerRunExampleTask(
26+
name: String,
27+
mainClassName: String,
28+
) = tasks.register<JavaExec>(name) {
29+
doFirst {
30+
standardInput = System.`in`
31+
standardOutput = System.out
32+
}
33+
34+
mainClass.set(mainClassName)
35+
classpath = sourceSets["main"].runtimeClasspath
36+
}
37+
// Simple joke generation
38+
registerRunExampleTask("runExampleSimpleJokeServer", "ai.koog.example.simplejoke.ServerKt")
39+
registerRunExampleTask("runExampleSimpleJokeClient", "ai.koog.example.simplejoke.ClientKt")
40+
41+
// Advanced joke generation
42+
registerRunExampleTask("runExampleAdvancedJokeServer", "ai.koog.example.advancedjoke.ServerKt")
43+
registerRunExampleTask("runExampleAdvancedJokeClient", "ai.koog.example.advancedjoke.ClientKt")
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#Kotlin
2+
kotlin.code.style=official
3+
4+
#Gradle
5+
org.gradle.jvmargs=-Dfile.encoding=UTF-8
6+
org.gradle.parallel=true
7+
org.gradle.caching=true
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
[versions]
2+
kotlin = "2.2.20"
3+
kotlinx-coroutines = "1.10.2"
4+
kotlinx-datetime = "0.6.2"
5+
kotlinx-serialization = "1.8.1"
6+
ktor3 = "3.2.2"
7+
koog = "0.5.0"
8+
logback = "1.5.13"
9+
oshai-logging = "7.0.7"
10+
ktlint = "13.1.0"
11+
12+
[libraries]
13+
kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "kotlin" }
14+
kotlinx-coroutines-bom = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-bom" }
15+
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core" }
16+
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx-datetime" }
17+
ktor-server-cio = { module = "io.ktor:ktor-server-cio", version.ref = "ktor3" }
18+
koog-agents = { module = "ai.koog:koog-agents", version.ref = "koog" }
19+
koog-agents-features-a2a-server = { module = "ai.koog:agents-features-a2a-server", version.ref = "koog" }
20+
koog-agents-features-a2a-client = { module = "ai.koog:agents-features-a2a-client", version.ref = "koog" }
21+
koog-a2a-transport-server-jsonrpc-http = { module = "ai.koog:a2a-transport-server-jsonrpc-http", version.ref = "koog" }
22+
koog-a2a-transport-client-jsonrpc-http = { module = "ai.koog:a2a-transport-client-jsonrpc-http", version.ref = "koog" }
23+
logback-classic = { module = "ch.qos.logback:logback-classic", version.ref = "logback" }
24+
oshai-kotlin-logging = { module = "io.github.oshai:kotlin-logging", version.ref = "oshai-logging" }
25+
26+
[plugins]
27+
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
28+
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
29+
ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint" }
42.7 KB
Binary file not shown.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
distributionBase=GRADLE_USER_HOME
2+
distributionPath=wrapper/dists
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
4+
networkTimeout=10000
5+
validateDistributionUrl=true
6+
zipStoreBase=GRADLE_USER_HOME
7+
zipStorePath=wrapper/dists

0 commit comments

Comments
 (0)