Skip to content
Merged
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
26 changes: 25 additions & 1 deletion docs/runtime/event-loop.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Runtime Event Loop

<div class="language-support-tag">
<span class="lst-supported">Supported in ADK</span><span class="lst-python">Python v0.1.0</span><span class="lst-typescript">Typescript v0.2.0</span><span class="lst-go">Go v0.1.0</span><span class="lst-java">Java v0.1.0</span>
<span class="lst-supported">Supported in ADK</span><span class="lst-python">Python v0.1.0</span><span class="lst-typescript">Typescript v0.2.0</span><span class="lst-go">Go v0.1.0</span><span class="lst-java">Java v0.1.0</span><span class="lst-kotlin">Kotlin v0.1.0</span>
</div>

The ADK Runtime is the underlying engine that powers your agent application during user interactions. It's the system that takes your defined agents, tools, and callbacks and orchestrates their execution in response to user input, managing the flow of information, state changes, and interactions with external services like LLMs or storage.
Expand Down Expand Up @@ -179,6 +179,12 @@ The `Runner` acts as the central coordinator for a single user invocation. Its r
}
```

=== "Kotlin"

```kotlin
--8<-- "examples/kotlin/snippets/runtime/RunnerLoop.kt:conceptual_loop"
```

### Execution Logic's Role (Agent, Tool, Callback)

Your code within agents, tools, and callbacks is responsible for the actual computation and decision-making. Its interaction with the loop involves:
Expand Down Expand Up @@ -372,6 +378,12 @@ Your code within agents, tools, and callbacks is responsible for the actual comp
// If this subsequent code needs to yield another event, it would do so here.
```

=== "Kotlin"

```kotlin
--8<-- "examples/kotlin/snippets/runtime/RunnerLoop.kt:execution_logic"
```

This cooperative yield/pause/resume cycle between the `Runner` and your Execution Logic, mediated by `Event` objects, forms the core of the ADK Runtime.

## Key components of the Runtime
Expand Down Expand Up @@ -588,6 +600,12 @@ Understanding a few key aspects of how the ADK Runtime handles state, streaming,
// or emitting more events based on the now-updated `ctx.session().state()`.
```

=== "Kotlin"

```kotlin
--8<-- "examples/kotlin/snippets/runtime/RunnerLoop.kt:state_update_timing"
```

### "Dirty Reads" of Session State

* **Definition:** While commitment happens *after* the yield, code running *later within the same invocation*, but *before* the state-changing event is actually yielded and processed, **can often see the local, uncommitted changes**. This is sometimes called a "dirty read".
Expand Down Expand Up @@ -666,6 +684,12 @@ Understanding a few key aspects of how the ADK Runtime handles state, streaming,
// is yielded *after* this tool runs and is processed by the Runner.
```

=== "Kotlin"

```kotlin
--8<-- "examples/kotlin/snippets/runtime/RunnerLoop.kt:dirty_read"
```

* **Implications:**
* **Benefit:** Allows different parts of your logic within a single complex step (e.g., multiple callbacks or tool calls before the next LLM turn) to coordinate using state without waiting for a full yield/commit cycle.
* **Caveat:** Relying heavily on dirty reads for critical logic can be risky. If the invocation fails *before* the event carrying the `state_delta` is yielded and processed by the `Runner`, the uncommitted state change will be lost. For critical state transitions, ensure they are associated with an event that gets successfully processed.
Expand Down
2 changes: 1 addition & 1 deletion docs/runtime/index.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Agent Runtime

<div class="language-support-tag">
<span class="lst-supported">Supported in ADK</span><span class="lst-python">Python v0.1.0</span><span class="lst-typescript">TypeScript v0.2.0</span><span class="lst-go">Go v0.1.0</span><span class="lst-java">Java v0.1.0</span>
<span class="lst-supported">Supported in ADK</span><span class="lst-python">Python v0.1.0</span><span class="lst-typescript">TypeScript v0.2.0</span><span class="lst-go">Go v0.1.0</span><span class="lst-java">Java v0.1.0</span><span class="lst-kotlin">Kotlin v0.1.0</span>
</div>

ADK provides several ways to run and test your agents during development. Choose
Expand Down
50 changes: 33 additions & 17 deletions docs/runtime/resume.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Resume stopped agents

<div class="language-support-tag">
<span class="lst-supported">Supported in ADK</span><span class="lst-python">Python v1.14.0</span>
<span class="lst-supported">Supported in ADK</span><span class="lst-python">Python v1.14.0</span><span class="lst-kotlin">Kotlin v0.1.0</span>
</div>

An ADK agent's execution can be interrupted by various factors including
Expand All @@ -23,16 +23,24 @@ Enable the Resume function for an agent workflow by applying a Resumability
configuration to the App object of your ADK workflow, as shown in the following
code example:

```python
app = App(
name='my_resumable_agent',
root_agent=root_agent,
# Set the resumability config to enable resumability.
resumability_config=ResumabilityConfig(
is_resumable=True,
),
)
```
=== "Python"

```python
app = App(
name='my_resumable_agent',
root_agent=root_agent,
# Set the resumability config to enable resumability.
resumability_config=ResumabilityConfig(
is_resumable=True,
),
)
```

=== "Kotlin"

```kotlin
--8<-- "examples/kotlin/snippets/runtime/RunConfigExample.kt:resumability_config"
```

!!! warning "Caution: Long Running Functions, Confirmations, Authentication"
For agents that use
Expand Down Expand Up @@ -77,13 +85,21 @@ curl -X POST http://localhost:8000/run_sse \
You can also resume a workflow using the Runner object Run Async method, as
shown below:

```python
runner.run_async(user_id='u_123', session_id='s_abc',
invocation_id='invocation-123')
=== "Python"

# When new_message is set to a function response,
# we are trying to resume a long running function.
```
```python
runner.run_async(user_id='u_123', session_id='s_abc',
invocation_id='invocation-123')

# When new_message is set to a function response,
# we are trying to resume a long running function.
```

=== "Kotlin"

```kotlin
--8<-- "examples/kotlin/snippets/runtime/RunConfigExample.kt:resume_usage"
```

!!! info "Note"
Resuming a workflow from the ADK Web user interface or using the ADK
Expand Down
14 changes: 13 additions & 1 deletion docs/runtime/runconfig.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Runtime Configuration

<div class="language-support-tag">
<span class="lst-supported">Supported in ADK</span><span class="lst-python">Python v0.1.0</span><span class="lst-typescript">TypeScript v0.2.0</span><span class="lst-go">Go v0.1.0</span><span class="lst-java">Java v0.1.0</span>
<span class="lst-supported">Supported in ADK</span><span class="lst-python">Python v0.1.0</span><span class="lst-typescript">TypeScript v0.2.0</span><span class="lst-go">Go v0.1.0</span><span class="lst-java">Java v0.1.0</span><span class="lst-kotlin">Kotlin v0.1.0</span>
</div>

`RunConfig` controls how agents behave at runtime, including streaming mode,
Expand Down Expand Up @@ -58,6 +58,12 @@ to `runner.run_async()` or `runner.run_live()` to override default behavior.
.build();
```

=== "Kotlin"

```kotlin
--8<-- "examples/kotlin/snippets/runtime/RunConfigExample.kt:basic_usage"
```

## Manage sessions and context

<div class="language-support-tag">
Expand Down Expand Up @@ -151,6 +157,12 @@ execute function calls. CFC uses the Live API under the hood.
.build();
```

=== "Kotlin"

```kotlin
--8<-- "examples/kotlin/snippets/runtime/RunConfigExample.kt:streaming_config"
```

## Configure audio and speech

<div class="language-support-tag">
Expand Down
103 changes: 103 additions & 0 deletions examples/kotlin/snippets/runtime/RunConfigExample.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.adk.kt.examples.runtime

import com.google.adk.kt.agents.LlmAgent
import com.google.adk.kt.agents.ResumabilityConfig
import com.google.adk.kt.agents.RunConfig
import com.google.adk.kt.agents.StreamingMode
import com.google.adk.kt.annotations.ExperimentalResumabilityFeature
import com.google.adk.kt.models.Gemini
import com.google.adk.kt.runners.InMemoryRunner
import com.google.adk.kt.sessions.InMemorySessionService
import com.google.adk.kt.types.Content
import com.google.adk.kt.types.Role
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.runBlocking

// --8<-- [start:basic_usage]
val config =
RunConfig(
streamingMode = StreamingMode.SSE,
)

// Pass it to runner.runAsync
// runner.runAsync(..., runConfig = config)
// --8<-- [end:basic_usage]

// --8<-- [start:full_example]
fun runWithConfig(runner: InMemoryRunner) =
runBlocking {
val config =
RunConfig(
streamingMode = StreamingMode.SSE,
customMetadata = mapOf("priority" to "high"),
)

runner
.runAsync(
userId = "user123",
sessionId = "session456",
newMessage = Content.fromText(Role.USER, "Hello!"),
runConfig = config,
).collect { event ->
// handle events
}
}
// --8<-- [end:full_example]

// --8<-- [start:custom_metadata]
val metadataConfig =
RunConfig(
customMetadata = mapOf("user_tier" to "premium"),
)
// --8<-- [end:custom_metadata]

// --8<-- [start:streaming_config]
val streamingConfig =
RunConfig(
streamingMode = StreamingMode.SSE,
)
// --8<-- [end:streaming_config]

private val rootAgent =
LlmAgent(name = "my_agent", model = Gemini(name = "gemini-flash-latest"))

// --8<-- [start:resumability_config]
@OptIn(ExperimentalResumabilityFeature::class)
val runner =
InMemoryRunner(
agent = rootAgent,
appName = "my_resumable_agent",
sessionService = InMemorySessionService(),
resumabilityConfig = ResumabilityConfig(isResumable = true),
)
// --8<-- [end:resumability_config]

// --8<-- [start:resume_usage]
fun resumeAgent(runner: InMemoryRunner) =
runBlocking {
runner
.runAsync(
userId = "user123",
sessionId = "session456",
invocationId = "previous-invocation-id",
).collect { event ->
// resume execution from previous state
}
}
// --8<-- [end:resume_usage]
Loading
Loading