You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/src/content/docs/reference/ai.md
+228Lines changed: 228 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -365,6 +365,234 @@ Configure the built-in client with environment variables:
365
365
|`ConversationPersistence`| SPI for durable conversation storage (Redis, SQLite) |
366
366
|`RetryPolicy`| Exponential backoff with circuit-breaker semantics |
367
367
368
+
## Approval Gates
369
+
370
+
`@RequiresApproval` pauses tool execution until the client approves. The virtual thread parks cheaply on a `CompletableFuture` -- no carrier thread consumed.
371
+
372
+
```java
373
+
@AiTool(name="delete_account", description="Permanently delete a user account")
374
+
@RequiresApproval("This will permanently delete the account. Are you sure?")
Default timeout: 5 minutes. Configurable via `@RequiresApproval(timeoutSeconds = 120)`.
399
+
400
+
### How It Works
401
+
402
+
1.`AiStreamingSession.wrapApprovalGates()` wraps `@RequiresApproval` tools with `ApprovalGateExecutor`
403
+
2. When the LLM calls the tool, `ApprovalGateExecutor` parks the virtual thread on `CompletableFuture.get(timeout)`
404
+
3. The session emits `AiEvent.ApprovalRequired` to the client
405
+
4.`AiEndpointHandler` fast-paths `/__approval/` messages to the session's `ApprovalRegistry` (before prompt dispatch)
406
+
5.`ApprovalRegistry.tryResolve()` completes the future, unparking the virtual thread
407
+
6. On transport reconnect, a fallback scan across all active sessions ensures the approval reaches the parked thread
408
+
409
+
### ADK ToolConfirmation Bridge
410
+
411
+
When running on Google ADK, Atmosphere also calls `toolContext.requestConfirmation()` to give ADK native visibility into the approval pause. If ADK resolves a confirmation before Atmosphere (e.g., via its own UI), the ADK denial short-circuits without calling the executor. This creates a two-layer model: Atmosphere-level (cross-runtime) + ADK-native (runtime-specific).
The `AiCompactionStrategy` SPI controls how conversation history is compacted when it exceeds the configured limit. Unlike `MemoryStrategy` (which selects messages for the next request -- read path), compaction permanently reduces stored history (write path).
**`SlidingWindowCompaction`** (default) -- drops the oldest non-system messages until under the limit. System messages are always preserved.
429
+
430
+
**`SummarizingCompaction`** -- condenses old messages into a single system-role summary, preserving the most recent messages verbatim. The recent window size is configurable (default: 6).
431
+
432
+
```java
433
+
// Default: sliding window
434
+
var memory =newInMemoryConversationMemory(20);
435
+
436
+
// Custom: summarization with 8-message recent window
437
+
var memory =newInMemoryConversationMemory(20, newSummarizingCompaction(8));
438
+
```
439
+
440
+
### ADK Bridge
441
+
442
+
`AdkCompactionBridge.toAdkConfig()` maps Atmosphere compaction settings to ADK's `EventsCompactionConfig` for native compaction when using the ADK runtime.
443
+
444
+
## Artifact Persistence SPI
445
+
446
+
The `ArtifactStore` SPI provides binary artifact persistence across agent runs. Use cases include agent-generated reports, images, code files, and content shared between coordinated agents.
447
+
448
+
```java
449
+
publicinterfaceArtifactStore {
450
+
Artifactsave(Artifactartifact); // auto-versions
451
+
Optional<Artifact>load(Stringnamespace, StringartifactId); // latest version
Byte arrays are defensively copied on construction and on access -- callers cannot mutate persisted data.
475
+
476
+
### Implementations
477
+
478
+
-**`InMemoryArtifactStore`** -- default, for development and testing. Data does not survive JVM restart.
479
+
-**ADK bridge** -- `AdkArtifactBridge.toAdkService()` wraps an `ArtifactStore` as ADK's `BaseArtifactService`.
480
+
481
+
## Interceptor Disconnect Lifecycle
482
+
483
+
`AiInterceptor` includes an `onDisconnect` hook called **before** conversation memory is cleared. This enables fact extraction, summary persistence, and other cleanup that requires access to the conversation history.
`LongTermMemoryInterceptor.onDisconnect()` uses this to extract facts from the full conversation on session close via `OnSessionCloseStrategy`.
494
+
495
+
Execution order: `preProcess` runs FIFO, `postProcess` runs LIFO, `onDisconnect` runs FIFO. Exceptions in one interceptor do not prevent others from being called.
496
+
497
+
## AiEvent Model
498
+
499
+
The `AiEvent` sealed interface provides 15 structured event types emitted via `session.emit()`. All runtimes map their native events to this common model.
Add `atmosphere-ai-test` as a test dependency and extend the base class:
585
+
586
+
```xml
587
+
<dependency>
588
+
<groupId>org.atmosphere</groupId>
589
+
<artifactId>atmosphere-ai-test</artifactId>
590
+
<scope>test</scope>
591
+
</dependency>
592
+
```
593
+
594
+
The `RecordingSession` test double captures all events, text chunks, metadata, and errors for assertion. Currently enforced on: ADK, LangChain4j, Spring AI.
595
+
368
596
## Samples
369
597
370
598
-[Spring Boot AI Chat](../samples/spring-boot-ai-chat/) -- built-in client with Gemini/OpenAI/Ollama
0 commit comments