-
Notifications
You must be signed in to change notification settings - Fork 925
Kotlinsdk #316
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Kotlinsdk #316
Changes from 10 commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
6c2a7ef
feat: add AG-UI-4K Kotlin Multiplatform SDK
contextablemark 5f093ae
fix: iOS app crash due to missing CADisableMinimumFrameDurationOnPhone
contextablemark abadc34
fix: add missing gradle-wrapper.jar files and update gitignore pattern
contextablemark 86a5e7a
fix: resolve Android instrumented test timing issue in chatapp-java
contextablemark 8335f1a
Remove MIT license headers from Kotlin files
contextablemark cbcd8f1
feat: implement thinking events support for AG-UI protocol
contextablemark bef6fcc
feat: implement TEXT_MESSAGE_CHUNK, TOOL_CALL_CHUNK, and TOOL_CALL_RE…
contextablemark c0a714e
docs: add comprehensive Kotlin SDK documentation and clean up redunda…
contextablemark ecc023f
Merge branch 'ag-ui-protocol:main' into kotlinsdk
contextablemark bc22ef6
Merge branch 'ag-ui-protocol:main' into kotlinsdk
contextablemark 72753d3
Merge branch 'ag-ui-protocol:main' into kotlinsdk
contextablemark f82ba62
feat: add Kotlin SDK JVM tests to GitHub Actions CI
contextablemark e725910
feat: add workflow_dispatch to test.yml for manual workflow runs
contextablemark a01315a
feat: add --info flag to Kotlin tests for verbose output
contextablemark ff943fc
feat: add clean test results summary for Kotlin SDK
contextablemark be2e19c
fix: parse XML test results instead of HTML for accurate test counts
contextablemark ef3236a
fix: correct XML parsing for Kotlin test results
contextablemark 0a8d491
chore: remove workflow_dispatch from test.yml
contextablemark 2b4e433
Merge branch 'ag-ui-protocol:main' into kotlinsdk
contextablemark d647e2a
Merge branch 'ag-ui-protocol:main' into kotlinsdk
contextablemark 16bf7bd
Merge branch 'ag-ui-protocol:main' into kotlinsdk
contextablemark File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,272 @@ | ||
| --- | ||
| title: AgUiAgent | ||
| description: Stateless client for AG-UI protocol interactions | ||
| --- | ||
|
|
||
| # AgUiAgent | ||
|
|
||
| `AgUiAgent` is a stateless client implementation designed for cases where no ongoing context is needed or where the agent manages all state server-side. It provides a simple, efficient interface for interacting with AG-UI protocol agents. | ||
|
|
||
| ## Usage Scenarios | ||
|
|
||
| ### No Ongoing Context | ||
| Perfect for single interactions or independent queries: | ||
| ```kotlin | ||
| val agent = AgUiAgent("https://api.example.com/agent") { | ||
| bearerToken = "your-token" | ||
| } | ||
|
|
||
| // Each interaction is independent | ||
| agent.sendMessage("What's the weather?").collect { state -> | ||
| println(state.messages.last().content) | ||
| } | ||
| ``` | ||
|
|
||
| ### Agent-Managed State | ||
| Ideal when the agent handles conversation history server-side: | ||
| ```kotlin | ||
| val agent = AgUiAgent("https://api.example.com/agent") { | ||
| bearerToken = "your-token" | ||
| // Agent manages conversation context internally | ||
| } | ||
|
|
||
| // Agent remembers previous interactions server-side | ||
| agent.sendMessage("My name is Bob").collect { } | ||
| agent.sendMessage("What's my name?").collect { state -> | ||
| // Agent retrieves context from server-side storage | ||
| } | ||
| ``` | ||
|
|
||
| ## Configuration | ||
|
|
||
| ### Convenience Builders | ||
| The easiest way to create AgUiAgent instances: | ||
|
|
||
| ```kotlin | ||
| import com.agui.client.builders.* | ||
|
|
||
| // Quick bearer token setup | ||
| val agent = agentWithBearer("https://api.example.com/agent", "your-token") | ||
|
|
||
| // Quick API key setup | ||
| val agent = agentWithApiKey("https://api.example.com/agent", "your-api-key") | ||
|
|
||
| // Custom API key header | ||
| val agent = agentWithApiKey("https://api.example.com/agent", "your-key", "Authorization") | ||
|
|
||
| // Agent with tools | ||
| val agent = agentWithTools( | ||
| url = "https://api.example.com/agent", | ||
| toolRegistry = toolRegistry { | ||
| addTool(CalculatorToolExecutor()) | ||
| } | ||
| ) { | ||
| bearerToken = "your-token" | ||
| } | ||
|
|
||
| // Debug agent with logging | ||
| val agent = debugAgent("https://api.example.com/agent") { | ||
| bearerToken = "your-token" | ||
| } | ||
| ``` | ||
|
|
||
| ### Basic Setup | ||
| ```kotlin | ||
| val agent = AgUiAgent( | ||
| url = "https://api.example.com/agent" | ||
| ) { | ||
| // Authentication (choose one) | ||
| bearerToken = "your-bearer-token" | ||
| // OR | ||
| apiKey = "your-api-key" | ||
| // OR | ||
| basicAuth("username", "password") | ||
|
|
||
| // Optional system prompt | ||
| systemPrompt = "You are a helpful assistant" | ||
|
|
||
| // Optional user ID | ||
| userId = "user-123" | ||
| } | ||
| ``` | ||
|
|
||
| ### Advanced Configuration | ||
| ```kotlin | ||
| val agent = AgUiAgent("https://api.example.com/agent") { | ||
| bearerToken = "your-token" | ||
|
|
||
| // Custom headers | ||
| customHeaders = mapOf( | ||
| "X-App-Version" to "1.0.0", | ||
| "X-Client-Type" to "mobile" | ||
| ) | ||
|
|
||
| // Timeout settings | ||
| requestTimeout = 30.seconds | ||
| connectTimeout = 10.seconds | ||
|
|
||
| // Debug logging | ||
| enableLogging = true | ||
|
|
||
| // Custom user agent | ||
| userAgent = "MyApp/1.0" | ||
| } | ||
| ``` | ||
|
|
||
| ## Methods | ||
|
|
||
| ### sendMessage | ||
| Send a message and receive streaming responses: | ||
|
|
||
| ```kotlin | ||
| fun sendMessage( | ||
| message: String, | ||
| threadId: String = generateThreadId(), | ||
| state: JsonElement? = null, | ||
| includeSystemPrompt: Boolean = true | ||
| ): Flow<BaseEvent> | ||
| ``` | ||
|
|
||
| **Parameters:** | ||
| - `message`: The message content to send | ||
| - `threadId`: Thread ID for conversation (defaults to generated ID) | ||
| - `state`: Initial state for the agent (defaults to null) | ||
| - `includeSystemPrompt`: Whether to include the configured system prompt | ||
|
|
||
| **Returns:** `Flow<BaseEvent>` - Stream of protocol events | ||
|
|
||
| **Example:** | ||
| ```kotlin | ||
| agent.sendMessage("Calculate 15% tip on $50").collect { event -> | ||
| when (event) { | ||
| is TextMessageStartEvent -> println("Agent started responding") | ||
| is TextMessageContentEvent -> print(event.delta) | ||
| is TextMessageEndEvent -> println("\nAgent finished responding") | ||
| is ToolCallStartEvent -> println("Agent is using tool: ${event.toolCallName}") | ||
| is RunErrorEvent -> println("Error: ${event.message}") | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### close | ||
| Close the agent and release resources: | ||
|
|
||
| ```kotlin | ||
| fun close() | ||
| ``` | ||
|
|
||
| **Example:** | ||
| ```kotlin | ||
| class MyRepository { | ||
| private val agent = AgUiAgent("https://api.example.com/agent") { | ||
| bearerToken = "your-token" | ||
| } | ||
|
|
||
| fun cleanup() { | ||
| agent.close() | ||
| } | ||
| } | ||
|
|
||
| ## Error Handling | ||
|
|
||
| ### Connection Errors | ||
| ```kotlin | ||
| agent.sendMessage("Hello").collect { state -> | ||
| state.errors.forEach { error -> | ||
| when (error.type) { | ||
| ErrorType.NETWORK -> { | ||
| println("Network error: ${error.message}") | ||
| // Handle network issues | ||
| } | ||
| ErrorType.AUTHENTICATION -> { | ||
| println("Auth error: ${error.message}") | ||
| // Handle authentication issues | ||
| } | ||
| ErrorType.PROTOCOL -> { | ||
| println("Protocol error: ${error.message}") | ||
| // Handle protocol violations | ||
| } | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### Retry Logic | ||
| ```kotlin | ||
| // Built-in retry for transient failures | ||
| val agent = AgUiAgent("https://api.example.com/agent") { | ||
| bearerToken = "your-token" | ||
| maxRetries = 3 | ||
| retryDelay = 1.seconds | ||
| } | ||
| ``` | ||
|
|
||
| ## Thread Safety | ||
|
|
||
| `AgUiAgent` is thread-safe and can be used concurrently: | ||
|
|
||
| ```kotlin | ||
| val agent = AgUiAgent("https://api.example.com/agent") { | ||
| bearerToken = "your-token" | ||
| } | ||
|
|
||
| // Safe to call from multiple coroutines | ||
| launch { | ||
| agent.sendMessage("First message").collect { } | ||
| } | ||
|
|
||
| launch { | ||
| agent.sendMessage("Second message").collect { } | ||
| } | ||
| ``` | ||
|
|
||
| ## Best Practices | ||
|
|
||
| ### Resource Management | ||
| ```kotlin | ||
| // Agent automatically manages HTTP connections | ||
| // No explicit cleanup required, but you can control lifecycle: | ||
|
|
||
| class MyRepository { | ||
| private val agent = AgUiAgent(url) { /* config */ } | ||
|
|
||
| // Agent will be garbage collected when repository is | ||
| } | ||
| ``` | ||
|
|
||
| ### Performance Optimization | ||
| ```kotlin | ||
| // Reuse agent instances when possible | ||
| val agent = AgUiAgent(url) { bearerToken = token } | ||
|
|
||
| // Multiple interactions with same agent instance | ||
| repeat(10) { i -> | ||
| agent.sendMessage("Message $i").collect { } | ||
| } | ||
| ``` | ||
|
|
||
| ### Message Threading | ||
| ```kotlin | ||
| // Group related messages with threadId | ||
| val threadId = UUID.randomUUID().toString() | ||
|
|
||
| agent.sendMessage("Start conversation", threadId = threadId).collect { } | ||
| agent.sendMessage("Continue conversation", threadId = threadId).collect { } | ||
| ``` | ||
|
|
||
| ## Platform Considerations | ||
|
|
||
| ### Android | ||
| - Uses Ktor Android engine (OkHttp under the hood) | ||
| - Handles network state changes automatically | ||
| - Compatible with background processing restrictions | ||
|
|
||
| ### iOS | ||
| - Uses Ktor Darwin engine (NSURLSession under the hood) | ||
| - Respects iOS app lifecycle events | ||
| - Compatible with background app refresh | ||
|
|
||
| ### JVM | ||
| - Uses Ktor CIO engine for server applications | ||
| - Supports high-concurrency scenarios | ||
| - Compatible with Spring Boot and other frameworks |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.