diff --git a/.gitignore b/.gitignore index 71d3d04..c82c8bf 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,8 @@ out/ # Auto-generated Gradle daemon JVM criteria (machine-specific) gradle/gradle-daemon-jvm.properties + +# Internal scratch / tooling / working docs — kept local, not part of the SDK. +# (iOS→Android parity audit artifacts, multi-agent workflow scripts, implementation notes.) +/scripts/ +/docs/ diff --git a/CHANGELOG.md b/CHANGELOG.md index a0d63eb..028a3ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,18 @@ is pre-1.0, breaking changes bump the **minor** version. ## [Unreleased] +## [0.9.0] - 2026-06-30 + +Adds the `ai.poly:voice` WebRTC voice-calling SDK (first publish) alongside `ai.poly:messaging:0.9.0`. + +### Added +- **Voice calling (`ai.poly:voice`):** live, two-way WebRTC voice calls to a PolyAI agent — call + lifecycle (`CallState`), mute, accessory-aware audio-output routing with mid-call switching + (speaker / earpiece / wired / Bluetooth), audio-focus interruption handling, signaling reconnect, + and a foreground-service recipe for background calls. Separate artifact; reuses the messaging + `Configuration`. See [`polyvoice/README.md`](polyvoice/README.md). +- **`PolyError.Voice`** error cases (e.g. `Disconnected`, `Interrupted`) on the shared error type. + ## [0.8.0] - 2026-06-16 First public release on Maven Central (`ai.poly:messaging:0.8.0`). diff --git a/README.md b/README.md index a7afc0e..2f68e07 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,12 @@ ![License](https://img.shields.io/badge/License-Apache%202.0-blue) [![Develop with Claude Code](https://img.shields.io/badge/Develop%20with-Claude%20Code-d97757)](https://claude.ai/download) -Add AI-powered chat to your Android app. The SDK is **headless** — it handles token auth, -the WebSocket, streaming, reconnection, delivery tracking, and live-agent handoff. You bring the UI. +Add AI-powered **chat** and **voice** to your Android app. The SDK is **headless** — it handles token +auth, the WebSocket, streaming, reconnection, delivery tracking, and live-agent handoff. You bring the UI. - **[Quick start](#quick-start)** — paste an `Activity`/`@Composable` and you have chat. - **[Integration guide](#integration-guide)** — observe one object, `ChatSession`. +- **[Voice calling](#voice-calling-aipolyvoice)** — live WebRTC voice calls with `ai.poly:voice`. Reference: [Configuration](#configuration) · [Error handling](#error-handling) · [How it works](#how-it-works) · [Raw transport](#advanced-raw-transport) · [Example apps](#example-apps). @@ -31,6 +32,7 @@ Reference: [Configuration](#configuration) · [Error handling](#error-handling) | 📎 | Attachments | Images, link cards, CTA phone buttons | | 📡 | Delivery tracking | Optimistic → confirmed → failed, per message | | 🔧 | Escape hatch | Raw WebSocket transport | +| 📞 | Voice calling | Live two-way WebRTC calls + audio-output routing (`ai.poly:voice`) | ## Install @@ -53,7 +55,7 @@ Then declare the dependency — the three forms below are equivalent (same artif ```kotlin // build.gradle.kts dependencies { - implementation("ai.poly:messaging:0.8.0") + implementation("ai.poly:messaging:0.9.0") } ``` @@ -62,7 +64,7 @@ dependencies { ```groovy // build.gradle dependencies { - implementation 'ai.poly:messaging:0.8.0' + implementation 'ai.poly:messaging:0.9.0' } ``` @@ -70,7 +72,7 @@ dependencies { ```toml [versions] -polyMessaging = "0.8.0" +polyMessaging = "0.9.0" [libraries] poly-messaging = { module = "ai.poly:messaging", version.ref = "polyMessaging" } @@ -117,7 +119,7 @@ class HelloApplication : Application() { > top of `MainActivity.onCreate()` (simplest; it re-runs on activity recreation, so prefer > `Application.onCreate()` for real apps). -> **Quick-start dependencies.** Beyond the SDK itself (`implementation("ai.poly:messaging:0.8.0")`), the +> **Quick-start dependencies.** Beyond the SDK itself (`implementation("ai.poly:messaging:0.9.0")`), the > only line a Compose app must add for the snippet below is **lifecycle-runtime-compose** (for > `collectAsStateWithLifecycle`): > @@ -388,7 +390,7 @@ Full details in [Streaming](#streaming). > **`chat()` vs `start()`** — `chat()` resumes the previous conversation if one exists (within the ~10-minute server WebSocket idle window), else starts fresh; `start()` always starts fresh. `PolyMessaging.hasResumableSession()` tells you which to offer. > **Lifecycle:** initialize once at app launch; keep one `ChatSession` per chat surface (a `remember { }` in Compose, a stored property in Views); call `session.close()` when the surface is dismissed to release its observers, and `session.client.shutdown()` when you're done with the client entirely. -*Example app: [`examples/compose/01-hello`](examples/compose/01-hello) and [`examples/views/01-hello`](examples/views/01-hello) are this quick start, runnable as-is. The full ladder — 01-Hello, 02-Standard, 03-RichContent, 04-Resilience, 05-Handoff, 06-FullReference, 07-Playground — is available across both UI toolkits; see [Example apps](#example-apps).* +*Example app: [`examples/chat/compose/01-hello`](examples/chat/compose/01-hello) and [`examples/chat/views/01-hello`](examples/chat/views/01-hello) are this quick start, runnable as-is. The full ladder — 01-Hello, 02-Standard, 03-RichContent, 04-Resilience, 05-Handoff, 06-FullReference, 07-Playground — is available across both UI toolkits; see [Example apps](#example-apps).* --- @@ -577,7 +579,7 @@ fun systemLabel(event: SystemEvent): String = when (event) { That's the foundation. The rest of this section is just *which field or case* each feature uses. -*Example app:* the full render loop is the heart of [`01-Hello`](examples/compose/01-hello) (Compose `MessageRow`) and its Views twin [`01-Hello`](examples/views/01-hello) — both runnable. [`02-Standard`](examples/compose/02-standard) / [`02-Standard`](examples/views/02-standard) (also runnable) layer delivery state, suggestions, typing, and the system pills on top of the same `when`. +*Example app:* the full render loop is the heart of [`01-Hello`](examples/chat/compose/01-hello) (Compose `MessageRow`) and its Views twin [`01-Hello`](examples/chat/views/01-hello) — both runnable. [`02-Standard`](examples/chat/compose/02-standard) / [`02-Standard`](examples/chat/views/02-standard) (also runnable) layer delivery state, suggestions, typing, and the system pills on top of the same `when`. ## Adding each feature @@ -630,7 +632,7 @@ val alt = PolyMessaging.chat(streamingEnabled = false) // this surface only Either way, your render code — the `when` over `messages` from [the core pattern](#the-core-pattern-render-messages-yourself) — doesn't change. -*Example app:* [01-Hello (Compose)](examples/compose/01-hello/) · [01-Hello (Views)](examples/views/01-hello/) — both stream agent replies by default (just `PolyMessaging.chat()` with the default config). For a live toggle to compare with `streamingEnabled = false` side by side, see [07-Playground](examples/compose/07-playground/). +*Example app:* [01-Hello (Compose)](examples/chat/compose/01-hello/) · [01-Hello (Views)](examples/chat/views/01-hello/) — both stream agent replies by default (just `PolyMessaging.chat()` with the default config). For a live toggle to compare with `streamingEnabled = false` side by side, see [07-Playground](examples/chat/compose/07-playground/). ### Connection & reconnect **Data:** `session.connection` — show a banner only while `ConnectionStatus.Reconnecting` (drops go `Open → Reconnecting(n) → Open`, no `Closed` flash). `session.failureReason` is terminal — recover with `session.client.startNewSession()` (or a fresh `chat()`/`start()`); `resume()` does **not** reconnect. Use `isConnected` / `isReconnecting` / `isFailed` (full list under [Connection states](#connection-states)). @@ -693,7 +695,7 @@ override fun onCreate(savedInstanceState: Bundle?) { } } ``` -*Example app:* [02-Standard (Compose)](examples/compose/02-standard/) · [02-Standard (Views)](examples/views/02-standard/) · [04-Resilience](examples/compose/04-resilience/). +*Example app:* [02-Standard (Compose)](examples/chat/compose/02-standard/) · [02-Standard (Views)](examples/chat/views/02-standard/) · [04-Resilience](examples/chat/compose/04-resilience/). **Device offline is a separate signal.** `session.connection` tracks the *socket*, not whether the *phone* lost Wi-Fi. For that, register a `ConnectivityManager.NetworkCallback` and show a distinct "You're offline" bar — the two can stack: offline (device) on top, reconnecting (socket) below. See 04-Resilience. @@ -752,7 +754,7 @@ override fun onCreate(savedInstanceState: Bundle?) { } } ``` -*Example app:* [04-Resilience (Compose)](examples/compose/04-resilience/) · [04-Resilience (Views)](examples/views/04-resilience/) (full-screen terminal-error screen) · [06-FullReference (Compose)](examples/compose/06-fullreference/) · [06-FullReference (Views)](examples/views/06-fullreference/) (in a screen state machine). +*Example app:* [04-Resilience (Compose)](examples/chat/compose/04-resilience/) · [04-Resilience (Views)](examples/chat/views/04-resilience/) (full-screen terminal-error screen) · [06-FullReference (Compose)](examples/chat/compose/06-fullreference/) · [06-FullReference (Views)](examples/chat/views/06-fullreference/) (in a screen state machine). ### Loading & empty states **Data:** `isReady` (false until connected) + `messages.isEmpty()`. Show a spinner until the first messages arrive, then swap to the transcript. @@ -795,7 +797,7 @@ override fun onCreate(savedInstanceState: Bundle?) { } } ``` -*Example app:* [04-Resilience (Compose)](examples/compose/04-resilience/) · [04-Resilience (Views)](examples/views/04-resilience/). +*Example app:* [04-Resilience (Compose)](examples/chat/compose/04-resilience/) · [04-Resilience (Views)](examples/chat/views/04-resilience/). ### Delivery state & retry **Data:** `UserMessage.delivery` is a `Delivery` enum (`PENDING` → `SENT` → `FAILED`). Restyle the bubble per state; on `FAILED`, drop the draft with `removeMessage(draftId)` then re-`send` so you don't duplicate. Tip: delay the "Sending…" label ~500 ms so fast confirmations don't flash it. @@ -866,7 +868,7 @@ private fun retry(message: UserMessage) { lifecycleScope.launch { runCatching { session.send(message.text) } } } ``` -*Example app:* [02-Standard (Compose)](examples/compose/02-standard/) · [02-Standard (Views)](examples/views/02-standard/). +*Example app:* [02-Standard (Compose)](examples/chat/compose/02-standard/) · [02-Standard (Views)](examples/chat/views/02-standard/). ### Typing **Data:** `isAgentTyping` (+ `agentAvatarUrl`) shows the dots; call `session.sendTyping()` on every keystroke to tell the agent — throttled, auto-STOPPED after idle, and `isAgentTyping` clears on the next agent message. @@ -919,7 +921,7 @@ override fun onCreate(savedInstanceState: Bundle?) { } } ``` -*Example app:* [02-Standard (Compose)](examples/compose/02-standard/) · [02-Standard (Views)](examples/views/02-standard/). +*Example app:* [02-Standard (Compose)](examples/chat/compose/02-standard/) · [02-Standard (Views)](examples/chat/views/02-standard/). ### Suggestions (quick replies) **Data:** `AgentMessage.suggestions` (`List`, agent-only). Render under the last message; on tap, `clearSuggestions(messageId)` then `send(suggestion.messageText)`. Only the latest agent message shows pills, and they scroll away with history. @@ -1001,7 +1003,7 @@ val onSuggestionTap: (UUID, ResponseSuggestion) -> Unit = { messageId, suggestio > `ChatMessage.suggestions` is exposed on the base `ChatMessage` (empty for user/system rows), so the "last message has pills" check works without first matching `ChatMessage.Agent`. -*Example app:* [02-Standard (Compose)](examples/compose/02-standard/) · [02-Standard (Views)](examples/views/02-standard/). +*Example app:* [02-Standard (Compose)](examples/chat/compose/02-standard/) · [02-Standard (Views)](examples/chat/views/02-standard/). ### Rich text & links **Data:** `AgentMessage.text` is the agent's text, delivered **raw**. It's usually Markdown — `**bold**`, `*italic*`, `` `code` ``, `[links](https://…)` — but it can also contain a small subset of **HTML** (most commonly `
` line breaks), because the backend serves the same message to the web chat widget, which renders it as HTML. The SDK never strips or converts it — you render it. Render with [Markwon](https://github.com/noties/Markwon) (Views) or `HtmlCompat.fromHtml` for the HTML subset; on Compose, hand the same Markwon-produced `Spanned` to an `AndroidView(TextView)`, or annotate the string yourself. @@ -1050,7 +1052,7 @@ class MessageHolder(private val b: ItemMessageBinding) : RecyclerView.ViewHolder > **Handling HTML (`
` & friends).** Because the same agent text is rendered by the web chat widget as HTML, a reply can arrive with literal tags — e.g. `…how can I help?

Pick an option:`. Markdown parsers don't convert HTML, so those tags would render raw. The advanced examples (`03-RichContent`, `06-FullReference`, and the rest of `03`–`07`) run a small `normalizeAgentHtml` pass first that mirrors the web widget's DOMPurify allow-list — `a, br, b, i, em, strong, p, ul, ol, li, code` — mapping `
`→newline, ``/``→`**`, ``/``→`*`, ``→`[text](url)`, lists→bullets, decoding HTML entities, and dropping any other tag (`HtmlCompat.fromHtml` is the quick alternative for the HTML subset alone). The minimal 01-Hello / 02-Standard examples deliberately skip it (they render `m.text` plainly to stay minimal), so they show `
` raw — port `normalizeAgentHtml` if your agent emits HTML. -*Example app:* [03-RichContent (Compose)](examples/compose/03-richcontent/) · [03-RichContent (Views)](examples/views/03-richcontent/). Note the examples stay dependency-free instead of pulling in Markwon: Compose hand-rolls the same normalize-then-parse pass into an `AnnotatedString` (`components/RichText.kt`), and Views builds the equivalent `Spanned` manually (`RichTextSpans.kt`) — Markwon (above) is the drop-in production alternative. +*Example app:* [03-RichContent (Compose)](examples/chat/compose/03-richcontent/) · [03-RichContent (Views)](examples/chat/views/03-richcontent/). Note the examples stay dependency-free instead of pulling in Markwon: Compose hand-rolls the same normalize-then-parse pass into an `AnnotatedString` (`components/RichText.kt`), and Views builds the equivalent `Spanned` manually (`RichTextSpans.kt`) — Markwon (above) is the drop-in production alternative. ### Attachments, link cards & call buttons An agent message can carry images, link preview-cards, and `tel:` call buttons — all on `AgentMessage`. Filter `attachments` by `contentType` and render each kind; drop `UNKNOWN` (it exists for forward-compat). @@ -1158,7 +1160,7 @@ fun bind(message: ChatMessage, context: Context) { Each link card opens `contentUrl` on tap; call buttons dial a sanitized `tel:` (digits + leading `+`). `ACTION_DIAL` opens the dialer pre-filled (no `CALL_PHONE` permission needed); use `ACTION_CALL` only if you want to place the call directly. -*Example app:* [03-RichContent (Compose)](examples/compose/03-richcontent/) · [03-RichContent (Views)](examples/views/03-richcontent/). +*Example app:* [03-RichContent (Compose)](examples/chat/compose/03-richcontent/) · [03-RichContent (Views)](examples/chat/views/03-richcontent/). ### Live agent handoff **No special listening** — handoff is already in `messages`: progress as `ChatMessage.System` events (your `systemLabel(event)` from the core pattern renders them), live-agent replies as `ChatMessage.Agent` with `agentKind == AgentKind.LIVE`, live typing via `isAgentTyping`. Just tint the live agent so the user can tell a human took over. @@ -1206,7 +1208,7 @@ fun bindAgent(m: AgentMessage) { `SystemEvent.LiveAgentLeft` is terminal (the SDK flips `hasEnded`). To deep-link a handoff route, observe [`session.client.events`](#side-effects-clientevents) for `MessagingEvent.ClientHandoffRequired` / `LiveAgentJoined`. -*Example app:* [05-Handoff (Compose)](examples/compose/05-handoff/) · [05-Handoff (Views)](examples/views/05-handoff/). +*Example app:* [05-Handoff (Compose)](examples/chat/compose/05-handoff/) · [05-Handoff (Views)](examples/chat/views/05-handoff/). ### Message timestamps **Data:** `ChatMessage.timestamp` (epoch millis, UTC; also on each `UserMessage` / `AgentMessage` / `SystemMessage`). Format with `DateUtils` or a `java.time` `DateTimeFormatter`. @@ -1244,7 +1246,7 @@ fun bind(message: ChatMessage) { For a date-grouped separator row (when the gap between consecutive messages crosses a date boundary, insert a row with the date), see the playground. -*Example app:* [07-Playground (Compose)](examples/compose/07-playground/) · [07-Playground (Views)](examples/views/07-playground/). +*Example app:* [07-Playground (Compose)](examples/chat/compose/07-playground/) · [07-Playground (Views)](examples/chat/views/07-playground/). ### Avatars & keyboard **Data:** `agentAvatarUrl` (latest, on the session) and `AgentMessage.avatarUrl` (per-message, `URI?`); load with Coil. Keyboard handling is yours — `Modifier.imePadding()` / `WindowInsets.ime` (Compose) or `adjustResize` + `WindowInsetsCompat` (Views). @@ -1310,7 +1312,7 @@ ViewCompat.setOnApplyWindowInsetsListener(binding.content) { v, insets -> The session-level `agentAvatarUrl` (a `StateFlow`) is the latest avatar — handy for a header or the typing-indicator row; `AgentMessage.avatarUrl` is the per-bubble one shown above. -*Example app:* [05-Handoff (Compose)](examples/compose/05-handoff/) · [05-Handoff (Views)](examples/views/05-handoff/). +*Example app:* [05-Handoff (Compose)](examples/chat/compose/05-handoff/) · [05-Handoff (Views)](examples/chat/views/05-handoff/). ## Side effects: `client.events` @@ -1385,7 +1387,7 @@ class ChatActivity : ComponentActivity() { > Tie the collection to the view lifecycle (Compose `LaunchedEffect`, or Views `repeatOnLifecycle`) and subscribe **before** sending — `events` is lazy-start. -*Example app:* the **05-Handoff** app subscribes to `session.client.events` exactly like this — Compose `ChatScreen.kt` collects it in a `LaunchedEffect`, Views `ChatActivity.kt` in a `lifecycleScope.launch` collector — handling `LiveAgentJoined` / `ClientHandoffRequired` side effects (title updates, deep links). [06-FullReference](examples/compose/06-fullreference/) and [07-Playground](examples/compose/07-playground/) also tap `client.events` (`NewMessageNotifier`, `DevDiagnostics`). +*Example app:* the **05-Handoff** app subscribes to `session.client.events` exactly like this — Compose `ChatScreen.kt` collects it in a `LaunchedEffect`, Views `ChatActivity.kt` in a `lifecycleScope.launch` collector — handling `LiveAgentJoined` / `ClientHandoffRequired` side effects (title updates, deep links). [06-FullReference](examples/chat/compose/06-fullreference/) and [07-Playground](examples/chat/compose/07-playground/) also tap `client.events` (`NewMessageNotifier`, `DevDiagnostics`). ### In-app new-message alerts (local-only workaround) @@ -1777,23 +1779,86 @@ lifecycleScope.launch { > `sendRaw` bypasses delivery tracking, retry, and `local_id` correlation — no `MessagePending` / `MessageConfirmed`. Use it only when the managed `session.client.send(...)` path doesn't fit. +## Voice calling (`ai.poly:voice`) + +Live, two-way WebRTC voice calls to a PolyAI agent ship in a **separate** artifact so chat-only apps +stay lean (the call path pulls in the native libwebrtc audio engine). Add it alongside the messaging +SDK — it reuses the same `Configuration`: + +```kotlin +// build.gradle.kts +dependencies { + implementation("ai.poly:messaging:0.9.0") + implementation("ai.poly:voice:0.9.0") +} +``` + +```kotlin +import ai.poly.voice.PolyVoice + +val call = PolyVoice.call( + context, + Configuration(apiKey = "YOUR_API_KEY"), // connector token (X-Token) + VoiceOptions(webrtcToken = "YOUR_WEBRTC_TOKEN"), // WebRTC gateway token — distinct, also required +) + +// Observe the lifecycle: Idle → Connecting → Connected → Ended / Failed. +lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + call.state.collect { state -> render(state) } // state.error is a PolyError.Voice on Failed + } +} + +lifecycleScope.launch { call.start() } // after RECORD_AUDIO is granted +call.setMuted(true) // in-call controls +call.end() +``` + +`CallState`, `PolyError.Voice`, `Configuration`, and `Environment` are the same types from +`ai.poly:messaging` — no new vocabulary. A call needs **two credentials, both required and distinct**, +from [Agent Studio](https://studio.poly.ai) › Connector Settings: the **API key** (`Configuration.apiKey`, +authenticates the connector) and the **WebRTC token** (`VoiceOptions.webrtcToken`, authenticates the media +gateway). It also needs the **`RECORD_AUDIO`** runtime permission — the SDK declares it; you request the +grant before `start()`. + +📖 **Full voice guide → [`polyvoice/README.md`](polyvoice/README.md)** — permissions, audio-output routing +(speaker / earpiece / headset / Bluetooth), interruptions, background calls (foreground service), and R8. +Runnable demos: [`examples/voice/compose`](examples/voice/compose/) · +[`examples/voice/views`](examples/voice/views/). + ## Dev tools (QA) For internal builds, `DevSettings` is a `SharedPreferences`-backed runtime `Configuration` builder — flip environment, streaming, logging, and other knobs (each exposed as a `StateFlow`, and assembled via `buildConfiguration()`) without rebuilding. The **07-Playground** example pairs it with an on-screen diagnostics strip and event log (`MessagingEvent.debugSummary` / `debugDetail`), plus the [raw transport](#advanced-raw-transport) tap for protocol-level pokes. These are for development/QA — they bake in no credentials and aren't needed in production. ## Example apps -A 7-rung ladder, mirrored across **Jetpack Compose** and **Android Views** — open a module in Android Studio, set your `apiKey`, and Run. Each level builds on the previous one; see its README for what's new. +Examples live under [`examples/`](examples/), split by product — **[`chat/`](examples/chat/)** +(`ai.poly:messaging`) and **[`voice/`](examples/voice/)** (`ai.poly:voice`) — each mirrored across +**Jetpack Compose** and **Android Views**. Open a module in Android Studio, set your `apiKey`, and Run. + +### Chat (`examples/chat`) + +A 7-rung ladder — each level builds on the previous one; see its README for what's new. | Level | What it adds | Compose · Views | |---|---|---| -| **01 Hello** | initialize, render, send | [Compose](examples/compose/01-hello/) · [Views](examples/views/01-hello/) | -| **02 Standard** | typing, suggestions, delivery, reconnect, end + start-new | [Compose](examples/compose/02-standard/) · [Views](examples/views/02-standard/) | -| **03 Rich Content** | attachments, link cards, `tel:` actions, Markdown | [Compose](examples/compose/03-richcontent/) · [Views](examples/views/03-richcontent/) | -| **04 Resilience** | offline banner, loading skeleton, terminal error + retry | [Compose](examples/compose/04-resilience/) · [Views](examples/views/04-resilience/) | -| **05 Handoff** | full live-agent ladder | [Compose](examples/compose/05-handoff/) · [Views](examples/views/05-handoff/) | -| **06 Full reference** | production resume + start-new flows | [Compose](examples/compose/06-fullreference/) · [Views](examples/views/06-fullreference/) | -| **07 Playground** | diagnostics, runtime config, streaming toggle | [Compose](examples/compose/07-playground/) · [Views](examples/views/07-playground/) | +| **01 Hello** | initialize, render, send | [Compose](examples/chat/compose/01-hello/) · [Views](examples/chat/views/01-hello/) | +| **02 Standard** | typing, suggestions, delivery, reconnect, end + start-new | [Compose](examples/chat/compose/02-standard/) · [Views](examples/chat/views/02-standard/) | +| **03 Rich Content** | attachments, link cards, `tel:` actions, Markdown | [Compose](examples/chat/compose/03-richcontent/) · [Views](examples/chat/views/03-richcontent/) | +| **04 Resilience** | offline banner, loading skeleton, terminal error + retry | [Compose](examples/chat/compose/04-resilience/) · [Views](examples/chat/views/04-resilience/) | +| **05 Handoff** | full live-agent ladder | [Compose](examples/chat/compose/05-handoff/) · [Views](examples/chat/views/05-handoff/) | +| **06 Full reference** | production resume + start-new flows | [Compose](examples/chat/compose/06-fullreference/) · [Views](examples/chat/views/06-fullreference/) | +| **07 Playground** | diagnostics, runtime config, streaming toggle | [Compose](examples/chat/compose/07-playground/) · [Views](examples/chat/views/07-playground/) | + +### Voice (`examples/voice`) + +A one-screen **tap-to-call** demo on `ai.poly:voice` — build a `VoiceCall`, request the mic, start / +mute / end, and switch the audio output (speaker / earpiece / headset / Bluetooth) mid-call. Set your +connector token + WebRTC token in the `PolyVoice.call(...)` block. See [Voice calling](#voice-calling-aipolyvoice). + +| Demo | What it shows | Compose · Views | +|---|---|---| +| **Tap to call** | `PolyVoice.call`, `CallState`, mic permission, mute/end, audio-output picker | [Compose](examples/voice/compose/) · [Views](examples/voice/views/) | ## Requirements diff --git a/build.gradle.kts b/build.gradle.kts index d6b743b..738bd3d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -13,9 +13,11 @@ plugins { alias(libs.plugins.bcv) } -// binary-compatibility-validator: only the published SDK has a tracked ABI; ignore samples/tests. +// binary-compatibility-validator: only the published SDKs have a tracked ABI; ignore samples/tests. apiValidation { - // Only :polymessaging has a tracked public ABI; ignore the example apps + container projects. - ignoredProjects.addAll(subprojects.map { it.name }.filter { it != "polymessaging" }) + // The published SDKs (:polymessaging, :polyvoice) have a tracked public ABI; ignore the + // example apps + container projects. + val tracked = setOf("polymessaging", "polyvoice") + ignoredProjects.addAll(subprojects.map { it.name }.filter { it !in tracked }) } diff --git a/examples/compose/01-hello/README.md b/examples/chat/compose/01-hello/README.md similarity index 92% rename from examples/compose/01-hello/README.md rename to examples/chat/compose/01-hello/README.md index ad7dea5..d1c3bac 100644 --- a/examples/compose/01-hello/README.md +++ b/examples/chat/compose/01-hello/README.md @@ -26,7 +26,7 @@ Set your API key in `HelloApplication.kt` (currently `"YOUR_API_KEY"`); the comm - Auto-scroll as the agent's reply streams in - Send with `session.send(text)` from a coroutine (`scope.launch { runCatching { session.send(text) } }`) -The SDK invariants behind each pattern are in the root README's [Integration guide](../../../README.md#integration-guide); this example shows them as one concrete file. +The SDK invariants behind each pattern are in the root README's [Integration guide](../../../../README.md#integration-guide); this example shows them as one concrete file. ## How it works @@ -66,7 +66,7 @@ After this, `PolyMessaging.chat()` works from any `Activity` / `@Composable`. **Under the hood:** `initialize` just stashes your config (API key + environment) process-wide — no network happens yet. The work starts when you call `chat()`. -*See [Quick start](../../../README.md#quick-start).* +*See [Quick start](../../../../README.md#quick-start).* ### Get a session and render messages — `MainActivity.kt` @@ -101,11 +101,11 @@ private fun ChatScreen() { `remember { … }` keeps **one** session per composition lifecycle. `session.messages` is a `StateFlow`, so `collectAsStateWithLifecycle()` re-renders any read of `messages` when the SDK updates the transcript. -**Streaming is on by default** — `Configuration.streamingEnabled` defaults to `true`, so agent replies grow token-by-token (ChatGPT-style). To switch to complete-message bubbles instead, pass `PolyMessaging.chat(streamingEnabled = false)`. See the root README's [Streaming](../../../README.md#streaming) section. +**Streaming is on by default** — `Configuration.streamingEnabled` defaults to `true`, so agent replies grow token-by-token (ChatGPT-style). To switch to complete-message bubbles instead, pass `PolyMessaging.chat(streamingEnabled = false)`. See the root README's [Streaming](../../../../README.md#streaming) section. **Under the hood:** `chat()` runs the whole REST + WebSocket handshake, agent-join, and resume-or-create for you; `isReady` flips true once it's connected. `messages` is the SDK-maintained transcript (`User` / `Agent` / `System`) that re-emits on every change, so your list just re-renders. -*See [Integration guide › The core pattern](../../../README.md#the-core-pattern-render-messages-yourself).* +*See [Integration guide › The core pattern](../../../../README.md#the-core-pattern-render-messages-yourself).* ### Render each message — `MainActivity.kt` @@ -134,7 +134,7 @@ A user bubble is drawn faded while `delivery == Delivery.PENDING`, then settles **Under the hood:** with `streamingEnabled = true` (the default), `ChatSession` extends the last `Agent` message's `text` on every chunk and re-emits `messages`. The `StateFlow` collection recomposes `MessageRow` and the text grows as the reply streams. -*See [Integration guide › Streaming](../../../README.md#streaming).* +*See [Integration guide › Streaming](../../../../README.md#streaming).* ### Scroll as the agent types — `MainActivity.kt` @@ -165,7 +165,7 @@ Streaming grows the last agent message's `text` in place — `messages.size` doe **Under the hood:** with `streamingEnabled = true` (the default), `ChatSession` extends the last `Agent` message's `text` on every chunk and re-emits `messages`. The `StateFlow` collection recomposes, the `LaunchedEffect` keys change, and the scroll tracks the reply as it grows. -*See [Integration guide › Streaming](../../../README.md#streaming).* +*See [Integration guide › Streaming](../../../../README.md#streaming).* ### Send a message — `MainActivity.kt` @@ -202,7 +202,7 @@ Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { **Under the hood:** `send(text)` is optimistic — the bubble appears in `messages` immediately while the SDK manages delivery and the server echo behind the scenes. -*See [Integration guide › The core pattern](../../../README.md#the-core-pattern-render-messages-yourself).* +*See [Integration guide › The core pattern](../../../../README.md#the-core-pattern-render-messages-yourself).* ### Keyboard & insets — `MainActivity.kt` @@ -225,7 +225,7 @@ Scaffold( `WindowInsets.ime` follows the keyboard, `navigationBars` keeps the composer off the gesture bar, and `union` takes the larger of the two so the field never jumps. -*See [Integration guide › Avatars & keyboard](../../../README.md#avatars--keyboard).* +*See [Integration guide › Avatars & keyboard](../../../../README.md#avatars--keyboard).* ## What this example skips @@ -234,10 +234,10 @@ Scaffold( - offline detection, full-screen terminal error → 04-Resilience (see [`../04-resilience/`](../04-resilience/)) - live agent handoff → 05-Handoff (see [`../05-handoff/`](../05-handoff/)) -It also doesn't surface a **terminal-error dialog** for a bad API key — `session.failureReason` (and `session.client.resume()` for retry) is wired up in [`../02-standard/`](../02-standard/). See [Terminal errors](../../../README.md#terminal-errors) for the pattern. +It also doesn't surface a **terminal-error dialog** for a bad API key — `session.failureReason` (and `session.client.resume()` for retry) is wired up in [`../02-standard/`](../02-standard/). See [Terminal errors](../../../../README.md#terminal-errors) for the pattern. --- - **Views counterpart:** [`../../views/01-hello/`](../../views/01-hello/) -- **SDK reference:** root [README → Integration guide](../../../README.md#integration-guide) -- **Install the package:** root [README → Install](../../../README.md#install) +- **SDK reference:** root [README → Integration guide](../../../../README.md#integration-guide) +- **Install the package:** root [README → Install](../../../../README.md#install) diff --git a/examples/compose/01-hello/build.gradle.kts b/examples/chat/compose/01-hello/build.gradle.kts similarity index 100% rename from examples/compose/01-hello/build.gradle.kts rename to examples/chat/compose/01-hello/build.gradle.kts diff --git a/examples/compose/01-hello/src/androidTest/kotlin/ai/poly/examples/hello/compose/HelloFlowTest.kt b/examples/chat/compose/01-hello/src/androidTest/kotlin/ai/poly/examples/hello/compose/HelloFlowTest.kt similarity index 100% rename from examples/compose/01-hello/src/androidTest/kotlin/ai/poly/examples/hello/compose/HelloFlowTest.kt rename to examples/chat/compose/01-hello/src/androidTest/kotlin/ai/poly/examples/hello/compose/HelloFlowTest.kt diff --git a/examples/compose/01-hello/src/main/AndroidManifest.xml b/examples/chat/compose/01-hello/src/main/AndroidManifest.xml similarity index 100% rename from examples/compose/01-hello/src/main/AndroidManifest.xml rename to examples/chat/compose/01-hello/src/main/AndroidManifest.xml diff --git a/examples/compose/01-hello/src/main/kotlin/ai/poly/examples/hello/compose/HelloApplication.kt b/examples/chat/compose/01-hello/src/main/kotlin/ai/poly/examples/hello/compose/HelloApplication.kt similarity index 100% rename from examples/compose/01-hello/src/main/kotlin/ai/poly/examples/hello/compose/HelloApplication.kt rename to examples/chat/compose/01-hello/src/main/kotlin/ai/poly/examples/hello/compose/HelloApplication.kt diff --git a/examples/compose/01-hello/src/main/kotlin/ai/poly/examples/hello/compose/MainActivity.kt b/examples/chat/compose/01-hello/src/main/kotlin/ai/poly/examples/hello/compose/MainActivity.kt similarity index 100% rename from examples/compose/01-hello/src/main/kotlin/ai/poly/examples/hello/compose/MainActivity.kt rename to examples/chat/compose/01-hello/src/main/kotlin/ai/poly/examples/hello/compose/MainActivity.kt diff --git a/examples/compose/01-hello/src/main/res/values/strings.xml b/examples/chat/compose/01-hello/src/main/res/values/strings.xml similarity index 100% rename from examples/compose/01-hello/src/main/res/values/strings.xml rename to examples/chat/compose/01-hello/src/main/res/values/strings.xml diff --git a/examples/compose/01-hello/src/main/res/values/themes.xml b/examples/chat/compose/01-hello/src/main/res/values/themes.xml similarity index 100% rename from examples/compose/01-hello/src/main/res/values/themes.xml rename to examples/chat/compose/01-hello/src/main/res/values/themes.xml diff --git a/examples/compose/02-standard/README.md b/examples/chat/compose/02-standard/README.md similarity index 94% rename from examples/compose/02-standard/README.md rename to examples/chat/compose/02-standard/README.md index 7341b08..d8573fe 100644 --- a/examples/compose/02-standard/README.md +++ b/examples/chat/compose/02-standard/README.md @@ -26,7 +26,7 @@ Set your API key in `src/main/kotlin/ai/poly/examples/standard/compose/StandardA - Failure overlay — `session.failureReason`, `session.client.resume()` - Keyboard handling — `WindowInsets.ime` + `windowInsetsPadding` (no manual layout math) -The SDK invariants behind each pattern are in the root README's [Integration guide](../../../README.md#integration-guide); this example shows them composed into one chat screen. +The SDK invariants behind each pattern are in the root README's [Integration guide](../../../../README.md#integration-guide); this example shows them composed into one chat screen. ## How it works @@ -85,7 +85,7 @@ scope.launch { runCatching { session.sendTyping() } } **Under the hood:** `isAgentTyping` is SDK-managed — true while the agent composes (driven by its thinking/streaming signals), auto-cleared on the next agent message or after the typing timeout (~10s), so you never run a timer. `sendTyping()` throttles outgoing STARTED frames to ≤1 per 3s and auto-emits STOPPED ~5s after your last call, so it's safe to fire on every keystroke. -*See [Integration guide › Typing](../../../README.md#typing).* +*See [Integration guide › Typing](../../../../README.md#typing).* ### Connection banner — `components/ConnectionBanner.kt` @@ -124,7 +124,7 @@ It sits at the top of the `Column`, above the message list, so it pushes the cha **Under the hood:** `session.connection` is SDK-driven — a transient drop surfaces as `Open → Reconnecting(n) → Open` (auto-reconnect with backoff and jitter, no `Closed` flash), so you only need a banner on `Reconnecting`. `Failed` arrives only after the reconnect budget is exhausted (handled by the failure overlay below). -*See [Integration guide › Connection & reconnect](../../../README.md#connection--reconnect).* +*See [Integration guide › Connection & reconnect](../../../../README.md#connection--reconnect).* ### Suggestion pills — under the last agent message @@ -167,7 +167,7 @@ if (showSuggestions && m.suggestions.isNotEmpty()) { **Under the hood:** `AgentMessage.suggestions` are quick replies the agent attached to *that* message (agent messages only). `clearSuggestions(id)` empties them in the model so the pills vanish before `send(...)` resolves — feels instant. -*See [Integration guide › Suggestions](../../../README.md#suggestions-quick-replies).* +*See [Integration guide › Suggestions](../../../../README.md#suggestions-quick-replies).* ### End chat + Start new chat — `ChatScreen.kt` @@ -210,7 +210,7 @@ if (hasEnded) { **Under the hood:** `session.end()` flips `hasEnded`. `startNewSession()` creates a fresh session — when the session id changes, `ChatSession` clears `messages` and resets the latched flags for you, so no view bookkeeping needed. -*See [Integration guide › Starting, resuming & ending a session](../../../README.md#starting-resuming--ending-a-session).* +*See [Integration guide › Starting, resuming & ending a session](../../../../README.md#starting-resuming--ending-a-session).* ### Delivery state + retry — inside the user bubble (`components/MessageBubbleView.kt`) @@ -265,7 +265,7 @@ onRetry = { draftId, text -> **Under the hood:** `UserMessage.delivery` is optimistic — `PENDING` immediately, then the SDK matches the server echo (via a local id) → `SENT`; if no echo arrives after retries (up to 3×) it settles on `FAILED`. You only render it; `removeMessage(draftId)` drops the failed draft so a retry doesn't leave a duplicate bubble. -*See [Integration guide › Delivery state & retry](../../../README.md#delivery-state--retry).* +*See [Integration guide › Delivery state & retry](../../../../README.md#delivery-state--retry).* ### Failure overlay — `ChatScreen.kt` @@ -299,7 +299,7 @@ Button(onClick = onReconnect) { Text("Reconnect") } **Under the hood:** `failureReason` is set whenever the chat can't auto-recover — an invalid `apiKey` rejected at the initial connect, the auto-reconnect budget exhausted, or the session expiring. Recovery is consumer-driven — call `session.client.resume()` to retry. -*See [Integration guide › Terminal errors](../../../README.md#terminal-errors).* +*See [Integration guide › Terminal errors](../../../../README.md#terminal-errors).* ### Keyboard handling — `ChatScreen.kt` @@ -318,7 +318,7 @@ Row( The `Scaffold` sets `contentWindowInsets = WindowInsets(0, 0, 0, 0)` so the content owns the bottom inset itself. The send button is a blue circle with an up-arrow vector (`R.drawable.ic_arrow_upward`). -*See [Integration guide › Avatars & keyboard](../../../README.md#avatars--keyboard).* +*See [Integration guide › Avatars & keyboard](../../../../README.md#avatars--keyboard).* ## What this example skips @@ -329,5 +329,5 @@ The `Scaffold` sets `contentWindowInsets = WindowInsets(0, 0, 0, 0)` so the cont --- - **Views counterpart:** [`examples/views/02-standard/`](../../views/02-standard/) -- **SDK reference:** root [README → Integration guide](../../../README.md#integration-guide) -- **Install the package:** root [README → Install](../../../README.md#install) +- **SDK reference:** root [README → Integration guide](../../../../README.md#integration-guide) +- **Install the package:** root [README → Install](../../../../README.md#install) diff --git a/examples/compose/02-standard/build.gradle.kts b/examples/chat/compose/02-standard/build.gradle.kts similarity index 100% rename from examples/compose/02-standard/build.gradle.kts rename to examples/chat/compose/02-standard/build.gradle.kts diff --git a/examples/compose/02-standard/src/androidTest/kotlin/ai/poly/examples/standard/compose/StandardComposeFlowTest.kt b/examples/chat/compose/02-standard/src/androidTest/kotlin/ai/poly/examples/standard/compose/StandardComposeFlowTest.kt similarity index 100% rename from examples/compose/02-standard/src/androidTest/kotlin/ai/poly/examples/standard/compose/StandardComposeFlowTest.kt rename to examples/chat/compose/02-standard/src/androidTest/kotlin/ai/poly/examples/standard/compose/StandardComposeFlowTest.kt diff --git a/examples/compose/02-standard/src/main/AndroidManifest.xml b/examples/chat/compose/02-standard/src/main/AndroidManifest.xml similarity index 100% rename from examples/compose/02-standard/src/main/AndroidManifest.xml rename to examples/chat/compose/02-standard/src/main/AndroidManifest.xml diff --git a/examples/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/ChatScreen.kt b/examples/chat/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/ChatScreen.kt similarity index 100% rename from examples/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/ChatScreen.kt rename to examples/chat/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/ChatScreen.kt diff --git a/examples/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/MainActivity.kt b/examples/chat/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/MainActivity.kt similarity index 100% rename from examples/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/MainActivity.kt rename to examples/chat/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/MainActivity.kt diff --git a/examples/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/Palette.kt b/examples/chat/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/Palette.kt similarity index 100% rename from examples/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/Palette.kt rename to examples/chat/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/Palette.kt diff --git a/examples/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/StandardApplication.kt b/examples/chat/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/StandardApplication.kt similarity index 100% rename from examples/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/StandardApplication.kt rename to examples/chat/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/StandardApplication.kt diff --git a/examples/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/components/ConnectionBanner.kt b/examples/chat/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/components/ConnectionBanner.kt similarity index 100% rename from examples/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/components/ConnectionBanner.kt rename to examples/chat/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/components/ConnectionBanner.kt diff --git a/examples/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/components/MessageBubbleView.kt b/examples/chat/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/components/MessageBubbleView.kt similarity index 100% rename from examples/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/components/MessageBubbleView.kt rename to examples/chat/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/components/MessageBubbleView.kt diff --git a/examples/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/components/SuggestionRow.kt b/examples/chat/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/components/SuggestionRow.kt similarity index 100% rename from examples/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/components/SuggestionRow.kt rename to examples/chat/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/components/SuggestionRow.kt diff --git a/examples/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/components/TypingIndicator.kt b/examples/chat/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/components/TypingIndicator.kt similarity index 100% rename from examples/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/components/TypingIndicator.kt rename to examples/chat/compose/02-standard/src/main/kotlin/ai/poly/examples/standard/compose/components/TypingIndicator.kt diff --git a/examples/compose/02-standard/src/main/res/drawable/ic_account_circle.xml b/examples/chat/compose/02-standard/src/main/res/drawable/ic_account_circle.xml similarity index 100% rename from examples/compose/02-standard/src/main/res/drawable/ic_account_circle.xml rename to examples/chat/compose/02-standard/src/main/res/drawable/ic_account_circle.xml diff --git a/examples/compose/02-standard/src/main/res/drawable/ic_arrow_upward.xml b/examples/chat/compose/02-standard/src/main/res/drawable/ic_arrow_upward.xml similarity index 100% rename from examples/compose/02-standard/src/main/res/drawable/ic_arrow_upward.xml rename to examples/chat/compose/02-standard/src/main/res/drawable/ic_arrow_upward.xml diff --git a/examples/compose/02-standard/src/main/res/values/strings.xml b/examples/chat/compose/02-standard/src/main/res/values/strings.xml similarity index 100% rename from examples/compose/02-standard/src/main/res/values/strings.xml rename to examples/chat/compose/02-standard/src/main/res/values/strings.xml diff --git a/examples/compose/02-standard/src/main/res/values/themes.xml b/examples/chat/compose/02-standard/src/main/res/values/themes.xml similarity index 100% rename from examples/compose/02-standard/src/main/res/values/themes.xml rename to examples/chat/compose/02-standard/src/main/res/values/themes.xml diff --git a/examples/compose/03-richcontent/README.md b/examples/chat/compose/03-richcontent/README.md similarity index 95% rename from examples/compose/03-richcontent/README.md rename to examples/chat/compose/03-richcontent/README.md index 3ad2c75..6060a96 100644 --- a/examples/compose/03-richcontent/README.md +++ b/examples/chat/compose/03-richcontent/README.md @@ -25,7 +25,7 @@ Then launch the installed app (the launcher `MainActivity`, which hosts `ChatScr **The SDK decodes the data; it never fetches bytes or dials phones.** You own image loading, caching, retry, link-opening, and the `tel:` URI. This example does all of that with Coil + `Intent`s. -The SDK invariants behind each pattern are in the root README's [Integration guide](../../../README.md#integration-guide). +The SDK invariants behind each pattern are in the root README's [Integration guide](../../../../README.md#integration-guide). ## How it works @@ -57,7 +57,7 @@ if (images.isNotEmpty()) { **Under the hood:** the SDK decodes the agent's `attachments` array and groups them onto the same `AgentMessage` as the text. No background fetch happens — you load `contentUrl` / `previewImageUrl` yourself. -*See [Integration guide › Attachments, link cards & call buttons](../../../README.md#attachments-link-cards--call-buttons).* +*See [Integration guide › Attachments, link cards & call buttons](../../../../README.md#attachments-link-cards--call-buttons).* ### Render URL link cards — `components/UrlCard.kt` @@ -86,7 +86,7 @@ if (urls.isNotEmpty()) { **Under the hood:** same decoded `Attachment` data — the SDK hands you the URL + preview + title, and leaves the card layout and link-opening entirely to your code. The example puts `clickable(enabled = contentUrl != null)` on the whole card (rather than a link inside it) so the tap target covers the full card and you can intercept (e.g. route in-app) before launching the `Intent`. -*See [Integration guide › Attachments, link cards & call buttons](../../../README.md#attachments-link-cards--call-buttons).* +*See [Integration guide › Attachments, link cards & call buttons](../../../../README.md#attachments-link-cards--call-buttons).* ### Render `tel:` call buttons — `components/CallActionButton.kt` @@ -109,7 +109,7 @@ if (m.callActions.isNotEmpty()) { `CallActionButton` sanitizes the number (digits + leading `+`), builds `tel:`, and hands it to the dialer via `Intent(ACTION_DIAL)` (no `CALL_PHONE` permission — the dialer pre-fills). -*See [Integration guide › Attachments, link cards & call buttons](../../../README.md#attachments-link-cards--call-buttons).* +*See [Integration guide › Attachments, link cards & call buttons](../../../../README.md#attachments-link-cards--call-buttons).* ### Render Markdown — `components/RichText.kt` @@ -141,7 +141,7 @@ if (m.text.isNotEmpty()) { > **Why normalize HTML?** Agent content is authored once and rendered on both web and mobile. The web widget pipes it through `marked` + DOMPurify, so a reply can reach mobile with literal `
` tags. `normalizeAgentHtml` mirrors that allow-list so the bubble matches the web. The minimal [`01-Hello`](../01-hello/) / [`02-Standard`](../02-standard/) examples skip this (plain `Text`), so they show `
` raw. -*See [Integration guide › Rich text & links](../../../README.md#rich-text--links).* +*See [Integration guide › Rich text & links](../../../../README.md#rich-text--links).* ### Bubble layout — compose everything @@ -194,7 +194,7 @@ NewMessageNotifier(session, NotificationPolicy.WHEN_BACKGROUNDED) // component It requests `POST_NOTIFICATIONS` (API 33+), creates a notification channel, and observes `client.events` for completed `AgentMessage` / `LiveAgentMessage` events (full text + stable `messageId`, not chunks). Collection is gated on the **`CREATED`** lifecycle (not `STARTED`) so a reply that lands while the chat is backgrounded can still raise a banner; on each event it checks whether the chat is currently on screen (`lifecycle.currentState.isAtLeast(STARTED)`) and — for `WHEN_BACKGROUNDED` — stays quiet if it is. Already-shown ids are skipped (persisted in `SharedPreferences`, so resume/relaunch replays don't re-fire), and a `NotificationCompat` banner is posted otherwise. On Android 13+ (API 33) the banner only appears if the user grants the `POST_NOTIFICATIONS` prompt — if it's denied, `post()` silently no-ops and no banner shows. -*See [Integration guide › In-app new-message alerts (local-only workaround)](../../../README.md#in-app-new-message-alerts-local-only-workaround).* +*See [Integration guide › In-app new-message alerts (local-only workaround)](../../../../README.md#in-app-new-message-alerts-local-only-workaround).* ## What this example skips @@ -204,5 +204,5 @@ It requests `POST_NOTIFICATIONS` (API 33+), creates a notification channel, and --- - **Views counterpart:** [`../../views/03-richcontent/`](../../views/03-richcontent/) -- **SDK reference:** root [README → Integration guide](../../../README.md#integration-guide) -- **Install the package:** root [README → Install](../../../README.md#install) +- **SDK reference:** root [README → Integration guide](../../../../README.md#integration-guide) +- **Install the package:** root [README → Install](../../../../README.md#install) diff --git a/examples/compose/03-richcontent/build.gradle.kts b/examples/chat/compose/03-richcontent/build.gradle.kts similarity index 100% rename from examples/compose/03-richcontent/build.gradle.kts rename to examples/chat/compose/03-richcontent/build.gradle.kts diff --git a/examples/compose/03-richcontent/src/androidTest/kotlin/ai/poly/examples/richcontent/compose/NotificationBannerTest.kt b/examples/chat/compose/03-richcontent/src/androidTest/kotlin/ai/poly/examples/richcontent/compose/NotificationBannerTest.kt similarity index 100% rename from examples/compose/03-richcontent/src/androidTest/kotlin/ai/poly/examples/richcontent/compose/NotificationBannerTest.kt rename to examples/chat/compose/03-richcontent/src/androidTest/kotlin/ai/poly/examples/richcontent/compose/NotificationBannerTest.kt diff --git a/examples/compose/03-richcontent/src/androidTest/kotlin/ai/poly/examples/richcontent/compose/RichContentComposeFlowTest.kt b/examples/chat/compose/03-richcontent/src/androidTest/kotlin/ai/poly/examples/richcontent/compose/RichContentComposeFlowTest.kt similarity index 100% rename from examples/compose/03-richcontent/src/androidTest/kotlin/ai/poly/examples/richcontent/compose/RichContentComposeFlowTest.kt rename to examples/chat/compose/03-richcontent/src/androidTest/kotlin/ai/poly/examples/richcontent/compose/RichContentComposeFlowTest.kt diff --git a/examples/compose/03-richcontent/src/main/AndroidManifest.xml b/examples/chat/compose/03-richcontent/src/main/AndroidManifest.xml similarity index 100% rename from examples/compose/03-richcontent/src/main/AndroidManifest.xml rename to examples/chat/compose/03-richcontent/src/main/AndroidManifest.xml diff --git a/examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/ChatScreen.kt b/examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/ChatScreen.kt similarity index 100% rename from examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/ChatScreen.kt rename to examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/ChatScreen.kt diff --git a/examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/MainActivity.kt b/examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/MainActivity.kt similarity index 100% rename from examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/MainActivity.kt rename to examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/MainActivity.kt diff --git a/examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/Palette.kt b/examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/Palette.kt similarity index 100% rename from examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/Palette.kt rename to examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/Palette.kt diff --git a/examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/RichContentApplication.kt b/examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/RichContentApplication.kt similarity index 100% rename from examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/RichContentApplication.kt rename to examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/RichContentApplication.kt diff --git a/examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/AttachmentCarousel.kt b/examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/AttachmentCarousel.kt similarity index 100% rename from examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/AttachmentCarousel.kt rename to examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/AttachmentCarousel.kt diff --git a/examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/CallActionButton.kt b/examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/CallActionButton.kt similarity index 100% rename from examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/CallActionButton.kt rename to examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/CallActionButton.kt diff --git a/examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/ConnectionBanner.kt b/examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/ConnectionBanner.kt similarity index 100% rename from examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/ConnectionBanner.kt rename to examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/ConnectionBanner.kt diff --git a/examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/MessageBubbleView.kt b/examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/MessageBubbleView.kt similarity index 100% rename from examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/MessageBubbleView.kt rename to examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/MessageBubbleView.kt diff --git a/examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/NewMessageNotifier.kt b/examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/NewMessageNotifier.kt similarity index 100% rename from examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/NewMessageNotifier.kt rename to examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/NewMessageNotifier.kt diff --git a/examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/RetryableAsyncImage.kt b/examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/RetryableAsyncImage.kt similarity index 100% rename from examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/RetryableAsyncImage.kt rename to examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/RetryableAsyncImage.kt diff --git a/examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/RichText.kt b/examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/RichText.kt similarity index 100% rename from examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/RichText.kt rename to examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/RichText.kt diff --git a/examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/SuggestionRow.kt b/examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/SuggestionRow.kt similarity index 100% rename from examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/SuggestionRow.kt rename to examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/SuggestionRow.kt diff --git a/examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/TypingIndicator.kt b/examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/TypingIndicator.kt similarity index 100% rename from examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/TypingIndicator.kt rename to examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/TypingIndicator.kt diff --git a/examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/UrlCard.kt b/examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/UrlCard.kt similarity index 100% rename from examples/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/UrlCard.kt rename to examples/chat/compose/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/compose/components/UrlCard.kt diff --git a/examples/compose/03-richcontent/src/main/res/drawable/ic_account_circle.xml b/examples/chat/compose/03-richcontent/src/main/res/drawable/ic_account_circle.xml similarity index 100% rename from examples/compose/03-richcontent/src/main/res/drawable/ic_account_circle.xml rename to examples/chat/compose/03-richcontent/src/main/res/drawable/ic_account_circle.xml diff --git a/examples/compose/03-richcontent/src/main/res/drawable/ic_arrow_upward.xml b/examples/chat/compose/03-richcontent/src/main/res/drawable/ic_arrow_upward.xml similarity index 100% rename from examples/compose/03-richcontent/src/main/res/drawable/ic_arrow_upward.xml rename to examples/chat/compose/03-richcontent/src/main/res/drawable/ic_arrow_upward.xml diff --git a/examples/compose/03-richcontent/src/main/res/drawable/ic_call.xml b/examples/chat/compose/03-richcontent/src/main/res/drawable/ic_call.xml similarity index 100% rename from examples/compose/03-richcontent/src/main/res/drawable/ic_call.xml rename to examples/chat/compose/03-richcontent/src/main/res/drawable/ic_call.xml diff --git a/examples/compose/03-richcontent/src/main/res/drawable/ic_image.xml b/examples/chat/compose/03-richcontent/src/main/res/drawable/ic_image.xml similarity index 100% rename from examples/compose/03-richcontent/src/main/res/drawable/ic_image.xml rename to examples/chat/compose/03-richcontent/src/main/res/drawable/ic_image.xml diff --git a/examples/compose/03-richcontent/src/main/res/values/strings.xml b/examples/chat/compose/03-richcontent/src/main/res/values/strings.xml similarity index 100% rename from examples/compose/03-richcontent/src/main/res/values/strings.xml rename to examples/chat/compose/03-richcontent/src/main/res/values/strings.xml diff --git a/examples/compose/03-richcontent/src/main/res/values/themes.xml b/examples/chat/compose/03-richcontent/src/main/res/values/themes.xml similarity index 100% rename from examples/compose/03-richcontent/src/main/res/values/themes.xml rename to examples/chat/compose/03-richcontent/src/main/res/values/themes.xml diff --git a/examples/compose/04-resilience/README.md b/examples/chat/compose/04-resilience/README.md similarity index 92% rename from examples/compose/04-resilience/README.md rename to examples/chat/compose/04-resilience/README.md index 0e62475..6d58418 100644 --- a/examples/compose/04-resilience/README.md +++ b/examples/chat/compose/04-resilience/README.md @@ -22,7 +22,7 @@ Then launch the installed app. Set your API key in `src/main/kotlin/ai/poly/exam - Replace the entire chat surface with a full-screen retry screen when `session.failureReason` is non-null - Recover via `session.client.resume()` from the terminal screen -The SDK invariants behind each pattern are in the root README's [Integration guide](../../../README.md#integration-guide); this example shows them as one concrete screen. +The SDK invariants behind each pattern are in the root README's [Integration guide](../../../../README.md#integration-guide); this example shows them as one concrete screen. ## How it works @@ -69,7 +69,7 @@ Column { **Under the hood:** when the OS reports no usable default network, the SDK's reachability watcher drops its dead socket and `session.connection` flips to `Reconnecting`. The two banners measure different things — the offline pill is the device, the reconnect pill is the socket — so it's meaningful to show both. -*See [Integration guide › Connection & reconnect](../../../README.md#connection--reconnect).* +*See [Integration guide › Connection & reconnect](../../../../README.md#connection--reconnect).* ### Loading skeleton — `components/LoadingSkeleton.kt` @@ -97,9 +97,9 @@ LazyColumn { **Under the hood:** `isReady` flips `true` only when the WebSocket reaches Open — after the REST call has returned a session id AND the socket handshake completes. On a cold relaunch with a stored session within the timeout, the server replays the transcript over the socket after it opens — so the skeleton shows briefly while connecting, then clears into the restored messages. The `messages.isEmpty()` half of the gate matters for mid-session reconnects, where the transcript is already in memory while `isReady` is `false`. -> **Streaming:** agent replies grow token-by-token by default (`Configuration.streamingEnabled = true` — ChatGPT-style). Set `streamingEnabled = false` to render completed bubbles only. See the root README's [*Streaming*](../../../README.md#streaming) section and [`07-Playground/`](../07-playground/) for a live toggle. +> **Streaming:** agent replies grow token-by-token by default (`Configuration.streamingEnabled = true` — ChatGPT-style). Set `streamingEnabled = false` to render completed bubbles only. See the root README's [*Streaming*](../../../../README.md#streaming) section and [`07-Playground/`](../07-playground/) for a live toggle. -*See [Integration guide › Loading & empty states](../../../README.md#loading--empty-states).* +*See [Integration guide › Loading & empty states](../../../../README.md#loading--empty-states).* ### Terminal error screen — `TerminalErrorScreen.kt` @@ -125,7 +125,7 @@ The screen uses `reason.debugDescription` for the subtitle — its structural ca **Under the hood:** `failureReason` is set only after the SDK's exponential-backoff reconnect ladder is exhausted, or on a terminal session error (auth, session-expired, session-ended). Transient blips don't trip it — those just flip `connection` to `Reconnecting` and back. That's why this screen is full-screen and gated on `failureReason` rather than on `connection`. -*See [Integration guide › Terminal errors](../../../README.md#terminal-errors).* +*See [Integration guide › Terminal errors](../../../../README.md#terminal-errors).* ## Try this on the emulator @@ -144,5 +144,5 @@ The screen uses `reason.debugDescription` for the subtitle — its structural ca --- - **Views counterpart:** [`../../views/04-resilience/`](../../views/04-resilience/) -- **SDK reference:** root [README → Integration guide](../../../README.md#integration-guide) -- **Install the package:** root [README → Install](../../../README.md#install) +- **SDK reference:** root [README → Integration guide](../../../../README.md#integration-guide) +- **Install the package:** root [README → Install](../../../../README.md#install) diff --git a/examples/compose/04-resilience/build.gradle.kts b/examples/chat/compose/04-resilience/build.gradle.kts similarity index 100% rename from examples/compose/04-resilience/build.gradle.kts rename to examples/chat/compose/04-resilience/build.gradle.kts diff --git a/examples/compose/04-resilience/src/androidTest/kotlin/ai/poly/examples/resilience/compose/ResilienceComposeFlowTest.kt b/examples/chat/compose/04-resilience/src/androidTest/kotlin/ai/poly/examples/resilience/compose/ResilienceComposeFlowTest.kt similarity index 100% rename from examples/compose/04-resilience/src/androidTest/kotlin/ai/poly/examples/resilience/compose/ResilienceComposeFlowTest.kt rename to examples/chat/compose/04-resilience/src/androidTest/kotlin/ai/poly/examples/resilience/compose/ResilienceComposeFlowTest.kt diff --git a/examples/compose/04-resilience/src/main/AndroidManifest.xml b/examples/chat/compose/04-resilience/src/main/AndroidManifest.xml similarity index 100% rename from examples/compose/04-resilience/src/main/AndroidManifest.xml rename to examples/chat/compose/04-resilience/src/main/AndroidManifest.xml diff --git a/examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/ChatScreen.kt b/examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/ChatScreen.kt similarity index 100% rename from examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/ChatScreen.kt rename to examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/ChatScreen.kt diff --git a/examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/MainActivity.kt b/examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/MainActivity.kt similarity index 100% rename from examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/MainActivity.kt rename to examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/MainActivity.kt diff --git a/examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/NetworkMonitor.kt b/examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/NetworkMonitor.kt similarity index 100% rename from examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/NetworkMonitor.kt rename to examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/NetworkMonitor.kt diff --git a/examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/Palette.kt b/examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/Palette.kt similarity index 100% rename from examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/Palette.kt rename to examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/Palette.kt diff --git a/examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/ResilienceApplication.kt b/examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/ResilienceApplication.kt similarity index 100% rename from examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/ResilienceApplication.kt rename to examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/ResilienceApplication.kt diff --git a/examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/TerminalErrorScreen.kt b/examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/TerminalErrorScreen.kt similarity index 100% rename from examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/TerminalErrorScreen.kt rename to examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/TerminalErrorScreen.kt diff --git a/examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/AttachmentCarousel.kt b/examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/AttachmentCarousel.kt similarity index 100% rename from examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/AttachmentCarousel.kt rename to examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/AttachmentCarousel.kt diff --git a/examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/CallActionButton.kt b/examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/CallActionButton.kt similarity index 100% rename from examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/CallActionButton.kt rename to examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/CallActionButton.kt diff --git a/examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/ConnectionBanner.kt b/examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/ConnectionBanner.kt similarity index 100% rename from examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/ConnectionBanner.kt rename to examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/ConnectionBanner.kt diff --git a/examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/LoadingSkeleton.kt b/examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/LoadingSkeleton.kt similarity index 100% rename from examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/LoadingSkeleton.kt rename to examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/LoadingSkeleton.kt diff --git a/examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/MessageBubbleView.kt b/examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/MessageBubbleView.kt similarity index 100% rename from examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/MessageBubbleView.kt rename to examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/MessageBubbleView.kt diff --git a/examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/OfflineBanner.kt b/examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/OfflineBanner.kt similarity index 100% rename from examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/OfflineBanner.kt rename to examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/OfflineBanner.kt diff --git a/examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/RetryableAsyncImage.kt b/examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/RetryableAsyncImage.kt similarity index 100% rename from examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/RetryableAsyncImage.kt rename to examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/RetryableAsyncImage.kt diff --git a/examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/RichText.kt b/examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/RichText.kt similarity index 100% rename from examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/RichText.kt rename to examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/RichText.kt diff --git a/examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/SuggestionRow.kt b/examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/SuggestionRow.kt similarity index 100% rename from examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/SuggestionRow.kt rename to examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/SuggestionRow.kt diff --git a/examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/TypingIndicator.kt b/examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/TypingIndicator.kt similarity index 100% rename from examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/TypingIndicator.kt rename to examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/TypingIndicator.kt diff --git a/examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/UrlCard.kt b/examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/UrlCard.kt similarity index 100% rename from examples/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/UrlCard.kt rename to examples/chat/compose/04-resilience/src/main/kotlin/ai/poly/examples/resilience/compose/components/UrlCard.kt diff --git a/examples/compose/04-resilience/src/main/res/drawable/ic_account_circle.xml b/examples/chat/compose/04-resilience/src/main/res/drawable/ic_account_circle.xml similarity index 100% rename from examples/compose/04-resilience/src/main/res/drawable/ic_account_circle.xml rename to examples/chat/compose/04-resilience/src/main/res/drawable/ic_account_circle.xml diff --git a/examples/compose/04-resilience/src/main/res/drawable/ic_arrow_upward.xml b/examples/chat/compose/04-resilience/src/main/res/drawable/ic_arrow_upward.xml similarity index 100% rename from examples/compose/04-resilience/src/main/res/drawable/ic_arrow_upward.xml rename to examples/chat/compose/04-resilience/src/main/res/drawable/ic_arrow_upward.xml diff --git a/examples/compose/04-resilience/src/main/res/drawable/ic_call.xml b/examples/chat/compose/04-resilience/src/main/res/drawable/ic_call.xml similarity index 100% rename from examples/compose/04-resilience/src/main/res/drawable/ic_call.xml rename to examples/chat/compose/04-resilience/src/main/res/drawable/ic_call.xml diff --git a/examples/compose/04-resilience/src/main/res/drawable/ic_error_triangle.xml b/examples/chat/compose/04-resilience/src/main/res/drawable/ic_error_triangle.xml similarity index 100% rename from examples/compose/04-resilience/src/main/res/drawable/ic_error_triangle.xml rename to examples/chat/compose/04-resilience/src/main/res/drawable/ic_error_triangle.xml diff --git a/examples/compose/04-resilience/src/main/res/drawable/ic_image.xml b/examples/chat/compose/04-resilience/src/main/res/drawable/ic_image.xml similarity index 100% rename from examples/compose/04-resilience/src/main/res/drawable/ic_image.xml rename to examples/chat/compose/04-resilience/src/main/res/drawable/ic_image.xml diff --git a/examples/compose/04-resilience/src/main/res/drawable/ic_link.xml b/examples/chat/compose/04-resilience/src/main/res/drawable/ic_link.xml similarity index 100% rename from examples/compose/04-resilience/src/main/res/drawable/ic_link.xml rename to examples/chat/compose/04-resilience/src/main/res/drawable/ic_link.xml diff --git a/examples/compose/04-resilience/src/main/res/drawable/ic_wifi_off.xml b/examples/chat/compose/04-resilience/src/main/res/drawable/ic_wifi_off.xml similarity index 100% rename from examples/compose/04-resilience/src/main/res/drawable/ic_wifi_off.xml rename to examples/chat/compose/04-resilience/src/main/res/drawable/ic_wifi_off.xml diff --git a/examples/compose/04-resilience/src/main/res/values/strings.xml b/examples/chat/compose/04-resilience/src/main/res/values/strings.xml similarity index 100% rename from examples/compose/04-resilience/src/main/res/values/strings.xml rename to examples/chat/compose/04-resilience/src/main/res/values/strings.xml diff --git a/examples/compose/04-resilience/src/main/res/values/themes.xml b/examples/chat/compose/04-resilience/src/main/res/values/themes.xml similarity index 100% rename from examples/compose/04-resilience/src/main/res/values/themes.xml rename to examples/chat/compose/04-resilience/src/main/res/values/themes.xml diff --git a/examples/compose/05-handoff/README.md b/examples/chat/compose/05-handoff/README.md similarity index 93% rename from examples/compose/05-handoff/README.md rename to examples/chat/compose/05-handoff/README.md index f13d505..be5505d 100644 --- a/examples/compose/05-handoff/README.md +++ b/examples/chat/compose/05-handoff/README.md @@ -22,7 +22,7 @@ Then launch the installed app. Set your API key in `src/main/kotlin/ai/poly/exam - Reuse `session.isAgentTyping` for live-agent typing — no new flag needed - Let `LiveAgentLeft` flip `session.hasEnded` naturally so the existing chat-ended footer takes over -The SDK invariants behind each pattern are in the root README's [Integration guide](../../../README.md#integration-guide); this example shows them as one concrete screen. +The SDK invariants behind each pattern are in the root README's [Integration guide](../../../../README.md#integration-guide); this example shows them as one concrete screen. ## How it works @@ -77,7 +77,7 @@ private fun systemText(event: SystemEvent): String = when (event) { **Under the hood:** the SDK converts every handoff transition — agent-triggered handoff, queue status, accepted / failed / timeout, live-agent joined / left — into a `ChatMessage.System` appended to `session.messages`. They interleave with `User` / `Agent` bubbles in the timeline, so you only render the `System` branch and the order comes out right for free. -*See [Integration guide › Live agent handoff](../../../README.md#live-agent-handoff).* +*See [Integration guide › Live agent handoff](../../../../README.md#live-agent-handoff).* ### Live-agent bubble styling — `components/MessageBubbleView.kt` @@ -116,9 +116,9 @@ RichText( **Under the hood:** the SDK normalises live-agent replies into the same `AgentMessage` shape as Poly replies — only `agentKind` and (usually) `avatarUrl` / `agentName` differ. Live-agent typing reuses `session.isAgentTyping`, so the typing indicator works during handoff with no extra wiring. -> **Streaming:** agent replies grow token-by-token by default (`Configuration.streamingEnabled = true` — ChatGPT-style). Live-agent messages flow through the same path, so streaming works for them too. See the root README's [*Streaming*](../../../README.md#streaming) section and [`07-Playground/`](../07-playground/) for a live toggle. +> **Streaming:** agent replies grow token-by-token by default (`Configuration.streamingEnabled = true` — ChatGPT-style). Live-agent messages flow through the same path, so streaming works for them too. See the root README's [*Streaming*](../../../../README.md#streaming) section and [`07-Playground/`](../07-playground/) for a live toggle. -*See [Integration guide › Live agent handoff](../../../README.md#live-agent-handoff).* +*See [Integration guide › Live agent handoff](../../../../README.md#live-agent-handoff).* ### Side effects via raw `client.events` — `ChatScreen.kt` @@ -163,7 +163,7 @@ TopAppBar(title = { Text(connectedAgentName?.takeIf { it.isNotEmpty() } ?: "Chat **Under the hood:** `client.events` is the same typed, decoded stream the SDK uses internally — subscribing adds no transport overhead, and is the right place for imperative side effects (title, analytics, deep-linking) that aren't a function of `messages`. Anything renderable already comes through `session.messages` / `session.isAgentTyping`, so don't drive the bubble list off this stream. -*See [Integration guide › Live agent handoff](../../../README.md#live-agent-handoff).* +*See [Integration guide › Live agent handoff](../../../../README.md#live-agent-handoff).* ### Why `LiveAgentLeft` needs no special handling @@ -188,5 +188,5 @@ It's terminal — `session.hasEnded` flips true and the existing chat-ended foot --- - **Views counterpart:** [`../../views/05-handoff/`](../../views/05-handoff/) -- **SDK reference:** root [README → Integration guide](../../../README.md#integration-guide) -- **Install the package:** root [README → Install](../../../README.md#install) +- **SDK reference:** root [README → Integration guide](../../../../README.md#integration-guide) +- **Install the package:** root [README → Install](../../../../README.md#install) diff --git a/examples/compose/05-handoff/build.gradle.kts b/examples/chat/compose/05-handoff/build.gradle.kts similarity index 100% rename from examples/compose/05-handoff/build.gradle.kts rename to examples/chat/compose/05-handoff/build.gradle.kts diff --git a/examples/compose/05-handoff/src/androidTest/kotlin/ai/poly/examples/handoff/compose/HandoffFlowTest.kt b/examples/chat/compose/05-handoff/src/androidTest/kotlin/ai/poly/examples/handoff/compose/HandoffFlowTest.kt similarity index 100% rename from examples/compose/05-handoff/src/androidTest/kotlin/ai/poly/examples/handoff/compose/HandoffFlowTest.kt rename to examples/chat/compose/05-handoff/src/androidTest/kotlin/ai/poly/examples/handoff/compose/HandoffFlowTest.kt diff --git a/examples/compose/05-handoff/src/main/AndroidManifest.xml b/examples/chat/compose/05-handoff/src/main/AndroidManifest.xml similarity index 100% rename from examples/compose/05-handoff/src/main/AndroidManifest.xml rename to examples/chat/compose/05-handoff/src/main/AndroidManifest.xml diff --git a/examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/ChatScreen.kt b/examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/ChatScreen.kt similarity index 100% rename from examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/ChatScreen.kt rename to examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/ChatScreen.kt diff --git a/examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/HandoffApplication.kt b/examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/HandoffApplication.kt similarity index 100% rename from examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/HandoffApplication.kt rename to examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/HandoffApplication.kt diff --git a/examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/MainActivity.kt b/examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/MainActivity.kt similarity index 100% rename from examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/MainActivity.kt rename to examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/MainActivity.kt diff --git a/examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/NetworkMonitor.kt b/examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/NetworkMonitor.kt similarity index 100% rename from examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/NetworkMonitor.kt rename to examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/NetworkMonitor.kt diff --git a/examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/Palette.kt b/examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/Palette.kt similarity index 100% rename from examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/Palette.kt rename to examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/Palette.kt diff --git a/examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/AgentAvatarView.kt b/examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/AgentAvatarView.kt similarity index 100% rename from examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/AgentAvatarView.kt rename to examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/AgentAvatarView.kt diff --git a/examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/AttachmentCarousel.kt b/examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/AttachmentCarousel.kt similarity index 100% rename from examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/AttachmentCarousel.kt rename to examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/AttachmentCarousel.kt diff --git a/examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/CallActionButton.kt b/examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/CallActionButton.kt similarity index 100% rename from examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/CallActionButton.kt rename to examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/CallActionButton.kt diff --git a/examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/ConnectionBanner.kt b/examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/ConnectionBanner.kt similarity index 100% rename from examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/ConnectionBanner.kt rename to examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/ConnectionBanner.kt diff --git a/examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/LoadingSkeleton.kt b/examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/LoadingSkeleton.kt similarity index 100% rename from examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/LoadingSkeleton.kt rename to examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/LoadingSkeleton.kt diff --git a/examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/MessageBubbleView.kt b/examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/MessageBubbleView.kt similarity index 100% rename from examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/MessageBubbleView.kt rename to examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/MessageBubbleView.kt diff --git a/examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/OfflineBanner.kt b/examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/OfflineBanner.kt similarity index 100% rename from examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/OfflineBanner.kt rename to examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/OfflineBanner.kt diff --git a/examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/RetryableAsyncImage.kt b/examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/RetryableAsyncImage.kt similarity index 100% rename from examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/RetryableAsyncImage.kt rename to examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/RetryableAsyncImage.kt diff --git a/examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/RichText.kt b/examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/RichText.kt similarity index 100% rename from examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/RichText.kt rename to examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/RichText.kt diff --git a/examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/SuggestionRow.kt b/examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/SuggestionRow.kt similarity index 100% rename from examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/SuggestionRow.kt rename to examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/SuggestionRow.kt diff --git a/examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/TypingIndicator.kt b/examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/TypingIndicator.kt similarity index 100% rename from examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/TypingIndicator.kt rename to examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/TypingIndicator.kt diff --git a/examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/UrlCard.kt b/examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/UrlCard.kt similarity index 100% rename from examples/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/UrlCard.kt rename to examples/chat/compose/05-handoff/src/main/kotlin/ai/poly/examples/handoff/compose/components/UrlCard.kt diff --git a/examples/compose/05-handoff/src/main/res/drawable/ic_account_circle.xml b/examples/chat/compose/05-handoff/src/main/res/drawable/ic_account_circle.xml similarity index 100% rename from examples/compose/05-handoff/src/main/res/drawable/ic_account_circle.xml rename to examples/chat/compose/05-handoff/src/main/res/drawable/ic_account_circle.xml diff --git a/examples/compose/05-handoff/src/main/res/drawable/ic_arrow_upward.xml b/examples/chat/compose/05-handoff/src/main/res/drawable/ic_arrow_upward.xml similarity index 100% rename from examples/compose/05-handoff/src/main/res/drawable/ic_arrow_upward.xml rename to examples/chat/compose/05-handoff/src/main/res/drawable/ic_arrow_upward.xml diff --git a/examples/compose/05-handoff/src/main/res/drawable/ic_call.xml b/examples/chat/compose/05-handoff/src/main/res/drawable/ic_call.xml similarity index 100% rename from examples/compose/05-handoff/src/main/res/drawable/ic_call.xml rename to examples/chat/compose/05-handoff/src/main/res/drawable/ic_call.xml diff --git a/examples/compose/05-handoff/src/main/res/drawable/ic_error_triangle.xml b/examples/chat/compose/05-handoff/src/main/res/drawable/ic_error_triangle.xml similarity index 100% rename from examples/compose/05-handoff/src/main/res/drawable/ic_error_triangle.xml rename to examples/chat/compose/05-handoff/src/main/res/drawable/ic_error_triangle.xml diff --git a/examples/compose/05-handoff/src/main/res/drawable/ic_image.xml b/examples/chat/compose/05-handoff/src/main/res/drawable/ic_image.xml similarity index 100% rename from examples/compose/05-handoff/src/main/res/drawable/ic_image.xml rename to examples/chat/compose/05-handoff/src/main/res/drawable/ic_image.xml diff --git a/examples/compose/05-handoff/src/main/res/drawable/ic_link.xml b/examples/chat/compose/05-handoff/src/main/res/drawable/ic_link.xml similarity index 100% rename from examples/compose/05-handoff/src/main/res/drawable/ic_link.xml rename to examples/chat/compose/05-handoff/src/main/res/drawable/ic_link.xml diff --git a/examples/compose/05-handoff/src/main/res/drawable/ic_person.xml b/examples/chat/compose/05-handoff/src/main/res/drawable/ic_person.xml similarity index 100% rename from examples/compose/05-handoff/src/main/res/drawable/ic_person.xml rename to examples/chat/compose/05-handoff/src/main/res/drawable/ic_person.xml diff --git a/examples/compose/05-handoff/src/main/res/drawable/ic_wifi_off.xml b/examples/chat/compose/05-handoff/src/main/res/drawable/ic_wifi_off.xml similarity index 100% rename from examples/compose/05-handoff/src/main/res/drawable/ic_wifi_off.xml rename to examples/chat/compose/05-handoff/src/main/res/drawable/ic_wifi_off.xml diff --git a/examples/compose/05-handoff/src/main/res/values/strings.xml b/examples/chat/compose/05-handoff/src/main/res/values/strings.xml similarity index 100% rename from examples/compose/05-handoff/src/main/res/values/strings.xml rename to examples/chat/compose/05-handoff/src/main/res/values/strings.xml diff --git a/examples/compose/05-handoff/src/main/res/values/themes.xml b/examples/chat/compose/05-handoff/src/main/res/values/themes.xml similarity index 100% rename from examples/compose/05-handoff/src/main/res/values/themes.xml rename to examples/chat/compose/05-handoff/src/main/res/values/themes.xml diff --git a/examples/compose/06-fullreference/README.md b/examples/chat/compose/06-fullreference/README.md similarity index 92% rename from examples/compose/06-fullreference/README.md rename to examples/chat/compose/06-fullreference/README.md index f1e9dc1..336de16 100644 --- a/examples/compose/06-fullreference/README.md +++ b/examples/chat/compose/06-fullreference/README.md @@ -28,7 +28,7 @@ Then launch the installed app. Set your API key in `src/main/kotlin/ai/poly/exam - Streaming-aware scroll: re-anchor on text-length growth, not just `messages.size` - In-app new-message banners with a `NotificationPolicy` (quiet while the chat is on screen) -The SDK invariants behind each pattern are in the root README's [Integration guide](../../../README.md#integration-guide). +The SDK invariants behind each pattern are in the root README's [Integration guide](../../../../README.md#integration-guide). ## How it works @@ -76,7 +76,7 @@ scope.launch { **Under the hood:** three lifecycle streams cover the router — `client.sessionState` is the SDK's own lifecycle state (loading / ready / restored / error), `client.connectionStatus` the transport (`Failed` routes to the error screen while loading), `client.events` the decoded wire stream. Between them the router never needs private hooks; transitions only fire *while still loading*, so a mid-chat blip never throws the user back. -*See [Integration guide › Connection & reconnect](../../../README.md#connection--reconnect).* +*See [Integration guide › Connection & reconnect](../../../../README.md#connection--reconnect).* ### Recoverable error screen — `ErrorScreen.kt` @@ -93,7 +93,7 @@ The error subtitles use `PolyError.debugDescription` rather than a localized mes **Under the hood:** routing errors only while `Loading` means the error screen is recoverable by design — a transient blip after the chat is up just flips `connection` and recovers itself. If you want a non-recoverable terminal screen instead (the `04-Resilience` pattern), bind to `session.failureReason` directly. -*See [Integration guide › Terminal errors](../../../README.md#terminal-errors).* +*See [Integration guide › Terminal errors](../../../../README.md#terminal-errors).* ### Start New with an active session — `AppRoot.kt` @@ -105,7 +105,7 @@ scope.launch { existing.client.startNewSession() } **Under the hood:** `ChatSession` is just an observable view over a client. Constructing a new one gives you an empty `messages` list; `startNewSession()` ends the old conversation server-side, creates a new session, and reconnects — the new transcript fills from the fresh `sessionStart`. -*See [Integration guide › Starting, resuming & ending a session](../../../README.md#starting-resuming--ending-a-session).* +*See [Integration guide › Starting, resuming & ending a session](../../../../README.md#starting-resuming--ending-a-session).* ### In-place start-new — `AppRoot.kt` @@ -121,7 +121,7 @@ fun startNewConversationInPlace() { **Under the hood:** `clearChat()` and `startNewSession()` work on the same client — so the lifecycle subscriptions (tied to that client) don't need re-arming. `ChatSession` detects the new session id and resets its latched flags, so the screen converges on a clean conversation without leaving `AppScreen.Chat`. -*See [Integration guide › Starting, resuming & ending a session](../../../README.md#starting-resuming--ending-a-session).* +*See [Integration guide › Starting, resuming & ending a session](../../../../README.md#starting-resuming--ending-a-session).* ### End → back to connect — `AppRoot.kt` @@ -141,7 +141,7 @@ fun endConversation() { **Under the hood:** awaiting `end()` before clearing the local `session` ensures the server has acknowledged the teardown before the connect screen re-probes `hasResumableSession()` — otherwise you can get a phantom "Resume" button for a session that's already dead. -*See [Integration guide › Starting, resuming & ending a session](../../../README.md#starting-resuming--ending-a-session).* +*See [Integration guide › Starting, resuming & ending a session](../../../../README.md#starting-resuming--ending-a-session).* ### Resume across launches — `ConnectView.kt` @@ -153,7 +153,7 @@ PolyMessaging.start() // always starts fresh The primary button flips between **Resume Chat** and **Start Chat** based on `hasActiveSession || canResume`; a secondary **Start New Chat** appears only when there's something to abandon. `hasResumableSession()` is a side-effect-free on-disk check (no network), so it's safe to call on every recomposition. -*See [Integration guide › Quick start](../../../README.md#quick-start) and [Integration guide › Starting, resuming & ending a session](../../../README.md#starting-resuming--ending-a-session).* +*See [Integration guide › Quick start](../../../../README.md#quick-start) and [Integration guide › Starting, resuming & ending a session](../../../../README.md#starting-resuming--ending-a-session).* ### Delayed "Sending..." label — `AppRoot.kt` (`ChatScreenHost`) @@ -185,7 +185,7 @@ LaunchedEffect(messages) { **Under the hood:** this only gates *display* — the SDK still reports `PENDING` immediately and `SENT` the moment the server confirms. The bubble is in `messages` from the first frame either way; the label is the only thing this code controls. -*See [Integration guide › Delivery state & retry](../../../README.md#delivery-state--retry).* +*See [Integration guide › Delivery state & retry](../../../../README.md#delivery-state--retry).* ### Retry removes the failed draft, then re-sends — `AppRoot.kt` @@ -200,7 +200,7 @@ onRetry = { text, draftId -> **Under the hood:** without `removeMessage`, retrying would leave a "Failed" bubble next to the new attempt — `send()` always creates a fresh draft id rather than mutating the old one. Dropping the failed draft first is what keeps the transcript clean. -*See [Integration guide › Delivery state & retry](../../../README.md#delivery-state--retry).* +*See [Integration guide › Delivery state & retry](../../../../README.md#delivery-state--retry).* ### Streaming-aware scroll — `ChatView.kt` @@ -238,11 +238,11 @@ LaunchedEffect(messages.size, lastTextLength, isAgentTyping, sendingLabels, last } ``` -> **Streaming:** agent replies grow token-by-token by default (`Configuration.streamingEnabled = true` — ChatGPT-style). The `lastTextLength` key above is what keeps the scroll pinned to the bottom while the text grows. See the root README's [*Streaming*](../../../README.md#streaming) section and [`07-Playground`](../07-playground/) for a live toggle. +> **Streaming:** agent replies grow token-by-token by default (`Configuration.streamingEnabled = true` — ChatGPT-style). The `lastTextLength` key above is what keeps the scroll pinned to the bottom while the text grows. See the root README's [*Streaming*](../../../../README.md#streaming) section and [`07-Playground`](../07-playground/) for a live toggle. **Under the hood:** with `streamingEnabled = true` (the default), `ChatSession` extends the last agent message's `text` on every chunk and re-publishes `messages`. Keying the effect on `lastTextLength` (a derived `Int`) gives Compose a stable, scalar signal to drive the scroll — without it, a streaming reply would slide off the bottom of the screen as it grows. -*See [Integration guide › Streaming](../../../README.md#streaming).* +*See [Integration guide › Streaming](../../../../README.md#streaming).* ### In-app new-message banners — `NewMessageNotifier.kt` @@ -260,7 +260,7 @@ fun NewMessageNotifier(session: ChatSession, policy: NotificationPolicy = Notifi - **CREATED-lifecycle collection** — it collects `session.client.events` under `repeatOnLifecycle(Lifecycle.State.CREATED)`, not `STARTED`, so a reply that lands while the chat is backgrounded still raises a banner. `WHEN_BACKGROUNDED` then suppresses the banner whenever the chat is actually visible (`currentState.isAtLeast(Lifecycle.State.STARTED)`) — STARTED, not RESUMED, so a reply that arrives while the shade is down or a dialog is up doesn't banner over a chat you're reading. - **Persisted dedupe** — completed messages only (chunks ignored); each is keyed by its server `messageId` in a bounded `SharedPreferences`-backed store, so the SDK's replay-on-resume doesn't re-fire old banners across relaunches. -*See [Integration guide › In-app new-message alerts (local-only workaround)](../../../README.md#in-app-new-message-alerts-local-only-workaround).* +*See [Integration guide › In-app new-message alerts (local-only workaround)](../../../../README.md#in-app-new-message-alerts-local-only-workaround).* ### Everything else @@ -287,5 +287,5 @@ fun NewMessageNotifier(session: ChatSession, policy: NotificationPolicy = Notifi --- - **Views counterpart:** [`../../views/06-fullreference/`](../../views/06-fullreference/) -- **SDK reference:** root [README → Integration guide](../../../README.md#integration-guide) -- **Install the package:** root [README → Install](../../../README.md#install) +- **SDK reference:** root [README → Integration guide](../../../../README.md#integration-guide) +- **Install the package:** root [README → Install](../../../../README.md#install) diff --git a/examples/compose/06-fullreference/build.gradle.kts b/examples/chat/compose/06-fullreference/build.gradle.kts similarity index 100% rename from examples/compose/06-fullreference/build.gradle.kts rename to examples/chat/compose/06-fullreference/build.gradle.kts diff --git a/examples/compose/06-fullreference/src/androidTest/kotlin/ai/poly/examples/fullreference/compose/FullReferenceFlowTest.kt b/examples/chat/compose/06-fullreference/src/androidTest/kotlin/ai/poly/examples/fullreference/compose/FullReferenceFlowTest.kt similarity index 100% rename from examples/compose/06-fullreference/src/androidTest/kotlin/ai/poly/examples/fullreference/compose/FullReferenceFlowTest.kt rename to examples/chat/compose/06-fullreference/src/androidTest/kotlin/ai/poly/examples/fullreference/compose/FullReferenceFlowTest.kt diff --git a/examples/compose/06-fullreference/src/androidTest/kotlin/ai/poly/examples/fullreference/compose/NotificationBannerTest.kt b/examples/chat/compose/06-fullreference/src/androidTest/kotlin/ai/poly/examples/fullreference/compose/NotificationBannerTest.kt similarity index 100% rename from examples/compose/06-fullreference/src/androidTest/kotlin/ai/poly/examples/fullreference/compose/NotificationBannerTest.kt rename to examples/chat/compose/06-fullreference/src/androidTest/kotlin/ai/poly/examples/fullreference/compose/NotificationBannerTest.kt diff --git a/examples/compose/06-fullreference/src/main/AndroidManifest.xml b/examples/chat/compose/06-fullreference/src/main/AndroidManifest.xml similarity index 100% rename from examples/compose/06-fullreference/src/main/AndroidManifest.xml rename to examples/chat/compose/06-fullreference/src/main/AndroidManifest.xml diff --git a/examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/AppRoot.kt b/examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/AppRoot.kt similarity index 100% rename from examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/AppRoot.kt rename to examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/AppRoot.kt diff --git a/examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/ChatView.kt b/examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/ChatView.kt similarity index 100% rename from examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/ChatView.kt rename to examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/ChatView.kt diff --git a/examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/ConnectView.kt b/examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/ConnectView.kt similarity index 100% rename from examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/ConnectView.kt rename to examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/ConnectView.kt diff --git a/examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/ErrorScreen.kt b/examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/ErrorScreen.kt similarity index 100% rename from examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/ErrorScreen.kt rename to examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/ErrorScreen.kt diff --git a/examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/FullReferenceApplication.kt b/examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/FullReferenceApplication.kt similarity index 100% rename from examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/FullReferenceApplication.kt rename to examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/FullReferenceApplication.kt diff --git a/examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/LoadingView.kt b/examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/LoadingView.kt similarity index 100% rename from examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/LoadingView.kt rename to examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/LoadingView.kt diff --git a/examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/MainActivity.kt b/examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/MainActivity.kt similarity index 100% rename from examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/MainActivity.kt rename to examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/MainActivity.kt diff --git a/examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/NetworkMonitor.kt b/examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/NetworkMonitor.kt similarity index 100% rename from examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/NetworkMonitor.kt rename to examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/NetworkMonitor.kt diff --git a/examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/Palette.kt b/examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/Palette.kt similarity index 100% rename from examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/Palette.kt rename to examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/Palette.kt diff --git a/examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/AgentAvatarView.kt b/examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/AgentAvatarView.kt similarity index 100% rename from examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/AgentAvatarView.kt rename to examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/AgentAvatarView.kt diff --git a/examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/AttachmentCarousel.kt b/examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/AttachmentCarousel.kt similarity index 100% rename from examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/AttachmentCarousel.kt rename to examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/AttachmentCarousel.kt diff --git a/examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/CallActionButton.kt b/examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/CallActionButton.kt similarity index 100% rename from examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/CallActionButton.kt rename to examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/CallActionButton.kt diff --git a/examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/LoadingSkeleton.kt b/examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/LoadingSkeleton.kt similarity index 100% rename from examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/LoadingSkeleton.kt rename to examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/LoadingSkeleton.kt diff --git a/examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/MessageBubbleView.kt b/examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/MessageBubbleView.kt similarity index 100% rename from examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/MessageBubbleView.kt rename to examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/MessageBubbleView.kt diff --git a/examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/NewMessageNotifier.kt b/examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/NewMessageNotifier.kt similarity index 100% rename from examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/NewMessageNotifier.kt rename to examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/NewMessageNotifier.kt diff --git a/examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/RetryableAsyncImage.kt b/examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/RetryableAsyncImage.kt similarity index 100% rename from examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/RetryableAsyncImage.kt rename to examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/RetryableAsyncImage.kt diff --git a/examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/RichText.kt b/examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/RichText.kt similarity index 100% rename from examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/RichText.kt rename to examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/RichText.kt diff --git a/examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/SuggestionRow.kt b/examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/SuggestionRow.kt similarity index 100% rename from examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/SuggestionRow.kt rename to examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/SuggestionRow.kt diff --git a/examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/TypingIndicator.kt b/examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/TypingIndicator.kt similarity index 100% rename from examples/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/TypingIndicator.kt rename to examples/chat/compose/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/compose/components/TypingIndicator.kt diff --git a/examples/compose/06-fullreference/src/main/res/drawable/ic_account_circle.xml b/examples/chat/compose/06-fullreference/src/main/res/drawable/ic_account_circle.xml similarity index 100% rename from examples/compose/06-fullreference/src/main/res/drawable/ic_account_circle.xml rename to examples/chat/compose/06-fullreference/src/main/res/drawable/ic_account_circle.xml diff --git a/examples/compose/06-fullreference/src/main/res/drawable/ic_arrow_down.xml b/examples/chat/compose/06-fullreference/src/main/res/drawable/ic_arrow_down.xml similarity index 100% rename from examples/compose/06-fullreference/src/main/res/drawable/ic_arrow_down.xml rename to examples/chat/compose/06-fullreference/src/main/res/drawable/ic_arrow_down.xml diff --git a/examples/compose/06-fullreference/src/main/res/drawable/ic_arrow_upward.xml b/examples/chat/compose/06-fullreference/src/main/res/drawable/ic_arrow_upward.xml similarity index 100% rename from examples/compose/06-fullreference/src/main/res/drawable/ic_arrow_upward.xml rename to examples/chat/compose/06-fullreference/src/main/res/drawable/ic_arrow_upward.xml diff --git a/examples/compose/06-fullreference/src/main/res/drawable/ic_bolt.xml b/examples/chat/compose/06-fullreference/src/main/res/drawable/ic_bolt.xml similarity index 100% rename from examples/compose/06-fullreference/src/main/res/drawable/ic_bolt.xml rename to examples/chat/compose/06-fullreference/src/main/res/drawable/ic_bolt.xml diff --git a/examples/compose/06-fullreference/src/main/res/drawable/ic_call.xml b/examples/chat/compose/06-fullreference/src/main/res/drawable/ic_call.xml similarity index 100% rename from examples/compose/06-fullreference/src/main/res/drawable/ic_call.xml rename to examples/chat/compose/06-fullreference/src/main/res/drawable/ic_call.xml diff --git a/examples/compose/06-fullreference/src/main/res/drawable/ic_chat_bubbles.xml b/examples/chat/compose/06-fullreference/src/main/res/drawable/ic_chat_bubbles.xml similarity index 100% rename from examples/compose/06-fullreference/src/main/res/drawable/ic_chat_bubbles.xml rename to examples/chat/compose/06-fullreference/src/main/res/drawable/ic_chat_bubbles.xml diff --git a/examples/compose/06-fullreference/src/main/res/drawable/ic_chevron_left.xml b/examples/chat/compose/06-fullreference/src/main/res/drawable/ic_chevron_left.xml similarity index 100% rename from examples/compose/06-fullreference/src/main/res/drawable/ic_chevron_left.xml rename to examples/chat/compose/06-fullreference/src/main/res/drawable/ic_chevron_left.xml diff --git a/examples/compose/06-fullreference/src/main/res/drawable/ic_close_circle.xml b/examples/chat/compose/06-fullreference/src/main/res/drawable/ic_close_circle.xml similarity index 100% rename from examples/compose/06-fullreference/src/main/res/drawable/ic_close_circle.xml rename to examples/chat/compose/06-fullreference/src/main/res/drawable/ic_close_circle.xml diff --git a/examples/compose/06-fullreference/src/main/res/drawable/ic_dns.xml b/examples/chat/compose/06-fullreference/src/main/res/drawable/ic_dns.xml similarity index 100% rename from examples/compose/06-fullreference/src/main/res/drawable/ic_dns.xml rename to examples/chat/compose/06-fullreference/src/main/res/drawable/ic_dns.xml diff --git a/examples/compose/06-fullreference/src/main/res/drawable/ic_error_triangle.xml b/examples/chat/compose/06-fullreference/src/main/res/drawable/ic_error_triangle.xml similarity index 100% rename from examples/compose/06-fullreference/src/main/res/drawable/ic_error_triangle.xml rename to examples/chat/compose/06-fullreference/src/main/res/drawable/ic_error_triangle.xml diff --git a/examples/compose/06-fullreference/src/main/res/drawable/ic_image.xml b/examples/chat/compose/06-fullreference/src/main/res/drawable/ic_image.xml similarity index 100% rename from examples/compose/06-fullreference/src/main/res/drawable/ic_image.xml rename to examples/chat/compose/06-fullreference/src/main/res/drawable/ic_image.xml diff --git a/examples/compose/06-fullreference/src/main/res/drawable/ic_key.xml b/examples/chat/compose/06-fullreference/src/main/res/drawable/ic_key.xml similarity index 100% rename from examples/compose/06-fullreference/src/main/res/drawable/ic_key.xml rename to examples/chat/compose/06-fullreference/src/main/res/drawable/ic_key.xml diff --git a/examples/compose/06-fullreference/src/main/res/drawable/ic_link.xml b/examples/chat/compose/06-fullreference/src/main/res/drawable/ic_link.xml similarity index 100% rename from examples/compose/06-fullreference/src/main/res/drawable/ic_link.xml rename to examples/chat/compose/06-fullreference/src/main/res/drawable/ic_link.xml diff --git a/examples/compose/06-fullreference/src/main/res/drawable/ic_open_external.xml b/examples/chat/compose/06-fullreference/src/main/res/drawable/ic_open_external.xml similarity index 100% rename from examples/compose/06-fullreference/src/main/res/drawable/ic_open_external.xml rename to examples/chat/compose/06-fullreference/src/main/res/drawable/ic_open_external.xml diff --git a/examples/compose/06-fullreference/src/main/res/drawable/ic_resume.xml b/examples/chat/compose/06-fullreference/src/main/res/drawable/ic_resume.xml similarity index 100% rename from examples/compose/06-fullreference/src/main/res/drawable/ic_resume.xml rename to examples/chat/compose/06-fullreference/src/main/res/drawable/ic_resume.xml diff --git a/examples/compose/06-fullreference/src/main/res/drawable/ic_wifi_off.xml b/examples/chat/compose/06-fullreference/src/main/res/drawable/ic_wifi_off.xml similarity index 100% rename from examples/compose/06-fullreference/src/main/res/drawable/ic_wifi_off.xml rename to examples/chat/compose/06-fullreference/src/main/res/drawable/ic_wifi_off.xml diff --git a/examples/compose/06-fullreference/src/main/res/values/strings.xml b/examples/chat/compose/06-fullreference/src/main/res/values/strings.xml similarity index 100% rename from examples/compose/06-fullreference/src/main/res/values/strings.xml rename to examples/chat/compose/06-fullreference/src/main/res/values/strings.xml diff --git a/examples/compose/06-fullreference/src/main/res/values/themes.xml b/examples/chat/compose/06-fullreference/src/main/res/values/themes.xml similarity index 100% rename from examples/compose/06-fullreference/src/main/res/values/themes.xml rename to examples/chat/compose/06-fullreference/src/main/res/values/themes.xml diff --git a/examples/compose/07-playground/README.md b/examples/chat/compose/07-playground/README.md similarity index 96% rename from examples/compose/07-playground/README.md rename to examples/chat/compose/07-playground/README.md index 60bba1e..e865e1c 100644 --- a/examples/compose/07-playground/README.md +++ b/examples/chat/compose/07-playground/README.md @@ -69,7 +69,7 @@ session = s **Under the hood:** session-creation knobs (environment, streaming — and the server-side greeting they trigger) take effect only on a fresh session, which is why the sheet shows "Apply & Start New Session" whenever a session is live or resumable. `lastAppliedStreamingEnabled` on `DevSettings` lets the UI flag when the running session is out of sync with the current knobs. -*See [Integration guide › Configuration](../../../README.md#configuration).* +*See [Integration guide › Configuration](../../../../README.md#configuration).* ### Streaming toggle — `SettingsSheet.kt` @@ -94,7 +94,7 @@ if (hasAnySession && streamingEnabled != lastApplied) { **Under the hood:** when `streamingEnabled = true` (default), `ChatSession` extends the last agent message's `text` on every chunk and re-publishes `messages` — your `Text(message.text)` re-renders in place. When `false`, the SDK shows the assembled message in one shot and keeps `isAgentTyping == true` while the agent thinks. The chat view code is identical either way; the same `messages` list just updates differently. -*See [Integration guide › Streaming](../../../README.md#streaming).* +*See [Integration guide › Streaming](../../../../README.md#streaming).* ### Raw transport: send frames — `SettingsSheet.kt`, `AppRoot.kt` @@ -140,7 +140,7 @@ fun rawSend(event: OutgoingEvent) { **Under the hood:** `UserEndConversation` / `UserLeft` are real frames the backend processes (a server-side `EVENT_TYPE_USER_END_SESSION`); `Heartbeat` and `UserTyping` are protocol bookkeeping. Because the managed `send()` path isn't involved, the SDK won't surface these as messages or delivery events — they're invisible to `session.messages`. -*See [Integration guide › Raw transport](../../../README.md#advanced-raw-transport).* +*See [Integration guide › Raw transport](../../../../README.md#advanced-raw-transport).* ### Raw transport: close-code simulations — `SettingsSheet.kt`, `AppRoot.kt` @@ -182,7 +182,7 @@ onDisconnectClean = { closeWith(1000, "Debug clean disconnect") }, **Under the hood:** these are **client-side simulations**, not backend round-trips. The `40xx` codes are the SDK's internal vocabulary for classifying the close — the buttons exercise the SDK's own reconnect classification; the server isn't asked to reject or idle-out. -*See [Integration guide › Raw transport](../../../README.md#advanced-raw-transport).* +*See [Integration guide › Raw transport](../../../../README.md#advanced-raw-transport).* ### Event log — `EventLogger.kt`, `LogsSheet.kt` @@ -324,7 +324,7 @@ NewMessageNotifier(session, policy = NotificationPolicy.WHEN_BACKGROUNDED) **Under the hood.** -*In a nutshell* — request `POST_NOTIFICATIONS` (API 33+) and create the channel, watch `client.events` for completed agent messages, skip already-shown ones via the persisted store, and post through `NotificationManager` only when the policy allows it. (Full generic walkthrough in the [integration guide](../../../README.md#in-app-new-message-alerts-local-only-workaround), linked below.) +*In a nutshell* — request `POST_NOTIFICATIONS` (API 33+) and create the channel, watch `client.events` for completed agent messages, skip already-shown ones via the persisted store, and post through `NotificationManager` only when the policy allows it. (Full generic walkthrough in the [integration guide](../../../../README.md#in-app-new-message-alerts-local-only-workaround), linked below.) *In detail*, mapped to this example's code: @@ -352,7 +352,7 @@ store.markShown(id) Toggle streaming in the Settings sheet to confirm it stays one banner per reply (the bubble `id` is stable across chunks). -*See [Integration guide › In-app new-message alerts (local-only workaround)](../../../README.md#in-app-new-message-alerts-local-only-workaround).* +*See [Integration guide › In-app new-message alerts (local-only workaround)](../../../../README.md#in-app-new-message-alerts-local-only-workaround).* ## What this example is for @@ -364,5 +364,5 @@ Toggle streaming in the Settings sheet to confirm it stays one banner per reply --- - **Views counterpart:** [`examples/views/07-playground/`](../../views/07-playground/) -- **SDK reference:** root [README → Integration guide](../../../README.md#integration-guide) -- **Install the package:** root [README → Install](../../../README.md#install) +- **SDK reference:** root [README → Integration guide](../../../../README.md#integration-guide) +- **Install the package:** root [README → Install](../../../../README.md#install) diff --git a/examples/compose/07-playground/build.gradle.kts b/examples/chat/compose/07-playground/build.gradle.kts similarity index 100% rename from examples/compose/07-playground/build.gradle.kts rename to examples/chat/compose/07-playground/build.gradle.kts diff --git a/examples/compose/07-playground/src/androidTest/kotlin/ai/poly/examples/playground/compose/NotificationBannerTest.kt b/examples/chat/compose/07-playground/src/androidTest/kotlin/ai/poly/examples/playground/compose/NotificationBannerTest.kt similarity index 100% rename from examples/compose/07-playground/src/androidTest/kotlin/ai/poly/examples/playground/compose/NotificationBannerTest.kt rename to examples/chat/compose/07-playground/src/androidTest/kotlin/ai/poly/examples/playground/compose/NotificationBannerTest.kt diff --git a/examples/compose/07-playground/src/androidTest/kotlin/ai/poly/examples/playground/compose/PlaygroundFlowTest.kt b/examples/chat/compose/07-playground/src/androidTest/kotlin/ai/poly/examples/playground/compose/PlaygroundFlowTest.kt similarity index 100% rename from examples/compose/07-playground/src/androidTest/kotlin/ai/poly/examples/playground/compose/PlaygroundFlowTest.kt rename to examples/chat/compose/07-playground/src/androidTest/kotlin/ai/poly/examples/playground/compose/PlaygroundFlowTest.kt diff --git a/examples/compose/07-playground/src/main/AndroidManifest.xml b/examples/chat/compose/07-playground/src/main/AndroidManifest.xml similarity index 100% rename from examples/compose/07-playground/src/main/AndroidManifest.xml rename to examples/chat/compose/07-playground/src/main/AndroidManifest.xml diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/AppRoot.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/AppRoot.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/AppRoot.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/AppRoot.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/ChatModels.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/ChatModels.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/ChatModels.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/ChatModels.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/ChatView.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/ChatView.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/ChatView.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/ChatView.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/ConnectView.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/ConnectView.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/ConnectView.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/ConnectView.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/DevDiagnostics.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/DevDiagnostics.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/DevDiagnostics.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/DevDiagnostics.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/ErrorScreen.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/ErrorScreen.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/ErrorScreen.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/ErrorScreen.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/EventLogger.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/EventLogger.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/EventLogger.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/EventLogger.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/LoadingView.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/LoadingView.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/LoadingView.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/LoadingView.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/LogsSheet.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/LogsSheet.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/LogsSheet.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/LogsSheet.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/MainActivity.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/MainActivity.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/MainActivity.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/MainActivity.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/MessageTimestamp.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/MessageTimestamp.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/MessageTimestamp.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/MessageTimestamp.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/NetworkMonitor.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/NetworkMonitor.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/NetworkMonitor.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/NetworkMonitor.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/Palette.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/Palette.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/Palette.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/Palette.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/PlaygroundApplication.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/PlaygroundApplication.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/PlaygroundApplication.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/PlaygroundApplication.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/SettingsSheet.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/SettingsSheet.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/SettingsSheet.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/SettingsSheet.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/AgentAvatarView.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/AgentAvatarView.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/AgentAvatarView.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/AgentAvatarView.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/AttachmentCarousel.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/AttachmentCarousel.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/AttachmentCarousel.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/AttachmentCarousel.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/CallActionButton.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/CallActionButton.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/CallActionButton.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/CallActionButton.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/DebugStrip.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/DebugStrip.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/DebugStrip.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/DebugStrip.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/LoadingSkeleton.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/LoadingSkeleton.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/LoadingSkeleton.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/LoadingSkeleton.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/MessageBubbleView.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/MessageBubbleView.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/MessageBubbleView.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/MessageBubbleView.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/NewMessageNotifier.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/NewMessageNotifier.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/NewMessageNotifier.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/NewMessageNotifier.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/RetryableAsyncImage.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/RetryableAsyncImage.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/RetryableAsyncImage.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/RetryableAsyncImage.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/RichText.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/RichText.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/RichText.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/RichText.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/SuggestionRow.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/SuggestionRow.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/SuggestionRow.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/SuggestionRow.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/TimestampSeparator.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/TimestampSeparator.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/TimestampSeparator.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/TimestampSeparator.kt diff --git a/examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/TypingIndicator.kt b/examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/TypingIndicator.kt similarity index 100% rename from examples/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/TypingIndicator.kt rename to examples/chat/compose/07-playground/src/main/kotlin/ai/poly/examples/playground/compose/components/TypingIndicator.kt diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_account_circle.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_account_circle.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_account_circle.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_account_circle.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_arrow_down.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_arrow_down.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_arrow_down.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_arrow_down.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_arrow_upward.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_arrow_upward.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_arrow_upward.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_arrow_upward.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_autorenew.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_autorenew.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_autorenew.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_autorenew.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_block.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_block.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_block.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_block.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_bolt.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_bolt.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_bolt.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_bolt.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_call.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_call.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_call.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_call.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_chat_bubbles.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_chat_bubbles.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_chat_bubbles.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_chat_bubbles.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_chat_typing.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_chat_typing.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_chat_typing.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_chat_typing.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_chat_typing_filled.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_chat_typing_filled.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_chat_typing_filled.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_chat_typing_filled.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_check_circle.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_check_circle.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_check_circle.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_check_circle.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_chevron_left.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_chevron_left.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_chevron_left.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_chevron_left.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_circle_outline.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_circle_outline.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_circle_outline.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_circle_outline.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_clock.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_clock.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_clock.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_clock.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_clock_alert.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_clock_alert.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_clock_alert.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_clock_alert.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_close_circle.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_close_circle.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_close_circle.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_close_circle.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_copy.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_copy.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_copy.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_copy.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_dns.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_dns.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_dns.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_dns.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_ecg.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_ecg.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_ecg.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_ecg.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_error_circle.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_error_circle.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_error_circle.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_error_circle.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_error_triangle.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_error_triangle.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_error_triangle.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_error_triangle.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_expand_less.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_expand_less.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_expand_less.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_expand_less.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_expand_more.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_expand_more.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_expand_more.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_expand_more.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_filter_lines.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_filter_lines.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_filter_lines.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_filter_lines.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_find_in_page.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_find_in_page.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_find_in_page.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_find_in_page.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_image.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_image.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_image.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_image.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_info.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_info.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_info.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_info.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_key.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_key.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_key.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_key.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_link.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_link.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_link.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_link.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_log_lines.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_log_lines.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_log_lines.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_log_lines.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_logout.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_logout.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_logout.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_logout.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_more_horiz.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_more_horiz.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_more_horiz.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_more_horiz.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_open_external.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_open_external.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_open_external.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_open_external.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_radio_waves.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_radio_waves.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_radio_waves.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_radio_waves.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_restore.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_restore.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_restore.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_restore.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_resume.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_resume.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_resume.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_resume.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_search.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_search.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_search.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_search.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_settings.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_settings.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_settings.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_settings.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_shield_alert.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_shield_alert.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_shield_alert.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_shield_alert.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_swap_vert.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_swap_vert.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_swap_vert.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_swap_vert.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_tag.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_tag.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_tag.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_tag.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_waveform.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_waveform.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_waveform.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_waveform.xml diff --git a/examples/compose/07-playground/src/main/res/drawable/ic_wifi_off.xml b/examples/chat/compose/07-playground/src/main/res/drawable/ic_wifi_off.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/drawable/ic_wifi_off.xml rename to examples/chat/compose/07-playground/src/main/res/drawable/ic_wifi_off.xml diff --git a/examples/compose/07-playground/src/main/res/values/strings.xml b/examples/chat/compose/07-playground/src/main/res/values/strings.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/values/strings.xml rename to examples/chat/compose/07-playground/src/main/res/values/strings.xml diff --git a/examples/compose/07-playground/src/main/res/values/themes.xml b/examples/chat/compose/07-playground/src/main/res/values/themes.xml similarity index 100% rename from examples/compose/07-playground/src/main/res/values/themes.xml rename to examples/chat/compose/07-playground/src/main/res/values/themes.xml diff --git a/examples/views/01-hello/README.md b/examples/chat/views/01-hello/README.md similarity index 92% rename from examples/views/01-hello/README.md rename to examples/chat/views/01-hello/README.md index ad39b66..6cf6b01 100644 --- a/examples/views/01-hello/README.md +++ b/examples/chat/views/01-hello/README.md @@ -24,7 +24,7 @@ Then launch the installed app — `ChatActivity` is the `LAUNCHER` activity. Set - Send with `runCatching { session.send(text) }` inside `lifecycleScope.launch { }` - A "Reconnecting…" banner driven by `session.connection` -The SDK invariants behind each pattern are in the root README's [Integration guide](../../../README.md#integration-guide); this example shows them as one concrete `Activity`. +The SDK invariants behind each pattern are in the root README's [Integration guide](../../../../README.md#integration-guide); this example shows them as one concrete `Activity`. ## How it works @@ -51,7 +51,7 @@ After this, `PolyMessaging.chat()` works from any `Activity` with no arguments. **Under the hood:** `initialize` just stashes your API key and environment process-wide — no network happens yet. The work starts when you call `chat()`. -*See [Quick start](../../../README.md#quick-start).* +*See [Quick start](../../../../README.md#quick-start).* ### Get a session and render messages — `ChatActivity.kt` @@ -105,11 +105,11 @@ class ChatActivity : ComponentActivity() { `messages.collect { … }` subscribes to the transcript; `repeatOnLifecycle(Lifecycle.State.STARTED)` ties the subscription to the foreground lifecycle so it doesn't leak. -**Streaming is on by default** — `Configuration.streamingEnabled` defaults to `true`, so agent replies grow token-by-token (ChatGPT-style). The collector re-runs `adapter.submit(messages)` on every emission — including the ones where only the last agent bubble's text grew — so the cell re-renders as the message fills in. To switch to complete-message bubbles instead, set `streamingEnabled = false` on the `Configuration` you pass to `initialize` in `HelloApplication.kt`. See the root README's [Streaming](../../../README.md#streaming) section. +**Streaming is on by default** — `Configuration.streamingEnabled` defaults to `true`, so agent replies grow token-by-token (ChatGPT-style). The collector re-runs `adapter.submit(messages)` on every emission — including the ones where only the last agent bubble's text grew — so the cell re-renders as the message fills in. To switch to complete-message bubbles instead, set `streamingEnabled = false` on the `Configuration` you pass to `initialize` in `HelloApplication.kt`. See the root README's [Streaming](../../../../README.md#streaming) section. **Under the hood:** `chat()` runs the whole REST + WebSocket handshake, agent-join, and resume-or-create for you; `isReady` flips true once it's connected. `messages` is the SDK-maintained transcript (`ChatMessage.User` / `.Agent` / `.System`) that re-emits on every change, so each `collect` hands you the full list to render. `ChatSession` is collected and mutated from the main thread. -*See [Integration guide › The core pattern](../../../README.md#the-core-pattern-render-messages-yourself).* +*See [Integration guide › The core pattern](../../../../README.md#the-core-pattern-render-messages-yourself).* ### Branch over the message and style the bubble — `ChatActivity.kt` @@ -155,7 +155,7 @@ Each cell is `item_message.xml` — a `LinearLayout` wrapping a single `bubble` **Under the hood:** with `streamingEnabled = true` (the default), `ChatSession` extends the last `ChatMessage.Agent` message's `text` on every chunk and re-emits `messages`. The collector calls `adapter.submit(messages)` and then `scrollToPosition(messages.size - 1)`, so the list tracks the reply as it grows. -*See [Integration guide › Streaming](../../../README.md#streaming).* +*See [Integration guide › Streaming](../../../../README.md#streaming).* ### Send a message — `ChatActivity.kt` @@ -182,7 +182,7 @@ binding.send.setOnClickListener { **Under the hood:** `send(text)` is optimistic — the bubble appears in `messages` immediately while the SDK manages delivery and the server echo behind the scenes. Collect and call the session from the main thread. -*See [Integration guide › The core pattern](../../../README.md#the-core-pattern-render-messages-yourself).* +*See [Integration guide › The core pattern](../../../../README.md#the-core-pattern-render-messages-yourself).* ### Show a "Reconnecting…" banner — `ChatActivity.kt` @@ -208,7 +208,7 @@ launch { **Under the hood:** `connection` tracks the *socket*, not whether the *phone* lost Wi-Fi. The SDK reconnects with backoff + jitter and resumes the session; you only render the state. -*See [Integration guide › Connection & reconnect](../../../README.md#connection--reconnect).* +*See [Integration guide › Connection & reconnect](../../../../README.md#connection--reconnect).* ## Layout & insets note @@ -221,10 +221,10 @@ launch { - offline detection, full-screen terminal error → [`04-resilience/`](../04-resilience/) - live agent handoff → [`05-handoff/`](../05-handoff/) -> Note: this minimal rung does **not** surface `session.failureReason` (terminal errors like an invalid API key) — there's no error dialog. Adding a retry surface driven by `session.failureReason` + `session.client.resume()` is covered in the root README's [Terminal errors](../../../README.md#terminal-errors) section and the [`04-resilience/`](../04-resilience/) rung. +> Note: this minimal rung does **not** surface `session.failureReason` (terminal errors like an invalid API key) — there's no error dialog. Adding a retry surface driven by `session.failureReason` + `session.client.resume()` is covered in the root README's [Terminal errors](../../../../README.md#terminal-errors) section and the [`04-resilience/`](../04-resilience/) rung. --- - **Compose counterpart:** [`examples/compose/01-hello/`](../../compose/01-hello/) -- **SDK reference:** root [README → Integration guide](../../../README.md#integration-guide) -- **Install the package:** root [README → Install](../../../README.md#install) +- **SDK reference:** root [README → Integration guide](../../../../README.md#integration-guide) +- **Install the package:** root [README → Install](../../../../README.md#install) diff --git a/examples/views/01-hello/build.gradle.kts b/examples/chat/views/01-hello/build.gradle.kts similarity index 100% rename from examples/views/01-hello/build.gradle.kts rename to examples/chat/views/01-hello/build.gradle.kts diff --git a/examples/views/01-hello/src/androidTest/kotlin/ai/poly/examples/hello/views/HelloViewsFlowTest.kt b/examples/chat/views/01-hello/src/androidTest/kotlin/ai/poly/examples/hello/views/HelloViewsFlowTest.kt similarity index 100% rename from examples/views/01-hello/src/androidTest/kotlin/ai/poly/examples/hello/views/HelloViewsFlowTest.kt rename to examples/chat/views/01-hello/src/androidTest/kotlin/ai/poly/examples/hello/views/HelloViewsFlowTest.kt diff --git a/examples/views/01-hello/src/main/AndroidManifest.xml b/examples/chat/views/01-hello/src/main/AndroidManifest.xml similarity index 100% rename from examples/views/01-hello/src/main/AndroidManifest.xml rename to examples/chat/views/01-hello/src/main/AndroidManifest.xml diff --git a/examples/views/01-hello/src/main/kotlin/ai/poly/examples/hello/views/ChatActivity.kt b/examples/chat/views/01-hello/src/main/kotlin/ai/poly/examples/hello/views/ChatActivity.kt similarity index 100% rename from examples/views/01-hello/src/main/kotlin/ai/poly/examples/hello/views/ChatActivity.kt rename to examples/chat/views/01-hello/src/main/kotlin/ai/poly/examples/hello/views/ChatActivity.kt diff --git a/examples/views/01-hello/src/main/kotlin/ai/poly/examples/hello/views/HelloApplication.kt b/examples/chat/views/01-hello/src/main/kotlin/ai/poly/examples/hello/views/HelloApplication.kt similarity index 100% rename from examples/views/01-hello/src/main/kotlin/ai/poly/examples/hello/views/HelloApplication.kt rename to examples/chat/views/01-hello/src/main/kotlin/ai/poly/examples/hello/views/HelloApplication.kt diff --git a/examples/views/01-hello/src/main/res/layout/activity_chat.xml b/examples/chat/views/01-hello/src/main/res/layout/activity_chat.xml similarity index 100% rename from examples/views/01-hello/src/main/res/layout/activity_chat.xml rename to examples/chat/views/01-hello/src/main/res/layout/activity_chat.xml diff --git a/examples/views/01-hello/src/main/res/layout/item_message.xml b/examples/chat/views/01-hello/src/main/res/layout/item_message.xml similarity index 100% rename from examples/views/01-hello/src/main/res/layout/item_message.xml rename to examples/chat/views/01-hello/src/main/res/layout/item_message.xml diff --git a/examples/views/01-hello/src/main/res/values/strings.xml b/examples/chat/views/01-hello/src/main/res/values/strings.xml similarity index 100% rename from examples/views/01-hello/src/main/res/values/strings.xml rename to examples/chat/views/01-hello/src/main/res/values/strings.xml diff --git a/examples/views/01-hello/src/main/res/values/themes.xml b/examples/chat/views/01-hello/src/main/res/values/themes.xml similarity index 100% rename from examples/views/01-hello/src/main/res/values/themes.xml rename to examples/chat/views/01-hello/src/main/res/values/themes.xml diff --git a/examples/views/02-standard/README.md b/examples/chat/views/02-standard/README.md similarity index 95% rename from examples/views/02-standard/README.md rename to examples/chat/views/02-standard/README.md index 4ecd26d..d220d8b 100644 --- a/examples/views/02-standard/README.md +++ b/examples/chat/views/02-standard/README.md @@ -27,7 +27,7 @@ Then launch `ChatActivity`. Set your API key in `src/main/kotlin/ai/poly/example - Failure overlay — `session.failureReason`, `session.client.resume()` - Keyboard ride-along — `windowSoftInputMode=adjustResize` + `WindowInsets` padding -The SDK invariants behind each pattern are in the root README's [Integration guide](../../../README.md#integration-guide); this example shows them composed into one activity. +The SDK invariants behind each pattern are in the root README's [Integration guide](../../../../README.md#integration-guide); this example shows them composed into one activity. ## How it works @@ -82,7 +82,7 @@ The `TypingHolder` shows the agent avatar plus three animated dots (`ObjectAnima **Under the hood:** `isAgentTyping` is SDK-managed — true while the agent composes (driven by its thinking/streaming signals), auto-cleared on the next agent message or after the typing timeout (~10s), so you never run a timer. `sendTyping()` throttles outgoing STARTED frames to ≤1 per 3s and auto-emits STOPPED ~5s after your last call, so it's safe to fire on every keystroke. -*See [Integration guide › Typing](../../../README.md#typing).* +*See [Integration guide › Typing](../../../../README.md#typing).* ### Connection banner — `ChatActivity.kt` + `activity_chat.xml` @@ -112,7 +112,7 @@ The banner (`@id/banner`) is a yellow pill — a small `ProgressBar` spinner plu **Under the hood:** `session.connection` is SDK-driven — a transient drop surfaces as `Open → Reconnecting(n) → Open` (auto-reconnect with backoff and jitter, no `Closed` flash), so you only need to react to `Reconnecting`. `Failed` arrives only after the reconnect budget is exhausted (handled by the failure overlay below). -*See [Integration guide › Connection & reconnect](../../../README.md#connection--reconnect).* +*See [Integration guide › Connection & reconnect](../../../../README.md#connection--reconnect).* ### Suggestion pills — under the last message @@ -159,7 +159,7 @@ private val adapter = ChatAdapter( **Under the hood:** `suggestions` are quick replies the agent attached to *that* message. `clearSuggestions(messageId)` empties them in the model so the pills vanish before `send(...)` resolves — feels instant. Sending appends the user message as the new last message, so the suggestions row falls out of the rebuilt list naturally. -*See [Integration guide › Suggestions](../../../README.md#suggestions-quick-replies).* +*See [Integration guide › Suggestions](../../../../README.md#suggestions-quick-replies).* ### End + Start new chat — `ChatActivity.kt` @@ -218,7 +218,7 @@ The "End" item is registered in `onCreateOptionsMenu` and hidden in `onPrepareOp **Under the hood:** `session.end()` flips `hasEnded`. `startNewSession()` creates a fresh session — when the session id changes, `ChatSession` clears `messages` and resets the latched flags for you. -*See [Integration guide › Starting, resuming & ending a session](../../../README.md#starting-resuming--ending-a-session).* +*See [Integration guide › Starting, resuming & ending a session](../../../../README.md#starting-resuming--ending-a-session).* ### Delivery state + retry — `ChatAdapter.kt` + `item_message.xml` @@ -263,7 +263,7 @@ if (failed) { **Under the hood:** `UserMessage.delivery` is optimistic — `PENDING` immediately, then the SDK matches the server echo (via a local id) → `SENT`; if it can't be confirmed (offline at send time, or the connection drops while it's in flight) it settles on `FAILED`. The SDK does **not** auto-resend — the user retries explicitly via the "Tap to retry" affordance. The retry calls `session.removeMessage(m.draftId)` before `session.send(...)` so the failed bubble is replaced rather than left beside the new attempt. -*See [Integration guide › Delivery state & retry](../../../README.md#delivery-state--retry).* +*See [Integration guide › Delivery state & retry](../../../../README.md#delivery-state--retry).* ### Failure overlay — `ChatActivity.kt` + `activity_chat.xml` @@ -298,7 +298,7 @@ The overlay (`@id/failureOverlay`) is a dimmed, clickable card with a "Connectio **Under the hood:** `failureReason` is set whenever the chat can't auto-recover — an invalid `apiKey` rejected at the initial connect, the auto-reconnect budget exhausted, or the session expiring. Recovery is consumer-driven — call `session.client.resume()` to retry. -*See [Integration guide › Terminal errors](../../../README.md#terminal-errors).* +*See [Integration guide › Terminal errors](../../../../README.md#terminal-errors).* ### Keyboard handling — `ChatActivity.kt` + manifest @@ -317,7 +317,7 @@ ViewCompat.setOnApplyWindowInsetsListener(binding.content) { v, insets -> The list uses a `LinearLayoutManager` with `stackFromEnd = true` so newest content pins to the bottom; a floating "New messages" pill (a `↓` glyph) appears when content arrives while you're scrolled up. -*See [Integration guide › Avatars & keyboard](../../../README.md#avatars--keyboard).* +*See [Integration guide › Avatars & keyboard](../../../../README.md#avatars--keyboard).* ## Avatars @@ -332,5 +332,5 @@ Agent avatars are loaded with [Coil](https://coil-kt.github.io/coil/) — `image --- - **Compose counterpart:** [`examples/compose/02-standard/`](../../compose/02-standard/) -- **SDK reference:** root [README → Integration guide](../../../README.md#integration-guide) -- **Install the package:** root [README → Install](../../../README.md#install) +- **SDK reference:** root [README → Integration guide](../../../../README.md#integration-guide) +- **Install the package:** root [README → Install](../../../../README.md#install) diff --git a/examples/views/02-standard/build.gradle.kts b/examples/chat/views/02-standard/build.gradle.kts similarity index 100% rename from examples/views/02-standard/build.gradle.kts rename to examples/chat/views/02-standard/build.gradle.kts diff --git a/examples/views/02-standard/src/androidTest/kotlin/ai/poly/examples/standard/views/StandardViewsFlowTest.kt b/examples/chat/views/02-standard/src/androidTest/kotlin/ai/poly/examples/standard/views/StandardViewsFlowTest.kt similarity index 100% rename from examples/views/02-standard/src/androidTest/kotlin/ai/poly/examples/standard/views/StandardViewsFlowTest.kt rename to examples/chat/views/02-standard/src/androidTest/kotlin/ai/poly/examples/standard/views/StandardViewsFlowTest.kt diff --git a/examples/views/02-standard/src/main/AndroidManifest.xml b/examples/chat/views/02-standard/src/main/AndroidManifest.xml similarity index 100% rename from examples/views/02-standard/src/main/AndroidManifest.xml rename to examples/chat/views/02-standard/src/main/AndroidManifest.xml diff --git a/examples/views/02-standard/src/main/kotlin/ai/poly/examples/standard/views/ChatActivity.kt b/examples/chat/views/02-standard/src/main/kotlin/ai/poly/examples/standard/views/ChatActivity.kt similarity index 100% rename from examples/views/02-standard/src/main/kotlin/ai/poly/examples/standard/views/ChatActivity.kt rename to examples/chat/views/02-standard/src/main/kotlin/ai/poly/examples/standard/views/ChatActivity.kt diff --git a/examples/views/02-standard/src/main/kotlin/ai/poly/examples/standard/views/ChatAdapter.kt b/examples/chat/views/02-standard/src/main/kotlin/ai/poly/examples/standard/views/ChatAdapter.kt similarity index 100% rename from examples/views/02-standard/src/main/kotlin/ai/poly/examples/standard/views/ChatAdapter.kt rename to examples/chat/views/02-standard/src/main/kotlin/ai/poly/examples/standard/views/ChatAdapter.kt diff --git a/examples/views/02-standard/src/main/kotlin/ai/poly/examples/standard/views/Palette.kt b/examples/chat/views/02-standard/src/main/kotlin/ai/poly/examples/standard/views/Palette.kt similarity index 100% rename from examples/views/02-standard/src/main/kotlin/ai/poly/examples/standard/views/Palette.kt rename to examples/chat/views/02-standard/src/main/kotlin/ai/poly/examples/standard/views/Palette.kt diff --git a/examples/views/02-standard/src/main/kotlin/ai/poly/examples/standard/views/StandardApplication.kt b/examples/chat/views/02-standard/src/main/kotlin/ai/poly/examples/standard/views/StandardApplication.kt similarity index 100% rename from examples/views/02-standard/src/main/kotlin/ai/poly/examples/standard/views/StandardApplication.kt rename to examples/chat/views/02-standard/src/main/kotlin/ai/poly/examples/standard/views/StandardApplication.kt diff --git a/examples/views/02-standard/src/main/res/drawable/avatar_placeholder.xml b/examples/chat/views/02-standard/src/main/res/drawable/avatar_placeholder.xml similarity index 100% rename from examples/views/02-standard/src/main/res/drawable/avatar_placeholder.xml rename to examples/chat/views/02-standard/src/main/res/drawable/avatar_placeholder.xml diff --git a/examples/views/02-standard/src/main/res/drawable/bg_failure_card.xml b/examples/chat/views/02-standard/src/main/res/drawable/bg_failure_card.xml similarity index 100% rename from examples/views/02-standard/src/main/res/drawable/bg_failure_card.xml rename to examples/chat/views/02-standard/src/main/res/drawable/bg_failure_card.xml diff --git a/examples/views/02-standard/src/main/res/drawable/bg_input_field.xml b/examples/chat/views/02-standard/src/main/res/drawable/bg_input_field.xml similarity index 100% rename from examples/views/02-standard/src/main/res/drawable/bg_input_field.xml rename to examples/chat/views/02-standard/src/main/res/drawable/bg_input_field.xml diff --git a/examples/views/02-standard/src/main/res/drawable/bg_pill_new_messages.xml b/examples/chat/views/02-standard/src/main/res/drawable/bg_pill_new_messages.xml similarity index 100% rename from examples/views/02-standard/src/main/res/drawable/bg_pill_new_messages.xml rename to examples/chat/views/02-standard/src/main/res/drawable/bg_pill_new_messages.xml diff --git a/examples/views/02-standard/src/main/res/drawable/bg_typing_bubble.xml b/examples/chat/views/02-standard/src/main/res/drawable/bg_typing_bubble.xml similarity index 100% rename from examples/views/02-standard/src/main/res/drawable/bg_typing_bubble.xml rename to examples/chat/views/02-standard/src/main/res/drawable/bg_typing_bubble.xml diff --git a/examples/views/02-standard/src/main/res/drawable/ic_arrow_upward.xml b/examples/chat/views/02-standard/src/main/res/drawable/ic_arrow_upward.xml similarity index 100% rename from examples/views/02-standard/src/main/res/drawable/ic_arrow_upward.xml rename to examples/chat/views/02-standard/src/main/res/drawable/ic_arrow_upward.xml diff --git a/examples/views/02-standard/src/main/res/drawable/typing_dot.xml b/examples/chat/views/02-standard/src/main/res/drawable/typing_dot.xml similarity index 100% rename from examples/views/02-standard/src/main/res/drawable/typing_dot.xml rename to examples/chat/views/02-standard/src/main/res/drawable/typing_dot.xml diff --git a/examples/views/02-standard/src/main/res/layout/activity_chat.xml b/examples/chat/views/02-standard/src/main/res/layout/activity_chat.xml similarity index 100% rename from examples/views/02-standard/src/main/res/layout/activity_chat.xml rename to examples/chat/views/02-standard/src/main/res/layout/activity_chat.xml diff --git a/examples/views/02-standard/src/main/res/layout/item_message.xml b/examples/chat/views/02-standard/src/main/res/layout/item_message.xml similarity index 100% rename from examples/views/02-standard/src/main/res/layout/item_message.xml rename to examples/chat/views/02-standard/src/main/res/layout/item_message.xml diff --git a/examples/views/02-standard/src/main/res/layout/item_suggestions.xml b/examples/chat/views/02-standard/src/main/res/layout/item_suggestions.xml similarity index 100% rename from examples/views/02-standard/src/main/res/layout/item_suggestions.xml rename to examples/chat/views/02-standard/src/main/res/layout/item_suggestions.xml diff --git a/examples/views/02-standard/src/main/res/layout/item_typing.xml b/examples/chat/views/02-standard/src/main/res/layout/item_typing.xml similarity index 100% rename from examples/views/02-standard/src/main/res/layout/item_typing.xml rename to examples/chat/views/02-standard/src/main/res/layout/item_typing.xml diff --git a/examples/views/02-standard/src/main/res/values/strings.xml b/examples/chat/views/02-standard/src/main/res/values/strings.xml similarity index 100% rename from examples/views/02-standard/src/main/res/values/strings.xml rename to examples/chat/views/02-standard/src/main/res/values/strings.xml diff --git a/examples/views/02-standard/src/main/res/values/themes.xml b/examples/chat/views/02-standard/src/main/res/values/themes.xml similarity index 100% rename from examples/views/02-standard/src/main/res/values/themes.xml rename to examples/chat/views/02-standard/src/main/res/values/themes.xml diff --git a/examples/views/03-richcontent/README.md b/examples/chat/views/03-richcontent/README.md similarity index 95% rename from examples/views/03-richcontent/README.md rename to examples/chat/views/03-richcontent/README.md index 622d021..938fcaf 100644 --- a/examples/views/03-richcontent/README.md +++ b/examples/chat/views/03-richcontent/README.md @@ -25,7 +25,7 @@ Then launch `ChatActivity`. Set your API key in `src/main/kotlin/ai/poly/example **The SDK decodes the data; it never fetches bytes or dials phones.** You own image loading, caching, retry, link-opening, and the `tel:` URI. This example does all of that with Coil + `Intent`s. -The SDK invariants behind each pattern are in the root README's [Integration guide](../../../README.md#integration-guide). +The SDK invariants behind each pattern are in the root README's [Integration guide](../../../../README.md#integration-guide). ## How it works @@ -58,7 +58,7 @@ bindCallActions(m.callActions) **Under the hood:** the SDK decodes the agent's `attachments` array and groups them onto the same `AgentMessage` as the text. No background fetch happens — `makeCard` hands each `previewImageUrl ?: contentUrl` to a `RetryableImageView` (`RetryableImageView.kt`), which loads via Coil with tap-to-retry + a 5-second auto-retry. -*See [Integration guide › Attachments, link cards & call buttons](../../../README.md#attachments-link-cards--call-buttons).* +*See [Integration guide › Attachments, link cards & call buttons](../../../../README.md#attachments-link-cards--call-buttons).* ### Render URL link cards — same `attachments`, filtered by `.URL` @@ -77,7 +77,7 @@ bindCarousel(b.urlCarousel, b.urlStack, m.attachments.filter { it.contentType == **Under the hood:** same decoded `Attachment` data — the SDK hands you the URL + preview + title; the card lays the preview image on top of the title + CTA, and the whole card opens `contentUrl` on tap. -*See [Integration guide › Attachments, link cards & call buttons](../../../README.md#attachments-link-cards--call-buttons).* +*See [Integration guide › Attachments, link cards & call buttons](../../../../README.md#attachments-link-cards--call-buttons).* ### Render `tel:` call buttons — `AgentMessage.callActions` @@ -97,7 +97,7 @@ context.startActivity(Intent(Intent.ACTION_DIAL, Uri.parse("tel:$digits"))) **Under the hood:** the SDK delivers `ChatCallAction` as decoded data — `title` + `contactNumber`. Dialling is your code: sanitise the number (digits + leading `+`), build `tel:`, and `ACTION_DIAL` opens the dialer pre-filled (no `CALL_PHONE` permission needed). The label falls back to the number when `title` is empty. -*See [Integration guide › Attachments, link cards & call buttons](../../../README.md#attachments-link-cards--call-buttons).* +*See [Integration guide › Attachments, link cards & call buttons](../../../../README.md#attachments-link-cards--call-buttons).* ### Render Markdown (tappable links) — `AgentMessage.text` @@ -124,7 +124,7 @@ b.bubble.visibility = if (m.text.isEmpty()) View.GONE else View.VISIBLE > **Why normalize HTML?** Agent content is authored once and rendered on both web and mobile. The web widget pipes it through `marked` + DOMPurify, so a reply can reach mobile with literal `
` tags. `normalizeAgentHtml` mirrors that allow-list so the bubble matches the web. The minimal [`01-Hello`](../01-hello/) / [`02-Standard`](../02-standard/) examples skip this (plain text), so they show `
` raw. -*See [Integration guide › Rich text & links](../../../README.md#rich-text--links).* +*See [Integration guide › Rich text & links](../../../../README.md#rich-text--links).* ### Bubble layout — compose everything @@ -164,7 +164,7 @@ messageNotifier.start(lifecycleScope, lifecycle, session, notificationPolicy) `start(...)` creates a notification channel and runs `repeatOnLifecycle(CREATED) { session.client.events.collect { … } }` — gated on `CREATED` (not `STARTED`) so a reply that lands while the chat is backgrounded can still raise a banner. It maps completed `AgentMessage` / `LiveAgentMessage` events to a banner, checks whether the chat is currently on screen (`lifecycle.currentState.isAtLeast(STARTED)`) and — for `WHEN_BACKGROUNDED` — stays quiet if it is, and skips ids already in the persisted (`SharedPreferences`) store so resume/relaunch replays don't re-fire. -*See [Integration guide › In-app new-message alerts (local-only workaround)](../../../README.md#in-app-new-message-alerts-local-only-workaround).* +*See [Integration guide › In-app new-message alerts (local-only workaround)](../../../../README.md#in-app-new-message-alerts-local-only-workaround).* ## What this example skips @@ -174,5 +174,5 @@ messageNotifier.start(lifecycleScope, lifecycle, session, notificationPolicy) --- - **Compose counterpart:** [`examples/compose/03-richcontent/`](../../compose/03-richcontent/) -- **SDK reference:** root [README → Integration guide](../../../README.md#integration-guide) -- **Install the package:** root [README → Install](../../../README.md#install) +- **SDK reference:** root [README → Integration guide](../../../../README.md#integration-guide) +- **Install the package:** root [README → Install](../../../../README.md#install) diff --git a/examples/views/03-richcontent/build.gradle.kts b/examples/chat/views/03-richcontent/build.gradle.kts similarity index 100% rename from examples/views/03-richcontent/build.gradle.kts rename to examples/chat/views/03-richcontent/build.gradle.kts diff --git a/examples/views/03-richcontent/src/androidTest/kotlin/ai/poly/examples/richcontent/views/NotificationBannerTest.kt b/examples/chat/views/03-richcontent/src/androidTest/kotlin/ai/poly/examples/richcontent/views/NotificationBannerTest.kt similarity index 100% rename from examples/views/03-richcontent/src/androidTest/kotlin/ai/poly/examples/richcontent/views/NotificationBannerTest.kt rename to examples/chat/views/03-richcontent/src/androidTest/kotlin/ai/poly/examples/richcontent/views/NotificationBannerTest.kt diff --git a/examples/views/03-richcontent/src/androidTest/kotlin/ai/poly/examples/richcontent/views/RichContentViewsFlowTest.kt b/examples/chat/views/03-richcontent/src/androidTest/kotlin/ai/poly/examples/richcontent/views/RichContentViewsFlowTest.kt similarity index 100% rename from examples/views/03-richcontent/src/androidTest/kotlin/ai/poly/examples/richcontent/views/RichContentViewsFlowTest.kt rename to examples/chat/views/03-richcontent/src/androidTest/kotlin/ai/poly/examples/richcontent/views/RichContentViewsFlowTest.kt diff --git a/examples/views/03-richcontent/src/main/AndroidManifest.xml b/examples/chat/views/03-richcontent/src/main/AndroidManifest.xml similarity index 100% rename from examples/views/03-richcontent/src/main/AndroidManifest.xml rename to examples/chat/views/03-richcontent/src/main/AndroidManifest.xml diff --git a/examples/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/ChatActivity.kt b/examples/chat/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/ChatActivity.kt similarity index 100% rename from examples/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/ChatActivity.kt rename to examples/chat/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/ChatActivity.kt diff --git a/examples/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/ChatAdapter.kt b/examples/chat/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/ChatAdapter.kt similarity index 100% rename from examples/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/ChatAdapter.kt rename to examples/chat/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/ChatAdapter.kt diff --git a/examples/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/NewMessageNotifier.kt b/examples/chat/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/NewMessageNotifier.kt similarity index 100% rename from examples/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/NewMessageNotifier.kt rename to examples/chat/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/NewMessageNotifier.kt diff --git a/examples/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/Palette.kt b/examples/chat/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/Palette.kt similarity index 100% rename from examples/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/Palette.kt rename to examples/chat/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/Palette.kt diff --git a/examples/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/RetryableImageView.kt b/examples/chat/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/RetryableImageView.kt similarity index 100% rename from examples/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/RetryableImageView.kt rename to examples/chat/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/RetryableImageView.kt diff --git a/examples/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/RichContentApplication.kt b/examples/chat/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/RichContentApplication.kt similarity index 100% rename from examples/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/RichContentApplication.kt rename to examples/chat/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/RichContentApplication.kt diff --git a/examples/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/RichTextSpans.kt b/examples/chat/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/RichTextSpans.kt similarity index 100% rename from examples/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/RichTextSpans.kt rename to examples/chat/views/03-richcontent/src/main/kotlin/ai/poly/examples/richcontent/views/RichTextSpans.kt diff --git a/examples/views/03-richcontent/src/main/res/drawable/avatar_placeholder.xml b/examples/chat/views/03-richcontent/src/main/res/drawable/avatar_placeholder.xml similarity index 100% rename from examples/views/03-richcontent/src/main/res/drawable/avatar_placeholder.xml rename to examples/chat/views/03-richcontent/src/main/res/drawable/avatar_placeholder.xml diff --git a/examples/views/03-richcontent/src/main/res/drawable/bg_failure_card.xml b/examples/chat/views/03-richcontent/src/main/res/drawable/bg_failure_card.xml similarity index 100% rename from examples/views/03-richcontent/src/main/res/drawable/bg_failure_card.xml rename to examples/chat/views/03-richcontent/src/main/res/drawable/bg_failure_card.xml diff --git a/examples/views/03-richcontent/src/main/res/drawable/bg_input_field.xml b/examples/chat/views/03-richcontent/src/main/res/drawable/bg_input_field.xml similarity index 100% rename from examples/views/03-richcontent/src/main/res/drawable/bg_input_field.xml rename to examples/chat/views/03-richcontent/src/main/res/drawable/bg_input_field.xml diff --git a/examples/views/03-richcontent/src/main/res/drawable/bg_pill_new_messages.xml b/examples/chat/views/03-richcontent/src/main/res/drawable/bg_pill_new_messages.xml similarity index 100% rename from examples/views/03-richcontent/src/main/res/drawable/bg_pill_new_messages.xml rename to examples/chat/views/03-richcontent/src/main/res/drawable/bg_pill_new_messages.xml diff --git a/examples/views/03-richcontent/src/main/res/drawable/bg_typing_bubble.xml b/examples/chat/views/03-richcontent/src/main/res/drawable/bg_typing_bubble.xml similarity index 100% rename from examples/views/03-richcontent/src/main/res/drawable/bg_typing_bubble.xml rename to examples/chat/views/03-richcontent/src/main/res/drawable/bg_typing_bubble.xml diff --git a/examples/views/03-richcontent/src/main/res/drawable/ic_arrow_upward.xml b/examples/chat/views/03-richcontent/src/main/res/drawable/ic_arrow_upward.xml similarity index 100% rename from examples/views/03-richcontent/src/main/res/drawable/ic_arrow_upward.xml rename to examples/chat/views/03-richcontent/src/main/res/drawable/ic_arrow_upward.xml diff --git a/examples/views/03-richcontent/src/main/res/drawable/ic_call.xml b/examples/chat/views/03-richcontent/src/main/res/drawable/ic_call.xml similarity index 100% rename from examples/views/03-richcontent/src/main/res/drawable/ic_call.xml rename to examples/chat/views/03-richcontent/src/main/res/drawable/ic_call.xml diff --git a/examples/views/03-richcontent/src/main/res/drawable/ic_image.xml b/examples/chat/views/03-richcontent/src/main/res/drawable/ic_image.xml similarity index 100% rename from examples/views/03-richcontent/src/main/res/drawable/ic_image.xml rename to examples/chat/views/03-richcontent/src/main/res/drawable/ic_image.xml diff --git a/examples/views/03-richcontent/src/main/res/drawable/typing_dot.xml b/examples/chat/views/03-richcontent/src/main/res/drawable/typing_dot.xml similarity index 100% rename from examples/views/03-richcontent/src/main/res/drawable/typing_dot.xml rename to examples/chat/views/03-richcontent/src/main/res/drawable/typing_dot.xml diff --git a/examples/views/03-richcontent/src/main/res/layout/activity_chat.xml b/examples/chat/views/03-richcontent/src/main/res/layout/activity_chat.xml similarity index 100% rename from examples/views/03-richcontent/src/main/res/layout/activity_chat.xml rename to examples/chat/views/03-richcontent/src/main/res/layout/activity_chat.xml diff --git a/examples/views/03-richcontent/src/main/res/layout/item_message.xml b/examples/chat/views/03-richcontent/src/main/res/layout/item_message.xml similarity index 100% rename from examples/views/03-richcontent/src/main/res/layout/item_message.xml rename to examples/chat/views/03-richcontent/src/main/res/layout/item_message.xml diff --git a/examples/views/03-richcontent/src/main/res/layout/item_suggestions.xml b/examples/chat/views/03-richcontent/src/main/res/layout/item_suggestions.xml similarity index 100% rename from examples/views/03-richcontent/src/main/res/layout/item_suggestions.xml rename to examples/chat/views/03-richcontent/src/main/res/layout/item_suggestions.xml diff --git a/examples/views/03-richcontent/src/main/res/layout/item_typing.xml b/examples/chat/views/03-richcontent/src/main/res/layout/item_typing.xml similarity index 100% rename from examples/views/03-richcontent/src/main/res/layout/item_typing.xml rename to examples/chat/views/03-richcontent/src/main/res/layout/item_typing.xml diff --git a/examples/views/03-richcontent/src/main/res/values/strings.xml b/examples/chat/views/03-richcontent/src/main/res/values/strings.xml similarity index 100% rename from examples/views/03-richcontent/src/main/res/values/strings.xml rename to examples/chat/views/03-richcontent/src/main/res/values/strings.xml diff --git a/examples/views/03-richcontent/src/main/res/values/themes.xml b/examples/chat/views/03-richcontent/src/main/res/values/themes.xml similarity index 100% rename from examples/views/03-richcontent/src/main/res/values/themes.xml rename to examples/chat/views/03-richcontent/src/main/res/values/themes.xml diff --git a/examples/views/04-resilience/README.md b/examples/chat/views/04-resilience/README.md similarity index 86% rename from examples/views/04-resilience/README.md rename to examples/chat/views/04-resilience/README.md index ba1ddcc..b876571 100644 --- a/examples/views/04-resilience/README.md +++ b/examples/chat/views/04-resilience/README.md @@ -22,7 +22,7 @@ Then launch `ChatActivity`. Set your API key in `src/main/kotlin/ai/poly/example - Replace the entire chat surface with a full-screen retry screen when `session.failureReason` is non-null - Recover via `session.client.resume()` from the terminal screen — re-establishes the dead socket against the **same** session, so the transcript survives (see the note below) -The SDK invariants behind each pattern are in the root README's [Integration guide](../../../README.md#integration-guide). +The SDK invariants behind each pattern are in the root README's [Integration guide](../../../../README.md#integration-guide). ## How it works @@ -65,7 +65,7 @@ launch { session.connection.collect { status -> **Under the hood:** when the OS reports no usable default network, the SDK's reachability watcher drops its dead socket and `session.connection` flips to `Reconnecting`. The two banners measure different things — the offline pill is the device, the reconnect pill is the socket — so it's meaningful to show both. -*See [Integration guide › Connection & reconnect](../../../README.md#connection--reconnect).* +*See [Integration guide › Connection & reconnect](../../../../README.md#connection--reconnect).* ### Loading skeleton — `LoadingSkeletonView.kt` @@ -82,11 +82,11 @@ private fun updateSkeleton() { } ``` -**Under the hood:** `isReady` stays `false` until the REST + WebSocket handshake completes. On a mid-session reconnect, `messages` is already in memory while `isReady` drops to `false` — the `messages.isEmpty()` half of the gate is what skips the skeleton there. On a cross-launch resume the SDK persists only the session id/token (in `SharedPreferences`), not the messages — so at cold launch `messages` is empty and `isReady` is `false`, and the skeleton shows until the socket opens. The restored transcript is replayed by the server after `isReady` flips, which clears the gate. This resume only works inside the session-resume window (the SDK's ~10-min session timeout, matching the backend's WebSocket idle timeout — see [Starting, resuming & ending a session](../../../README.md#starting-resuming--ending-a-session)); past it, `chat()` starts fresh and the skeleton clears into an empty chat instead. +**Under the hood:** `isReady` stays `false` until the REST + WebSocket handshake completes. On a mid-session reconnect, `messages` is already in memory while `isReady` drops to `false` — the `messages.isEmpty()` half of the gate is what skips the skeleton there. On a cross-launch resume the SDK persists only the session id/token (in `SharedPreferences`), not the messages — so at cold launch `messages` is empty and `isReady` is `false`, and the skeleton shows until the socket opens. The restored transcript is replayed by the server after `isReady` flips, which clears the gate. This resume only works inside the session-resume window (the SDK's ~10-min session timeout, matching the backend's WebSocket idle timeout — see [Starting, resuming & ending a session](../../../../README.md#starting-resuming--ending-a-session)); past it, `chat()` starts fresh and the skeleton clears into an empty chat instead. -> **Streaming:** agent replies grow token-by-token by default (`Configuration.streamingEnabled = true` — ChatGPT-style). Set `streamingEnabled(false)` to render completed bubbles only. See the root README's [*Streaming*](../../../README.md#streaming) section and [`07-Playground`](../07-playground/) for a live toggle. +> **Streaming:** agent replies grow token-by-token by default (`Configuration.streamingEnabled = true` — ChatGPT-style). Set `streamingEnabled(false)` to render completed bubbles only. See the root README's [*Streaming*](../../../../README.md#streaming) section and [`07-Playground`](../07-playground/) for a live toggle. -*See [Integration guide › Loading & empty states](../../../README.md#loading--empty-states).* +*See [Integration guide › Loading & empty states](../../../../README.md#loading--empty-states).* ### Terminal error screen — the `failureOverlay` @@ -107,9 +107,9 @@ binding.reconnect.setOnClickListener { lifecycleScope.launch { runCatching { ses **Under the hood:** `failureReason` is set only after the SDK's exponential-backoff reconnect ladder is exhausted, or on a terminal session error. Transient blips just flip `connection` to `Reconnecting` and back — that's why this screen is full-screen and gated on `failureReason`. -> **`resume()` vs `startNewSession()` here:** `resume()` re-establishes a terminally-`Failed` socket against the **same** session (resetting the reconnect budget) so the existing transcript is kept — this example uses it deliberately to show same-session recovery. The root README's [resume() row](../../../README.md#starting-resuming--ending-a-session) recommends `startNewSession()` (or a fresh `chat()`/`start()`) for a generic user-facing "Try Again" when you'd rather hand the user a clean conversation. Pick whichever matches your product; [`06-FullReference`](../06-fullreference/) shows both on a dedicated connect screen. +> **`resume()` vs `startNewSession()` here:** `resume()` re-establishes a terminally-`Failed` socket against the **same** session (resetting the reconnect budget) so the existing transcript is kept — this example uses it deliberately to show same-session recovery. The root README's [resume() row](../../../../README.md#starting-resuming--ending-a-session) recommends `startNewSession()` (or a fresh `chat()`/`start()`) for a generic user-facing "Try Again" when you'd rather hand the user a clean conversation. Pick whichever matches your product; [`06-FullReference`](../06-fullreference/) shows both on a dedicated connect screen. -*See [Integration guide › Terminal errors](../../../README.md#terminal-errors).* +*See [Integration guide › Terminal errors](../../../../README.md#terminal-errors).* ## Try this on the emulator @@ -117,7 +117,7 @@ binding.reconnect.setOnClickListener { lifecycleScope.launch { runCatching { ses |---|---| | Toggle airplane mode mid-chat (`adb shell cmd connectivity airplane-mode enable`) | Red offline banner above a yellow reconnect banner; messages stay composable; toggle off → both clear | | Launch with the network off | Loading skeleton (pulsing rows) → eventually the full-screen "Couldn't connect" → tap Reconnect once back online | -| Cold launch with a stored session inside the resume window | Brief skeleton while the socket reconnects → server replays the restored transcript (the window is the SDK's session-resume timeout, ~10 min — it matches the backend's WebSocket idle timeout; see [Starting, resuming & ending a session](../../../README.md#starting-resuming--ending-a-session)) | +| Cold launch with a stored session inside the resume window | Brief skeleton while the socket reconnects → server replays the restored transcript (the window is the SDK's session-resume timeout, ~10 min — it matches the backend's WebSocket idle timeout; see [Starting, resuming & ending a session](../../../../README.md#starting-resuming--ending-a-session)) | ## What this example skips @@ -128,5 +128,5 @@ binding.reconnect.setOnClickListener { lifecycleScope.launch { runCatching { ses --- - **Compose counterpart:** [`examples/compose/04-resilience/`](../../compose/04-resilience/) -- **SDK reference:** root [README → Integration guide](../../../README.md#integration-guide) -- **Install the package:** root [README → Install](../../../README.md#install) +- **SDK reference:** root [README → Integration guide](../../../../README.md#integration-guide) +- **Install the package:** root [README → Install](../../../../README.md#install) diff --git a/examples/views/04-resilience/build.gradle.kts b/examples/chat/views/04-resilience/build.gradle.kts similarity index 100% rename from examples/views/04-resilience/build.gradle.kts rename to examples/chat/views/04-resilience/build.gradle.kts diff --git a/examples/views/04-resilience/src/androidTest/kotlin/ai/poly/examples/resilience/views/ResilienceViewsFlowTest.kt b/examples/chat/views/04-resilience/src/androidTest/kotlin/ai/poly/examples/resilience/views/ResilienceViewsFlowTest.kt similarity index 100% rename from examples/views/04-resilience/src/androidTest/kotlin/ai/poly/examples/resilience/views/ResilienceViewsFlowTest.kt rename to examples/chat/views/04-resilience/src/androidTest/kotlin/ai/poly/examples/resilience/views/ResilienceViewsFlowTest.kt diff --git a/examples/views/04-resilience/src/main/AndroidManifest.xml b/examples/chat/views/04-resilience/src/main/AndroidManifest.xml similarity index 100% rename from examples/views/04-resilience/src/main/AndroidManifest.xml rename to examples/chat/views/04-resilience/src/main/AndroidManifest.xml diff --git a/examples/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/ChatActivity.kt b/examples/chat/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/ChatActivity.kt similarity index 100% rename from examples/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/ChatActivity.kt rename to examples/chat/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/ChatActivity.kt diff --git a/examples/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/ChatAdapter.kt b/examples/chat/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/ChatAdapter.kt similarity index 100% rename from examples/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/ChatAdapter.kt rename to examples/chat/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/ChatAdapter.kt diff --git a/examples/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/LoadingSkeletonView.kt b/examples/chat/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/LoadingSkeletonView.kt similarity index 100% rename from examples/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/LoadingSkeletonView.kt rename to examples/chat/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/LoadingSkeletonView.kt diff --git a/examples/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/NetworkMonitor.kt b/examples/chat/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/NetworkMonitor.kt similarity index 100% rename from examples/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/NetworkMonitor.kt rename to examples/chat/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/NetworkMonitor.kt diff --git a/examples/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/Palette.kt b/examples/chat/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/Palette.kt similarity index 100% rename from examples/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/Palette.kt rename to examples/chat/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/Palette.kt diff --git a/examples/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/ResilienceApplication.kt b/examples/chat/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/ResilienceApplication.kt similarity index 100% rename from examples/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/ResilienceApplication.kt rename to examples/chat/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/ResilienceApplication.kt diff --git a/examples/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/RetryableImageView.kt b/examples/chat/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/RetryableImageView.kt similarity index 100% rename from examples/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/RetryableImageView.kt rename to examples/chat/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/RetryableImageView.kt diff --git a/examples/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/RichTextSpans.kt b/examples/chat/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/RichTextSpans.kt similarity index 100% rename from examples/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/RichTextSpans.kt rename to examples/chat/views/04-resilience/src/main/kotlin/ai/poly/examples/resilience/views/RichTextSpans.kt diff --git a/examples/views/04-resilience/src/main/res/drawable/avatar_placeholder.xml b/examples/chat/views/04-resilience/src/main/res/drawable/avatar_placeholder.xml similarity index 100% rename from examples/views/04-resilience/src/main/res/drawable/avatar_placeholder.xml rename to examples/chat/views/04-resilience/src/main/res/drawable/avatar_placeholder.xml diff --git a/examples/views/04-resilience/src/main/res/drawable/bg_failure_card.xml b/examples/chat/views/04-resilience/src/main/res/drawable/bg_failure_card.xml similarity index 100% rename from examples/views/04-resilience/src/main/res/drawable/bg_failure_card.xml rename to examples/chat/views/04-resilience/src/main/res/drawable/bg_failure_card.xml diff --git a/examples/views/04-resilience/src/main/res/drawable/bg_input_field.xml b/examples/chat/views/04-resilience/src/main/res/drawable/bg_input_field.xml similarity index 100% rename from examples/views/04-resilience/src/main/res/drawable/bg_input_field.xml rename to examples/chat/views/04-resilience/src/main/res/drawable/bg_input_field.xml diff --git a/examples/views/04-resilience/src/main/res/drawable/bg_pill_new_messages.xml b/examples/chat/views/04-resilience/src/main/res/drawable/bg_pill_new_messages.xml similarity index 100% rename from examples/views/04-resilience/src/main/res/drawable/bg_pill_new_messages.xml rename to examples/chat/views/04-resilience/src/main/res/drawable/bg_pill_new_messages.xml diff --git a/examples/views/04-resilience/src/main/res/drawable/bg_typing_bubble.xml b/examples/chat/views/04-resilience/src/main/res/drawable/bg_typing_bubble.xml similarity index 100% rename from examples/views/04-resilience/src/main/res/drawable/bg_typing_bubble.xml rename to examples/chat/views/04-resilience/src/main/res/drawable/bg_typing_bubble.xml diff --git a/examples/views/04-resilience/src/main/res/drawable/ic_arrow_upward.xml b/examples/chat/views/04-resilience/src/main/res/drawable/ic_arrow_upward.xml similarity index 100% rename from examples/views/04-resilience/src/main/res/drawable/ic_arrow_upward.xml rename to examples/chat/views/04-resilience/src/main/res/drawable/ic_arrow_upward.xml diff --git a/examples/views/04-resilience/src/main/res/drawable/ic_call.xml b/examples/chat/views/04-resilience/src/main/res/drawable/ic_call.xml similarity index 100% rename from examples/views/04-resilience/src/main/res/drawable/ic_call.xml rename to examples/chat/views/04-resilience/src/main/res/drawable/ic_call.xml diff --git a/examples/views/04-resilience/src/main/res/drawable/ic_error_triangle.xml b/examples/chat/views/04-resilience/src/main/res/drawable/ic_error_triangle.xml similarity index 100% rename from examples/views/04-resilience/src/main/res/drawable/ic_error_triangle.xml rename to examples/chat/views/04-resilience/src/main/res/drawable/ic_error_triangle.xml diff --git a/examples/views/04-resilience/src/main/res/drawable/ic_image.xml b/examples/chat/views/04-resilience/src/main/res/drawable/ic_image.xml similarity index 100% rename from examples/views/04-resilience/src/main/res/drawable/ic_image.xml rename to examples/chat/views/04-resilience/src/main/res/drawable/ic_image.xml diff --git a/examples/views/04-resilience/src/main/res/drawable/ic_wifi_off.xml b/examples/chat/views/04-resilience/src/main/res/drawable/ic_wifi_off.xml similarity index 100% rename from examples/views/04-resilience/src/main/res/drawable/ic_wifi_off.xml rename to examples/chat/views/04-resilience/src/main/res/drawable/ic_wifi_off.xml diff --git a/examples/views/04-resilience/src/main/res/drawable/typing_dot.xml b/examples/chat/views/04-resilience/src/main/res/drawable/typing_dot.xml similarity index 100% rename from examples/views/04-resilience/src/main/res/drawable/typing_dot.xml rename to examples/chat/views/04-resilience/src/main/res/drawable/typing_dot.xml diff --git a/examples/views/04-resilience/src/main/res/layout/activity_chat.xml b/examples/chat/views/04-resilience/src/main/res/layout/activity_chat.xml similarity index 100% rename from examples/views/04-resilience/src/main/res/layout/activity_chat.xml rename to examples/chat/views/04-resilience/src/main/res/layout/activity_chat.xml diff --git a/examples/views/04-resilience/src/main/res/layout/item_message.xml b/examples/chat/views/04-resilience/src/main/res/layout/item_message.xml similarity index 100% rename from examples/views/04-resilience/src/main/res/layout/item_message.xml rename to examples/chat/views/04-resilience/src/main/res/layout/item_message.xml diff --git a/examples/views/04-resilience/src/main/res/layout/item_suggestions.xml b/examples/chat/views/04-resilience/src/main/res/layout/item_suggestions.xml similarity index 100% rename from examples/views/04-resilience/src/main/res/layout/item_suggestions.xml rename to examples/chat/views/04-resilience/src/main/res/layout/item_suggestions.xml diff --git a/examples/views/04-resilience/src/main/res/layout/item_typing.xml b/examples/chat/views/04-resilience/src/main/res/layout/item_typing.xml similarity index 100% rename from examples/views/04-resilience/src/main/res/layout/item_typing.xml rename to examples/chat/views/04-resilience/src/main/res/layout/item_typing.xml diff --git a/examples/views/04-resilience/src/main/res/values/strings.xml b/examples/chat/views/04-resilience/src/main/res/values/strings.xml similarity index 100% rename from examples/views/04-resilience/src/main/res/values/strings.xml rename to examples/chat/views/04-resilience/src/main/res/values/strings.xml diff --git a/examples/views/04-resilience/src/main/res/values/themes.xml b/examples/chat/views/04-resilience/src/main/res/values/themes.xml similarity index 100% rename from examples/views/04-resilience/src/main/res/values/themes.xml rename to examples/chat/views/04-resilience/src/main/res/values/themes.xml diff --git a/examples/views/05-handoff/README.md b/examples/chat/views/05-handoff/README.md similarity index 94% rename from examples/views/05-handoff/README.md rename to examples/chat/views/05-handoff/README.md index 8fbe283..361c19e 100644 --- a/examples/views/05-handoff/README.md +++ b/examples/chat/views/05-handoff/README.md @@ -23,7 +23,7 @@ Then launch `ChatActivity`. Set your API key in `src/main/kotlin/ai/poly/example - Let `LiveAgentLeft` flip `session.hasEnded` naturally so the existing chat-ended footer takes over - Split failures: terminal errors (auth / config / dead session) get a full-bleed "Something went wrong" screen with **Start New Chat**; reconnect exhaustion gets a centered "Connection lost" card with **Reconnect** -The SDK invariants behind each pattern are in the root README's [Integration guide](../../../README.md#integration-guide). +The SDK invariants behind each pattern are in the root README's [Integration guide](../../../../README.md#integration-guide). ## How it works @@ -61,7 +61,7 @@ private fun systemText(event: SystemEvent): String = when (event) { **Under the hood:** the SDK converts every handoff transition — agent-triggered handoff, queue status, accepted / failed / timeout, live-agent joined / left — into a `ChatMessage.System` appended to `session.messages`. They interleave with `User` / `Agent` bubbles in the timeline, so you only render the `System` branch and the order comes out right for free. -*See [Integration guide › Live agent handoff](../../../README.md#live-agent-handoff).* +*See [Integration guide › Live agent handoff](../../../../README.md#live-agent-handoff).* ### Live-agent bubble styling — `ChatAdapter.kt` @@ -92,11 +92,11 @@ b.bubble.background = rounded(if (isLive) Palette.systemTeal18 else Palette.syst **Under the hood:** the SDK normalises live-agent replies into the same `AgentMessage` shape as Poly replies — only `agentKind` and (usually) `avatarUrl` / `agentName` differ. Live-agent typing reuses `session.isAgentTyping`, so the typing indicator works during handoff with no extra wiring. -> **Streaming:** agent replies grow token-by-token by default (`Configuration.streamingEnabled = true` — ChatGPT-style). Live-agent messages flow through the same path, so streaming works for them too. See the root README's [*Streaming*](../../../README.md#streaming) section and [`07-Playground/`](../07-playground/) for a live toggle. +> **Streaming:** agent replies grow token-by-token by default (`Configuration.streamingEnabled = true` — ChatGPT-style). Live-agent messages flow through the same path, so streaming works for them too. See the root README's [*Streaming*](../../../../README.md#streaming) section and [`07-Playground/`](../07-playground/) for a live toggle. > Reminder from `03-RichContent`: set `movementMethod = LinkMovementMethod.getInstance()` on the bubble `TextView` — link spans render styled but ignore taps without it. -*See [Integration guide › Live agent handoff](../../../README.md#live-agent-handoff).* +*See [Integration guide › Live agent handoff](../../../../README.md#live-agent-handoff).* ### Side effects via raw `client.events` — `ChatActivity.kt` @@ -137,7 +137,7 @@ private fun handle(event: MessagingEvent) { **Under the hood:** `client.events` is the same typed, decoded stream the SDK uses internally — subscribing adds no transport overhead, and is the right place for imperative side effects (title, analytics, deep-linking) that aren't a function of `messages`. Anything renderable already comes through `session.messages` / `session.isAgentTyping`, so don't drive the list off this stream. -*See [Integration guide › Live agent handoff](../../../README.md#live-agent-handoff).* +*See [Integration guide › Live agent handoff](../../../../README.md#live-agent-handoff).* ### Terminal vs reconnectable failures — `ChatActivity.kt` @@ -190,5 +190,5 @@ It's terminal — `session.hasEnded` flips true and the existing chat-ended foot --- - **Compose counterpart:** [`../../compose/05-handoff/`](../../compose/05-handoff/) -- **SDK reference:** root [README → Integration guide](../../../README.md#integration-guide) -- **Install the package:** root [README → Install](../../../README.md#install) +- **SDK reference:** root [README → Integration guide](../../../../README.md#integration-guide) +- **Install the package:** root [README → Install](../../../../README.md#install) diff --git a/examples/views/05-handoff/build.gradle.kts b/examples/chat/views/05-handoff/build.gradle.kts similarity index 100% rename from examples/views/05-handoff/build.gradle.kts rename to examples/chat/views/05-handoff/build.gradle.kts diff --git a/examples/views/05-handoff/src/androidTest/kotlin/ai/poly/examples/handoff/views/HandoffViewsFlowTest.kt b/examples/chat/views/05-handoff/src/androidTest/kotlin/ai/poly/examples/handoff/views/HandoffViewsFlowTest.kt similarity index 100% rename from examples/views/05-handoff/src/androidTest/kotlin/ai/poly/examples/handoff/views/HandoffViewsFlowTest.kt rename to examples/chat/views/05-handoff/src/androidTest/kotlin/ai/poly/examples/handoff/views/HandoffViewsFlowTest.kt diff --git a/examples/views/05-handoff/src/main/AndroidManifest.xml b/examples/chat/views/05-handoff/src/main/AndroidManifest.xml similarity index 100% rename from examples/views/05-handoff/src/main/AndroidManifest.xml rename to examples/chat/views/05-handoff/src/main/AndroidManifest.xml diff --git a/examples/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/ChatActivity.kt b/examples/chat/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/ChatActivity.kt similarity index 100% rename from examples/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/ChatActivity.kt rename to examples/chat/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/ChatActivity.kt diff --git a/examples/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/ChatAdapter.kt b/examples/chat/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/ChatAdapter.kt similarity index 100% rename from examples/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/ChatAdapter.kt rename to examples/chat/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/ChatAdapter.kt diff --git a/examples/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/HandoffApplication.kt b/examples/chat/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/HandoffApplication.kt similarity index 100% rename from examples/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/HandoffApplication.kt rename to examples/chat/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/HandoffApplication.kt diff --git a/examples/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/LoadingSkeletonView.kt b/examples/chat/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/LoadingSkeletonView.kt similarity index 100% rename from examples/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/LoadingSkeletonView.kt rename to examples/chat/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/LoadingSkeletonView.kt diff --git a/examples/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/NetworkMonitor.kt b/examples/chat/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/NetworkMonitor.kt similarity index 100% rename from examples/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/NetworkMonitor.kt rename to examples/chat/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/NetworkMonitor.kt diff --git a/examples/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/Palette.kt b/examples/chat/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/Palette.kt similarity index 100% rename from examples/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/Palette.kt rename to examples/chat/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/Palette.kt diff --git a/examples/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/RetryableImageView.kt b/examples/chat/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/RetryableImageView.kt similarity index 100% rename from examples/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/RetryableImageView.kt rename to examples/chat/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/RetryableImageView.kt diff --git a/examples/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/RichTextSpans.kt b/examples/chat/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/RichTextSpans.kt similarity index 100% rename from examples/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/RichTextSpans.kt rename to examples/chat/views/05-handoff/src/main/kotlin/ai/poly/examples/handoff/views/RichTextSpans.kt diff --git a/examples/views/05-handoff/src/main/res/drawable/avatar_placeholder.xml b/examples/chat/views/05-handoff/src/main/res/drawable/avatar_placeholder.xml similarity index 100% rename from examples/views/05-handoff/src/main/res/drawable/avatar_placeholder.xml rename to examples/chat/views/05-handoff/src/main/res/drawable/avatar_placeholder.xml diff --git a/examples/views/05-handoff/src/main/res/drawable/bg_failure_card.xml b/examples/chat/views/05-handoff/src/main/res/drawable/bg_failure_card.xml similarity index 100% rename from examples/views/05-handoff/src/main/res/drawable/bg_failure_card.xml rename to examples/chat/views/05-handoff/src/main/res/drawable/bg_failure_card.xml diff --git a/examples/views/05-handoff/src/main/res/drawable/bg_input_field.xml b/examples/chat/views/05-handoff/src/main/res/drawable/bg_input_field.xml similarity index 100% rename from examples/views/05-handoff/src/main/res/drawable/bg_input_field.xml rename to examples/chat/views/05-handoff/src/main/res/drawable/bg_input_field.xml diff --git a/examples/views/05-handoff/src/main/res/drawable/bg_pill_new_messages.xml b/examples/chat/views/05-handoff/src/main/res/drawable/bg_pill_new_messages.xml similarity index 100% rename from examples/views/05-handoff/src/main/res/drawable/bg_pill_new_messages.xml rename to examples/chat/views/05-handoff/src/main/res/drawable/bg_pill_new_messages.xml diff --git a/examples/views/05-handoff/src/main/res/drawable/bg_typing_bubble.xml b/examples/chat/views/05-handoff/src/main/res/drawable/bg_typing_bubble.xml similarity index 100% rename from examples/views/05-handoff/src/main/res/drawable/bg_typing_bubble.xml rename to examples/chat/views/05-handoff/src/main/res/drawable/bg_typing_bubble.xml diff --git a/examples/views/05-handoff/src/main/res/drawable/ic_arrow_upward.xml b/examples/chat/views/05-handoff/src/main/res/drawable/ic_arrow_upward.xml similarity index 100% rename from examples/views/05-handoff/src/main/res/drawable/ic_arrow_upward.xml rename to examples/chat/views/05-handoff/src/main/res/drawable/ic_arrow_upward.xml diff --git a/examples/views/05-handoff/src/main/res/drawable/ic_call.xml b/examples/chat/views/05-handoff/src/main/res/drawable/ic_call.xml similarity index 100% rename from examples/views/05-handoff/src/main/res/drawable/ic_call.xml rename to examples/chat/views/05-handoff/src/main/res/drawable/ic_call.xml diff --git a/examples/views/05-handoff/src/main/res/drawable/ic_error_triangle.xml b/examples/chat/views/05-handoff/src/main/res/drawable/ic_error_triangle.xml similarity index 100% rename from examples/views/05-handoff/src/main/res/drawable/ic_error_triangle.xml rename to examples/chat/views/05-handoff/src/main/res/drawable/ic_error_triangle.xml diff --git a/examples/views/05-handoff/src/main/res/drawable/ic_image.xml b/examples/chat/views/05-handoff/src/main/res/drawable/ic_image.xml similarity index 100% rename from examples/views/05-handoff/src/main/res/drawable/ic_image.xml rename to examples/chat/views/05-handoff/src/main/res/drawable/ic_image.xml diff --git a/examples/views/05-handoff/src/main/res/drawable/ic_wifi_off.xml b/examples/chat/views/05-handoff/src/main/res/drawable/ic_wifi_off.xml similarity index 100% rename from examples/views/05-handoff/src/main/res/drawable/ic_wifi_off.xml rename to examples/chat/views/05-handoff/src/main/res/drawable/ic_wifi_off.xml diff --git a/examples/views/05-handoff/src/main/res/drawable/typing_dot.xml b/examples/chat/views/05-handoff/src/main/res/drawable/typing_dot.xml similarity index 100% rename from examples/views/05-handoff/src/main/res/drawable/typing_dot.xml rename to examples/chat/views/05-handoff/src/main/res/drawable/typing_dot.xml diff --git a/examples/views/05-handoff/src/main/res/layout/activity_chat.xml b/examples/chat/views/05-handoff/src/main/res/layout/activity_chat.xml similarity index 100% rename from examples/views/05-handoff/src/main/res/layout/activity_chat.xml rename to examples/chat/views/05-handoff/src/main/res/layout/activity_chat.xml diff --git a/examples/views/05-handoff/src/main/res/layout/item_message.xml b/examples/chat/views/05-handoff/src/main/res/layout/item_message.xml similarity index 100% rename from examples/views/05-handoff/src/main/res/layout/item_message.xml rename to examples/chat/views/05-handoff/src/main/res/layout/item_message.xml diff --git a/examples/views/05-handoff/src/main/res/layout/item_suggestions.xml b/examples/chat/views/05-handoff/src/main/res/layout/item_suggestions.xml similarity index 100% rename from examples/views/05-handoff/src/main/res/layout/item_suggestions.xml rename to examples/chat/views/05-handoff/src/main/res/layout/item_suggestions.xml diff --git a/examples/views/05-handoff/src/main/res/layout/item_typing.xml b/examples/chat/views/05-handoff/src/main/res/layout/item_typing.xml similarity index 100% rename from examples/views/05-handoff/src/main/res/layout/item_typing.xml rename to examples/chat/views/05-handoff/src/main/res/layout/item_typing.xml diff --git a/examples/views/05-handoff/src/main/res/values/strings.xml b/examples/chat/views/05-handoff/src/main/res/values/strings.xml similarity index 100% rename from examples/views/05-handoff/src/main/res/values/strings.xml rename to examples/chat/views/05-handoff/src/main/res/values/strings.xml diff --git a/examples/views/05-handoff/src/main/res/values/themes.xml b/examples/chat/views/05-handoff/src/main/res/values/themes.xml similarity index 100% rename from examples/views/05-handoff/src/main/res/values/themes.xml rename to examples/chat/views/05-handoff/src/main/res/values/themes.xml diff --git a/examples/views/06-fullreference/README.md b/examples/chat/views/06-fullreference/README.md similarity index 93% rename from examples/views/06-fullreference/README.md rename to examples/chat/views/06-fullreference/README.md index 9f9f898..d0614ce 100644 --- a/examples/views/06-fullreference/README.md +++ b/examples/chat/views/06-fullreference/README.md @@ -28,7 +28,7 @@ Then launch `RootActivity`. Set your API key in `src/main/kotlin/ai/poly/example - System pills with level styling (info / warning / error) and a tappable `handoffRequired` link bubble - In-app new-message banners with a `NotificationPolicy` (quiet while the chat is on screen) -The SDK invariants behind each pattern are in the root README's [Integration guide](../../../README.md#integration-guide); this example shows them as one concrete multi-screen app. +The SDK invariants behind each pattern are in the root README's [Integration guide](../../../../README.md#integration-guide); this example shows them as one concrete multi-screen app. ## How it works @@ -57,7 +57,7 @@ The collectors are tied to the **client** (not the ChatSession), so an in-place **Under the hood:** `PolyMessaging.initialize(...)` (once, in `FullReferenceApplication`) stashes the API key and environment process-wide — no network happens yet — so the no-arg facade calls (`chat()`, `start()`, `hasResumableSession()`) reuse that config from any screen. Loading → chat is gated on `state.isReady` (or a `SessionStart` event) and only fires *while still loading*, so a mid-chat reconnect never throws the user back to the loading screen. Errors are routed via `showError(...)` only while loading, for the same reason — a transient blip after the chat is up just flips `connection` and recovers itself. `state.status == SessionStatus.RESTORED` is how you know it's a warm resume. -*See [Integration guide › Quick start](../../../README.md#quick-start) and [Integration guide › Connection & reconnect](../../../README.md#connection--reconnect).* +*See [Integration guide › Quick start](../../../../README.md#quick-start) and [Integration guide › Connection & reconnect](../../../../README.md#connection--reconnect).* ### Recoverable error screen — `RootActivity.kt` + `screen_error.xml` @@ -87,7 +87,7 @@ The error subtitles use `PolyError.debugDescription` for a developer-readable re **Under the hood:** routing errors only while `LOADING` means the error screen is recoverable by design — Go Back returns to connect and the user can retry. The `sessionState` collector also flips `ERROR → chat` when `state.isReady` arrives, so a session that recovers on its own re-enters the chat. If you want a non-recoverable terminal screen instead (the `04-Resilience` pattern), bind to `session.failureReason` directly. -*See [Integration guide › Terminal errors](../../../README.md#terminal-errors).* +*See [Integration guide › Terminal errors](../../../../README.md#terminal-errors).* ### Resume-or-start picker — `RootActivity.kt` + `screen_connect.xml` @@ -126,7 +126,7 @@ private fun showConnect() { **Under the hood:** `hasResumableSession()` is a side-effect-free on-disk check (no network), so it's safe to call every time the connect screen is shown — keeping the buttons honest as the user moves between connect / chat / connect. -*See [Integration guide › Starting, resuming & ending a session](../../../README.md#starting-resuming--ending-a-session).* +*See [Integration guide › Starting, resuming & ending a session](../../../../README.md#starting-resuming--ending-a-session).* ### Nav-bar End vs back — `RootActivity.kt` @@ -160,7 +160,7 @@ private fun endConversation() { **Under the hood:** awaiting `end()` before clearing the local `session` ensures the server has acknowledged the teardown before the connect screen re-probes `hasResumableSession()` — otherwise you can get a phantom "Resume" button for a session that's already dead. -*See [Integration guide › Starting, resuming & ending a session](../../../README.md#starting-resuming--ending-a-session).* +*See [Integration guide › Starting, resuming & ending a session](../../../../README.md#starting-resuming--ending-a-session).* ### In-place start-new — `ChatScreenController.kt` @@ -184,7 +184,7 @@ private fun startNewConversationInPlace() { **Under the hood:** `startNewSession()` reuses the existing client, so the lifecycle collectors in `RootActivity` (tied to that client) don't need re-arming — they flip the root back to chat once the new session is ready. `ChatSession` detects the new session id and resets its latched flags, so the screen converges without leaving chat. -*See [Integration guide › Starting, resuming & ending a session](../../../README.md#starting-resuming--ending-a-session).* +*See [Integration guide › Starting, resuming & ending a session](../../../../README.md#starting-resuming--ending-a-session).* ### The chat surface — `ChatScreenController.kt` @@ -192,7 +192,7 @@ The rung-05 chat, re-packaged as a controller the Root hands a session to, plus: **Under the hood:** `NewMessageNotifier.start(...)` collects `session.client.events` under `repeatOnLifecycle(Lifecycle.State.CREATED)` (CREATED, not STARTED, so a reply that lands while the chat is backgrounded still raises a banner). For each `AgentMessage` / `LiveAgentMessage` it (1) drops anything already seen — it dedupes on the server `messageId`, persisted in `SharedPreferences`, so a resume/relaunch replay never re-fires; (2) under `WHEN_BACKGROUNDED`, posts only when the chat isn't on screen (lifecycle below `STARTED`), so you're never banner-spammed for a conversation you're already reading; and (3) marks the id handled either way. On API 33+ the host Activity must request `POST_NOTIFICATIONS` first (only when the policy isn't `NEVER`). -*See [Integration guide › In-app new-message alerts (local-only workaround)](../../../README.md#in-app-new-message-alerts-local-only-workaround).* +*See [Integration guide › In-app new-message alerts (local-only workaround)](../../../../README.md#in-app-new-message-alerts-local-only-workaround).* ### Delayed "Sending..." label — `ChatScreenController.kt` @@ -240,7 +240,7 @@ private fun syncSendingLabels(messages: List) { **Under the hood:** this only gates *display* — the SDK still reports `PENDING` immediately and `SENT` the moment the server confirms. The bubble is in `messages` from the first frame either way; the label (`showSendingLabel` on the row's `ListItem.Message`) is the only thing this code controls. -*See [Integration guide › Delivery state & retry](../../../README.md#delivery-state--retry).* +*See [Integration guide › Delivery state & retry](../../../../README.md#delivery-state--retry).* ### Retry removes the failed draft, then re-sends — `ChatScreenController.kt` + `ChatAdapter.kt` @@ -267,13 +267,13 @@ private val adapter = ChatAdapter( **Under the hood:** without `removeMessage`, retrying would leave a "Failed" bubble next to the new attempt — `send()` always creates a fresh draft id rather than mutating the old one. Dropping the failed draft first is what keeps the transcript clean. -*See [Integration guide › Delivery state & retry](../../../README.md#delivery-state--retry).* +*See [Integration guide › Delivery state & retry](../../../../README.md#delivery-state--retry).* ### System pills with levels — `ChatAdapter.kt` `ServerMessage` colors by `SystemMessageLevel`; `handoffFailed`/`handoffTimeout` render error-red, `idleWarning` warning-orange. An `handoffRequired` with an http(s) route becomes a tappable blue bubble that opens it; anything else shows "Contact Support". -*See [Integration guide › Live agent handoff](../../../README.md#live-agent-handoff).* +*See [Integration guide › Live agent handoff](../../../../README.md#live-agent-handoff).* ## Try this on the emulator @@ -291,9 +291,9 @@ private val adapter = ChatAdapter( - runtime configuration, raw transport experiments, diagnostics, event log, message timestamps → 07-Playground (see [`../07-playground/`](../07-playground/)) -> **Streaming:** agent replies stream token-by-token by default (the bubble grows as chunks land), with no extra code here — the chat surface just binds to `messages`. The live `streamingEnabled` toggle to compare against complete-message bubbles lives in 07-Playground. See [Integration guide › Streaming](../../../README.md#streaming). +> **Streaming:** agent replies stream token-by-token by default (the bubble grows as chunks land), with no extra code here — the chat surface just binds to `messages`. The live `streamingEnabled` toggle to compare against complete-message bubbles lives in 07-Playground. See [Integration guide › Streaming](../../../../README.md#streaming). --- - **Compose counterpart:** [`../../compose/06-fullreference/`](../../compose/06-fullreference/) -- **SDK reference:** root [README → Integration guide](../../../README.md#integration-guide) +- **SDK reference:** root [README → Integration guide](../../../../README.md#integration-guide) diff --git a/examples/views/06-fullreference/build.gradle.kts b/examples/chat/views/06-fullreference/build.gradle.kts similarity index 100% rename from examples/views/06-fullreference/build.gradle.kts rename to examples/chat/views/06-fullreference/build.gradle.kts diff --git a/examples/views/06-fullreference/src/androidTest/kotlin/ai/poly/examples/fullreference/views/FullReferenceViewsFlowTest.kt b/examples/chat/views/06-fullreference/src/androidTest/kotlin/ai/poly/examples/fullreference/views/FullReferenceViewsFlowTest.kt similarity index 100% rename from examples/views/06-fullreference/src/androidTest/kotlin/ai/poly/examples/fullreference/views/FullReferenceViewsFlowTest.kt rename to examples/chat/views/06-fullreference/src/androidTest/kotlin/ai/poly/examples/fullreference/views/FullReferenceViewsFlowTest.kt diff --git a/examples/views/06-fullreference/src/androidTest/kotlin/ai/poly/examples/fullreference/views/NotificationBannerTest.kt b/examples/chat/views/06-fullreference/src/androidTest/kotlin/ai/poly/examples/fullreference/views/NotificationBannerTest.kt similarity index 100% rename from examples/views/06-fullreference/src/androidTest/kotlin/ai/poly/examples/fullreference/views/NotificationBannerTest.kt rename to examples/chat/views/06-fullreference/src/androidTest/kotlin/ai/poly/examples/fullreference/views/NotificationBannerTest.kt diff --git a/examples/views/06-fullreference/src/main/AndroidManifest.xml b/examples/chat/views/06-fullreference/src/main/AndroidManifest.xml similarity index 100% rename from examples/views/06-fullreference/src/main/AndroidManifest.xml rename to examples/chat/views/06-fullreference/src/main/AndroidManifest.xml diff --git a/examples/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/ChatAdapter.kt b/examples/chat/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/ChatAdapter.kt similarity index 100% rename from examples/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/ChatAdapter.kt rename to examples/chat/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/ChatAdapter.kt diff --git a/examples/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/ChatScreenController.kt b/examples/chat/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/ChatScreenController.kt similarity index 100% rename from examples/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/ChatScreenController.kt rename to examples/chat/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/ChatScreenController.kt diff --git a/examples/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/FullReferenceApplication.kt b/examples/chat/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/FullReferenceApplication.kt similarity index 100% rename from examples/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/FullReferenceApplication.kt rename to examples/chat/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/FullReferenceApplication.kt diff --git a/examples/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/LoadingSkeletonView.kt b/examples/chat/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/LoadingSkeletonView.kt similarity index 100% rename from examples/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/LoadingSkeletonView.kt rename to examples/chat/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/LoadingSkeletonView.kt diff --git a/examples/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/NetworkMonitor.kt b/examples/chat/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/NetworkMonitor.kt similarity index 100% rename from examples/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/NetworkMonitor.kt rename to examples/chat/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/NetworkMonitor.kt diff --git a/examples/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/NewMessageNotifier.kt b/examples/chat/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/NewMessageNotifier.kt similarity index 100% rename from examples/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/NewMessageNotifier.kt rename to examples/chat/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/NewMessageNotifier.kt diff --git a/examples/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/Palette.kt b/examples/chat/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/Palette.kt similarity index 100% rename from examples/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/Palette.kt rename to examples/chat/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/Palette.kt diff --git a/examples/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/RetryableImageView.kt b/examples/chat/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/RetryableImageView.kt similarity index 100% rename from examples/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/RetryableImageView.kt rename to examples/chat/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/RetryableImageView.kt diff --git a/examples/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/RichTextSpans.kt b/examples/chat/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/RichTextSpans.kt similarity index 100% rename from examples/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/RichTextSpans.kt rename to examples/chat/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/RichTextSpans.kt diff --git a/examples/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/RootActivity.kt b/examples/chat/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/RootActivity.kt similarity index 100% rename from examples/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/RootActivity.kt rename to examples/chat/views/06-fullreference/src/main/kotlin/ai/poly/examples/fullreference/views/RootActivity.kt diff --git a/examples/views/06-fullreference/src/main/res/drawable/avatar_placeholder.xml b/examples/chat/views/06-fullreference/src/main/res/drawable/avatar_placeholder.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/drawable/avatar_placeholder.xml rename to examples/chat/views/06-fullreference/src/main/res/drawable/avatar_placeholder.xml diff --git a/examples/views/06-fullreference/src/main/res/drawable/bg_failure_card.xml b/examples/chat/views/06-fullreference/src/main/res/drawable/bg_failure_card.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/drawable/bg_failure_card.xml rename to examples/chat/views/06-fullreference/src/main/res/drawable/bg_failure_card.xml diff --git a/examples/views/06-fullreference/src/main/res/drawable/bg_green_dot.xml b/examples/chat/views/06-fullreference/src/main/res/drawable/bg_green_dot.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/drawable/bg_green_dot.xml rename to examples/chat/views/06-fullreference/src/main/res/drawable/bg_green_dot.xml diff --git a/examples/views/06-fullreference/src/main/res/drawable/bg_info_card.xml b/examples/chat/views/06-fullreference/src/main/res/drawable/bg_info_card.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/drawable/bg_info_card.xml rename to examples/chat/views/06-fullreference/src/main/res/drawable/bg_info_card.xml diff --git a/examples/views/06-fullreference/src/main/res/drawable/bg_input_field.xml b/examples/chat/views/06-fullreference/src/main/res/drawable/bg_input_field.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/drawable/bg_input_field.xml rename to examples/chat/views/06-fullreference/src/main/res/drawable/bg_input_field.xml diff --git a/examples/views/06-fullreference/src/main/res/drawable/bg_pill_new_messages.xml b/examples/chat/views/06-fullreference/src/main/res/drawable/bg_pill_new_messages.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/drawable/bg_pill_new_messages.xml rename to examples/chat/views/06-fullreference/src/main/res/drawable/bg_pill_new_messages.xml diff --git a/examples/views/06-fullreference/src/main/res/drawable/bg_typing_bubble.xml b/examples/chat/views/06-fullreference/src/main/res/drawable/bg_typing_bubble.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/drawable/bg_typing_bubble.xml rename to examples/chat/views/06-fullreference/src/main/res/drawable/bg_typing_bubble.xml diff --git a/examples/views/06-fullreference/src/main/res/drawable/ic_arrow_upward.xml b/examples/chat/views/06-fullreference/src/main/res/drawable/ic_arrow_upward.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/drawable/ic_arrow_upward.xml rename to examples/chat/views/06-fullreference/src/main/res/drawable/ic_arrow_upward.xml diff --git a/examples/views/06-fullreference/src/main/res/drawable/ic_bolt.xml b/examples/chat/views/06-fullreference/src/main/res/drawable/ic_bolt.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/drawable/ic_bolt.xml rename to examples/chat/views/06-fullreference/src/main/res/drawable/ic_bolt.xml diff --git a/examples/views/06-fullreference/src/main/res/drawable/ic_call.xml b/examples/chat/views/06-fullreference/src/main/res/drawable/ic_call.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/drawable/ic_call.xml rename to examples/chat/views/06-fullreference/src/main/res/drawable/ic_call.xml diff --git a/examples/views/06-fullreference/src/main/res/drawable/ic_chat_bubbles.xml b/examples/chat/views/06-fullreference/src/main/res/drawable/ic_chat_bubbles.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/drawable/ic_chat_bubbles.xml rename to examples/chat/views/06-fullreference/src/main/res/drawable/ic_chat_bubbles.xml diff --git a/examples/views/06-fullreference/src/main/res/drawable/ic_chevron_left.xml b/examples/chat/views/06-fullreference/src/main/res/drawable/ic_chevron_left.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/drawable/ic_chevron_left.xml rename to examples/chat/views/06-fullreference/src/main/res/drawable/ic_chevron_left.xml diff --git a/examples/views/06-fullreference/src/main/res/drawable/ic_close_circle.xml b/examples/chat/views/06-fullreference/src/main/res/drawable/ic_close_circle.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/drawable/ic_close_circle.xml rename to examples/chat/views/06-fullreference/src/main/res/drawable/ic_close_circle.xml diff --git a/examples/views/06-fullreference/src/main/res/drawable/ic_dns.xml b/examples/chat/views/06-fullreference/src/main/res/drawable/ic_dns.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/drawable/ic_dns.xml rename to examples/chat/views/06-fullreference/src/main/res/drawable/ic_dns.xml diff --git a/examples/views/06-fullreference/src/main/res/drawable/ic_error_triangle.xml b/examples/chat/views/06-fullreference/src/main/res/drawable/ic_error_triangle.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/drawable/ic_error_triangle.xml rename to examples/chat/views/06-fullreference/src/main/res/drawable/ic_error_triangle.xml diff --git a/examples/views/06-fullreference/src/main/res/drawable/ic_image.xml b/examples/chat/views/06-fullreference/src/main/res/drawable/ic_image.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/drawable/ic_image.xml rename to examples/chat/views/06-fullreference/src/main/res/drawable/ic_image.xml diff --git a/examples/views/06-fullreference/src/main/res/drawable/ic_key.xml b/examples/chat/views/06-fullreference/src/main/res/drawable/ic_key.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/drawable/ic_key.xml rename to examples/chat/views/06-fullreference/src/main/res/drawable/ic_key.xml diff --git a/examples/views/06-fullreference/src/main/res/drawable/ic_resume.xml b/examples/chat/views/06-fullreference/src/main/res/drawable/ic_resume.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/drawable/ic_resume.xml rename to examples/chat/views/06-fullreference/src/main/res/drawable/ic_resume.xml diff --git a/examples/views/06-fullreference/src/main/res/drawable/ic_wifi_off.xml b/examples/chat/views/06-fullreference/src/main/res/drawable/ic_wifi_off.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/drawable/ic_wifi_off.xml rename to examples/chat/views/06-fullreference/src/main/res/drawable/ic_wifi_off.xml diff --git a/examples/views/06-fullreference/src/main/res/drawable/typing_dot.xml b/examples/chat/views/06-fullreference/src/main/res/drawable/typing_dot.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/drawable/typing_dot.xml rename to examples/chat/views/06-fullreference/src/main/res/drawable/typing_dot.xml diff --git a/examples/views/06-fullreference/src/main/res/layout/activity_root.xml b/examples/chat/views/06-fullreference/src/main/res/layout/activity_root.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/layout/activity_root.xml rename to examples/chat/views/06-fullreference/src/main/res/layout/activity_root.xml diff --git a/examples/views/06-fullreference/src/main/res/layout/item_message.xml b/examples/chat/views/06-fullreference/src/main/res/layout/item_message.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/layout/item_message.xml rename to examples/chat/views/06-fullreference/src/main/res/layout/item_message.xml diff --git a/examples/views/06-fullreference/src/main/res/layout/item_suggestions.xml b/examples/chat/views/06-fullreference/src/main/res/layout/item_suggestions.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/layout/item_suggestions.xml rename to examples/chat/views/06-fullreference/src/main/res/layout/item_suggestions.xml diff --git a/examples/views/06-fullreference/src/main/res/layout/item_typing.xml b/examples/chat/views/06-fullreference/src/main/res/layout/item_typing.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/layout/item_typing.xml rename to examples/chat/views/06-fullreference/src/main/res/layout/item_typing.xml diff --git a/examples/views/06-fullreference/src/main/res/layout/screen_chat.xml b/examples/chat/views/06-fullreference/src/main/res/layout/screen_chat.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/layout/screen_chat.xml rename to examples/chat/views/06-fullreference/src/main/res/layout/screen_chat.xml diff --git a/examples/views/06-fullreference/src/main/res/layout/screen_connect.xml b/examples/chat/views/06-fullreference/src/main/res/layout/screen_connect.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/layout/screen_connect.xml rename to examples/chat/views/06-fullreference/src/main/res/layout/screen_connect.xml diff --git a/examples/views/06-fullreference/src/main/res/layout/screen_error.xml b/examples/chat/views/06-fullreference/src/main/res/layout/screen_error.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/layout/screen_error.xml rename to examples/chat/views/06-fullreference/src/main/res/layout/screen_error.xml diff --git a/examples/views/06-fullreference/src/main/res/layout/screen_loading.xml b/examples/chat/views/06-fullreference/src/main/res/layout/screen_loading.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/layout/screen_loading.xml rename to examples/chat/views/06-fullreference/src/main/res/layout/screen_loading.xml diff --git a/examples/views/06-fullreference/src/main/res/values/strings.xml b/examples/chat/views/06-fullreference/src/main/res/values/strings.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/values/strings.xml rename to examples/chat/views/06-fullreference/src/main/res/values/strings.xml diff --git a/examples/views/06-fullreference/src/main/res/values/themes.xml b/examples/chat/views/06-fullreference/src/main/res/values/themes.xml similarity index 100% rename from examples/views/06-fullreference/src/main/res/values/themes.xml rename to examples/chat/views/06-fullreference/src/main/res/values/themes.xml diff --git a/examples/views/07-playground/README.md b/examples/chat/views/07-playground/README.md similarity index 97% rename from examples/views/07-playground/README.md rename to examples/chat/views/07-playground/README.md index 8408f5a..57e4da1 100644 --- a/examples/views/07-playground/README.md +++ b/examples/chat/views/07-playground/README.md @@ -76,7 +76,7 @@ class RootActivity : ComponentActivity() { **Under the hood:** session-creation knobs (environment, streaming — and the server-side greeting they trigger) take effect only on a fresh session, which is why the sheet shows a "⚠︎ Live session active" / "⚠︎ Resumable session exists" mismatch banner with an **"Apply & Start New Session"** button whenever a session is live or resumable. `lastAppliedStreamingEnabled` on `DevSettings` records the value the running session was started with (the Compose sheet uses it to flag *which* knob is out of sync); the Views dialog shows the banner unconditionally whenever `hasAnySession` is true. -*See [Integration guide › Configuration](../../../README.md#configuration).* +*See [Integration guide › Configuration](../../../../README.md#configuration).* ### Streaming toggle — `SettingsDialog.kt` @@ -109,7 +109,7 @@ The "Restart to apply" affordance lives in the mismatch-banner card at the top o **Under the hood:** when `streamingEnabled = true` (default), `ChatSession` extends the last agent message's `text` on every chunk and re-publishes `messages` — the adapter rebinds the cell with the longer text. When `false`, the SDK shows the assembled message in one shot and keeps `isAgentTyping == true` while the agent thinks. The chat code is identical either way; the same `messages` list just updates differently. -*See [Integration guide › Streaming](../../../README.md#streaming).* +*See [Integration guide › Streaming](../../../../README.md#streaming).* ### Raw transport: send frames — `SettingsDialog.kt`, `RootActivity.kt` @@ -157,7 +157,7 @@ private fun rawSend(event: OutgoingEvent) { **Under the hood:** `UserEndConversation` / `UserLeft` are real frames the backend processes (a server-side `EVENT_TYPE_USER_END_SESSION`); `Heartbeat` and `UserTyping` are protocol bookkeeping. Because the managed `send()` path isn't involved, the SDK won't surface these as messages or delivery events — they're invisible to `session.messages`. -*See [Integration guide › Raw transport](../../../README.md#advanced-raw-transport).* +*See [Integration guide › Raw transport](../../../../README.md#advanced-raw-transport).* ### Raw transport: close-code simulations — `SettingsDialog.kt`, `RootActivity.kt` @@ -195,7 +195,7 @@ onDisconnectClean = { closeWith(1000, "Debug clean disconnect") }, **Under the hood:** these are **client-side simulations**, not backend round-trips. The `40xx` codes are the SDK's internal vocabulary for classifying the close — the buttons exercise the SDK's own reconnect classification; the server isn't asked to reject or idle-out. -*See [Integration guide › Raw transport](../../../README.md#advanced-raw-transport).* +*See [Integration guide › Raw transport](../../../../README.md#advanced-raw-transport).* ### Event log — `EventLogger.kt`, `LogsDialog.kt` @@ -361,7 +361,7 @@ fun start() { Toggle streaming in the Settings sheet to confirm it stays one banner per reply (the bubble `id` is stable across chunks). -*See [Integration guide › In-app new-message alerts (local-only workaround)](../../../README.md#in-app-new-message-alerts-local-only-workaround).* +*See [Integration guide › In-app new-message alerts (local-only workaround)](../../../../README.md#in-app-new-message-alerts-local-only-workaround).* ## What this example is for @@ -373,5 +373,5 @@ Toggle streaming in the Settings sheet to confirm it stays one banner per reply --- - **Compose counterpart:** [`examples/compose/07-playground/`](../../compose/07-playground/) -- **SDK reference:** root [README → Integration guide](../../../README.md#integration-guide) -- **Install the package:** root [README → Install](../../../README.md#install) +- **SDK reference:** root [README → Integration guide](../../../../README.md#integration-guide) +- **Install the package:** root [README → Install](../../../../README.md#install) diff --git a/examples/views/07-playground/build.gradle.kts b/examples/chat/views/07-playground/build.gradle.kts similarity index 100% rename from examples/views/07-playground/build.gradle.kts rename to examples/chat/views/07-playground/build.gradle.kts diff --git a/examples/views/07-playground/src/androidTest/kotlin/ai/poly/examples/playground/views/NotificationBannerTest.kt b/examples/chat/views/07-playground/src/androidTest/kotlin/ai/poly/examples/playground/views/NotificationBannerTest.kt similarity index 100% rename from examples/views/07-playground/src/androidTest/kotlin/ai/poly/examples/playground/views/NotificationBannerTest.kt rename to examples/chat/views/07-playground/src/androidTest/kotlin/ai/poly/examples/playground/views/NotificationBannerTest.kt diff --git a/examples/views/07-playground/src/androidTest/kotlin/ai/poly/examples/playground/views/PlaygroundViewsFlowTest.kt b/examples/chat/views/07-playground/src/androidTest/kotlin/ai/poly/examples/playground/views/PlaygroundViewsFlowTest.kt similarity index 100% rename from examples/views/07-playground/src/androidTest/kotlin/ai/poly/examples/playground/views/PlaygroundViewsFlowTest.kt rename to examples/chat/views/07-playground/src/androidTest/kotlin/ai/poly/examples/playground/views/PlaygroundViewsFlowTest.kt diff --git a/examples/views/07-playground/src/main/AndroidManifest.xml b/examples/chat/views/07-playground/src/main/AndroidManifest.xml similarity index 100% rename from examples/views/07-playground/src/main/AndroidManifest.xml rename to examples/chat/views/07-playground/src/main/AndroidManifest.xml diff --git a/examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/ChatAdapter.kt b/examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/ChatAdapter.kt similarity index 100% rename from examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/ChatAdapter.kt rename to examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/ChatAdapter.kt diff --git a/examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/ChatModels.kt b/examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/ChatModels.kt similarity index 100% rename from examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/ChatModels.kt rename to examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/ChatModels.kt diff --git a/examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/ChatScreenController.kt b/examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/ChatScreenController.kt similarity index 100% rename from examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/ChatScreenController.kt rename to examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/ChatScreenController.kt diff --git a/examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/DebugStripView.kt b/examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/DebugStripView.kt similarity index 100% rename from examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/DebugStripView.kt rename to examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/DebugStripView.kt diff --git a/examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/DevDiagnostics.kt b/examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/DevDiagnostics.kt similarity index 100% rename from examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/DevDiagnostics.kt rename to examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/DevDiagnostics.kt diff --git a/examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/EventLogger.kt b/examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/EventLogger.kt similarity index 100% rename from examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/EventLogger.kt rename to examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/EventLogger.kt diff --git a/examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/LoadingSkeletonView.kt b/examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/LoadingSkeletonView.kt similarity index 100% rename from examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/LoadingSkeletonView.kt rename to examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/LoadingSkeletonView.kt diff --git a/examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/LogsDialog.kt b/examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/LogsDialog.kt similarity index 100% rename from examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/LogsDialog.kt rename to examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/LogsDialog.kt diff --git a/examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/MessageTimestamp.kt b/examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/MessageTimestamp.kt similarity index 100% rename from examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/MessageTimestamp.kt rename to examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/MessageTimestamp.kt diff --git a/examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/NetworkMonitor.kt b/examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/NetworkMonitor.kt similarity index 100% rename from examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/NetworkMonitor.kt rename to examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/NetworkMonitor.kt diff --git a/examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/NewMessageNotifier.kt b/examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/NewMessageNotifier.kt similarity index 100% rename from examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/NewMessageNotifier.kt rename to examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/NewMessageNotifier.kt diff --git a/examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/Palette.kt b/examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/Palette.kt similarity index 100% rename from examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/Palette.kt rename to examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/Palette.kt diff --git a/examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/PlaygroundApplication.kt b/examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/PlaygroundApplication.kt similarity index 100% rename from examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/PlaygroundApplication.kt rename to examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/PlaygroundApplication.kt diff --git a/examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/RetryableImageView.kt b/examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/RetryableImageView.kt similarity index 100% rename from examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/RetryableImageView.kt rename to examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/RetryableImageView.kt diff --git a/examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/RichTextSpans.kt b/examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/RichTextSpans.kt similarity index 100% rename from examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/RichTextSpans.kt rename to examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/RichTextSpans.kt diff --git a/examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/RootActivity.kt b/examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/RootActivity.kt similarity index 100% rename from examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/RootActivity.kt rename to examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/RootActivity.kt diff --git a/examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/SettingsDialog.kt b/examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/SettingsDialog.kt similarity index 100% rename from examples/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/SettingsDialog.kt rename to examples/chat/views/07-playground/src/main/kotlin/ai/poly/examples/playground/views/SettingsDialog.kt diff --git a/examples/views/07-playground/src/main/res/drawable/avatar_placeholder.xml b/examples/chat/views/07-playground/src/main/res/drawable/avatar_placeholder.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/avatar_placeholder.xml rename to examples/chat/views/07-playground/src/main/res/drawable/avatar_placeholder.xml diff --git a/examples/views/07-playground/src/main/res/drawable/bg_failure_card.xml b/examples/chat/views/07-playground/src/main/res/drawable/bg_failure_card.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/bg_failure_card.xml rename to examples/chat/views/07-playground/src/main/res/drawable/bg_failure_card.xml diff --git a/examples/views/07-playground/src/main/res/drawable/bg_green_dot.xml b/examples/chat/views/07-playground/src/main/res/drawable/bg_green_dot.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/bg_green_dot.xml rename to examples/chat/views/07-playground/src/main/res/drawable/bg_green_dot.xml diff --git a/examples/views/07-playground/src/main/res/drawable/bg_info_card.xml b/examples/chat/views/07-playground/src/main/res/drawable/bg_info_card.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/bg_info_card.xml rename to examples/chat/views/07-playground/src/main/res/drawable/bg_info_card.xml diff --git a/examples/views/07-playground/src/main/res/drawable/bg_input_field.xml b/examples/chat/views/07-playground/src/main/res/drawable/bg_input_field.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/bg_input_field.xml rename to examples/chat/views/07-playground/src/main/res/drawable/bg_input_field.xml diff --git a/examples/views/07-playground/src/main/res/drawable/bg_pill_new_messages.xml b/examples/chat/views/07-playground/src/main/res/drawable/bg_pill_new_messages.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/bg_pill_new_messages.xml rename to examples/chat/views/07-playground/src/main/res/drawable/bg_pill_new_messages.xml diff --git a/examples/views/07-playground/src/main/res/drawable/bg_typing_bubble.xml b/examples/chat/views/07-playground/src/main/res/drawable/bg_typing_bubble.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/bg_typing_bubble.xml rename to examples/chat/views/07-playground/src/main/res/drawable/bg_typing_bubble.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_arrow_upward.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_arrow_upward.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_arrow_upward.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_arrow_upward.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_autorenew.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_autorenew.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_autorenew.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_autorenew.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_block.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_block.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_block.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_block.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_bolt.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_bolt.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_bolt.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_bolt.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_call.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_call.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_call.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_call.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_chat_bubbles.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_chat_bubbles.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_chat_bubbles.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_chat_bubbles.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_chat_typing.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_chat_typing.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_chat_typing.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_chat_typing.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_chat_typing_filled.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_chat_typing_filled.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_chat_typing_filled.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_chat_typing_filled.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_check_circle.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_check_circle.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_check_circle.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_check_circle.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_chevron_left.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_chevron_left.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_chevron_left.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_chevron_left.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_circle_outline.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_circle_outline.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_circle_outline.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_circle_outline.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_clock.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_clock.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_clock.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_clock.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_clock_alert.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_clock_alert.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_clock_alert.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_clock_alert.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_close_circle.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_close_circle.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_close_circle.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_close_circle.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_copy.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_copy.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_copy.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_copy.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_dns.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_dns.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_dns.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_dns.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_ecg.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_ecg.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_ecg.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_ecg.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_error_circle.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_error_circle.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_error_circle.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_error_circle.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_error_triangle.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_error_triangle.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_error_triangle.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_error_triangle.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_expand_less.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_expand_less.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_expand_less.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_expand_less.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_expand_more.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_expand_more.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_expand_more.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_expand_more.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_find_in_page.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_find_in_page.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_find_in_page.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_find_in_page.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_image.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_image.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_image.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_image.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_info.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_info.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_info.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_info.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_key.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_key.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_key.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_key.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_ladybug.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_ladybug.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_ladybug.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_ladybug.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_logout.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_logout.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_logout.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_logout.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_more_horiz.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_more_horiz.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_more_horiz.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_more_horiz.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_radio_waves.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_radio_waves.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_radio_waves.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_radio_waves.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_restore.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_restore.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_restore.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_restore.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_resume.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_resume.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_resume.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_resume.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_search.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_search.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_search.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_search.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_settings.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_settings.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_settings.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_settings.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_shield_alert.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_shield_alert.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_shield_alert.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_shield_alert.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_swap_vert.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_swap_vert.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_swap_vert.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_swap_vert.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_tag.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_tag.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_tag.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_tag.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_waveform.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_waveform.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_waveform.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_waveform.xml diff --git a/examples/views/07-playground/src/main/res/drawable/ic_wifi_off.xml b/examples/chat/views/07-playground/src/main/res/drawable/ic_wifi_off.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/ic_wifi_off.xml rename to examples/chat/views/07-playground/src/main/res/drawable/ic_wifi_off.xml diff --git a/examples/views/07-playground/src/main/res/drawable/typing_dot.xml b/examples/chat/views/07-playground/src/main/res/drawable/typing_dot.xml similarity index 100% rename from examples/views/07-playground/src/main/res/drawable/typing_dot.xml rename to examples/chat/views/07-playground/src/main/res/drawable/typing_dot.xml diff --git a/examples/views/07-playground/src/main/res/layout/activity_root.xml b/examples/chat/views/07-playground/src/main/res/layout/activity_root.xml similarity index 100% rename from examples/views/07-playground/src/main/res/layout/activity_root.xml rename to examples/chat/views/07-playground/src/main/res/layout/activity_root.xml diff --git a/examples/views/07-playground/src/main/res/layout/item_message.xml b/examples/chat/views/07-playground/src/main/res/layout/item_message.xml similarity index 100% rename from examples/views/07-playground/src/main/res/layout/item_message.xml rename to examples/chat/views/07-playground/src/main/res/layout/item_message.xml diff --git a/examples/views/07-playground/src/main/res/layout/item_suggestions.xml b/examples/chat/views/07-playground/src/main/res/layout/item_suggestions.xml similarity index 100% rename from examples/views/07-playground/src/main/res/layout/item_suggestions.xml rename to examples/chat/views/07-playground/src/main/res/layout/item_suggestions.xml diff --git a/examples/views/07-playground/src/main/res/layout/item_timestamp.xml b/examples/chat/views/07-playground/src/main/res/layout/item_timestamp.xml similarity index 100% rename from examples/views/07-playground/src/main/res/layout/item_timestamp.xml rename to examples/chat/views/07-playground/src/main/res/layout/item_timestamp.xml diff --git a/examples/views/07-playground/src/main/res/layout/item_typing.xml b/examples/chat/views/07-playground/src/main/res/layout/item_typing.xml similarity index 100% rename from examples/views/07-playground/src/main/res/layout/item_typing.xml rename to examples/chat/views/07-playground/src/main/res/layout/item_typing.xml diff --git a/examples/views/07-playground/src/main/res/layout/screen_chat.xml b/examples/chat/views/07-playground/src/main/res/layout/screen_chat.xml similarity index 100% rename from examples/views/07-playground/src/main/res/layout/screen_chat.xml rename to examples/chat/views/07-playground/src/main/res/layout/screen_chat.xml diff --git a/examples/views/07-playground/src/main/res/layout/screen_connect.xml b/examples/chat/views/07-playground/src/main/res/layout/screen_connect.xml similarity index 100% rename from examples/views/07-playground/src/main/res/layout/screen_connect.xml rename to examples/chat/views/07-playground/src/main/res/layout/screen_connect.xml diff --git a/examples/views/07-playground/src/main/res/layout/screen_error.xml b/examples/chat/views/07-playground/src/main/res/layout/screen_error.xml similarity index 100% rename from examples/views/07-playground/src/main/res/layout/screen_error.xml rename to examples/chat/views/07-playground/src/main/res/layout/screen_error.xml diff --git a/examples/views/07-playground/src/main/res/layout/screen_loading.xml b/examples/chat/views/07-playground/src/main/res/layout/screen_loading.xml similarity index 100% rename from examples/views/07-playground/src/main/res/layout/screen_loading.xml rename to examples/chat/views/07-playground/src/main/res/layout/screen_loading.xml diff --git a/examples/views/07-playground/src/main/res/values/strings.xml b/examples/chat/views/07-playground/src/main/res/values/strings.xml similarity index 100% rename from examples/views/07-playground/src/main/res/values/strings.xml rename to examples/chat/views/07-playground/src/main/res/values/strings.xml diff --git a/examples/views/07-playground/src/main/res/values/themes.xml b/examples/chat/views/07-playground/src/main/res/values/themes.xml similarity index 100% rename from examples/views/07-playground/src/main/res/values/themes.xml rename to examples/chat/views/07-playground/src/main/res/values/themes.xml diff --git a/examples/voice/compose/README.md b/examples/voice/compose/README.md new file mode 100644 index 0000000..c0144fe --- /dev/null +++ b/examples/voice/compose/README.md @@ -0,0 +1,186 @@ +# Voice — tap to call (Compose) + +The smallest thing that makes a **WebRTC voice call** to a PolyAI agent with `ai.poly:voice`: one +screen, one button, plus mute and an audio-output picker — all in one +[`MainActivity.kt`](src/main/kotlin/ai/poly/examples/voice/compose/MainActivity.kt) (~200 lines). + +## Run it + +First, set your connector in the `PolyVoice.call(...)` block at the top of `MainActivity.kt` — your **API +key** + **WebRTC token** from Agent Studio (see [Use your own agent](#use-your-own-agent)). Then open the +repo in Android Studio and run the **voice/compose** module, or from the repo root: + +```bash +./gradlew :examples:voice:compose:installDebug +``` + +`installDebug` only installs the APK — tap the launcher icon, or launch it directly: + +```bash +adb shell am start -n ai.poly.examples.voice.compose/.MainActivity +``` + +Run on a **physical device** (Android 7.0+ / API 24). PolyAI's hosts are public, so any normal internet +connection works. + +> A stock emulator often ships with a **broken DNS resolver** (can't resolve any hostname) — if you see +> an `Unable to resolve host` error for a `*.poly.ai` address, that's the emulator, not the SDK. Restart +> it with `emulator -avd -dns-server 8.8.8.8`, or just use a real device. + +## What this example demonstrates + +- `PolyVoice.call(context, config, options)` → a `VoiceCall` +- Observing `call.state: StateFlow` (`Idle → Connecting → Connected → Ended / Failed`) +- The `RECORD_AUDIO` runtime-permission flow before `start()` +- In-call controls: `setMuted(...)` / `end()`, and `close()` on teardown +- The **audio-output picker** — `call.audio` + `setAudioDevice(...)` to switch speaker / earpiece / + headset / Bluetooth mid-call +- A **microphone foreground service** (`CallForegroundService`) + wake lock so the call **survives the + app being backgrounded** — without it Android cuts background mic + throttles the media threads and the + call drops after ~15s + +The SDK surface behind each pattern is in the +[PolyAI Voice guide](../../../polyvoice/README.md); this example shows it as one concrete file. + +## Permissions + +The SDK auto-merges `INTERNET` / `ACCESS_NETWORK_STATE` / `RECORD_AUDIO`; this example's +[manifest](src/main/AndroidManifest.xml) adds the rest so every feature works out of the box: + +```xml + + + + + + +``` + +## How it works + +Each subsection leads with **the SDK call** (the actual API), then shows **how it's wired into a +`@Composable`**. + +### Build the call — `PolyVoice.call(...)` + +A call is self-contained: it creates its own session, independent of any chat. Hold it with `remember` +and close it when the screen leaves the composition. + +```kotlin +val call = remember { + PolyVoice.call( + context = context, + config = Configuration( + apiKey = "YOUR_API_KEY", // connector token, sent as X-Token + ), + options = VoiceOptions(webrtcToken = "YOUR_WEBRTC_TOKEN"), // the connector's WebRTC token (distinct from apiKey) + ) +} +// (the real teardown also stops the foreground service — see "Survive the background" below) +DisposableEffect(Unit) { onDispose { call.close() } } +``` + +### Observe the call state — `call.state` + +`state` is a `StateFlow` — collect it to drive the UI. + +```kotlin +val state by call.state.collectAsStateWithLifecycle() +// CallState.Idle → Connecting → Connected → Ended / Failed(error: PolyError.Voice) +``` + +### Grant the mic, then start — `call.start()` + +`start()` needs the `RECORD_AUDIO` runtime permission; request it first, then start from a coroutine. + +```kotlin +val requestMic = rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { granted -> + if (granted) scope.launch { runCatching { call.start() } } +} +// on tap: +if (granted) scope.launch { runCatching { call.start() } } else requestMic.launch(Manifest.permission.RECORD_AUDIO) +``` + +> In the actual code these go through a `startCall()` helper that *also* starts the foreground service — +> see [Survive the background](#survive-the-background--callforegroundservice). It's shown plain here to +> keep the permission flow clear. + +### Mute and hang up — `call.setMuted(...)` / `call.end()` + +```kotlin +scope.launch { call.setMuted(true) } // mute the mic +scope.launch { call.end() } // hang up and release the mic +``` + +### Audio output picker — `call.audio` + `call.setAudioDevice(...)` + +By default the call **follows the connected accessory** (headset/Bluetooth), falling back to the +loudspeaker. `call.audio` is a `StateFlow` — a snapshot of the outputs available now and the +active one. Render an **Auto** chip plus one per device: tapping a device pins it; **Auto** returns to +automatic (`setAudioDevice(null)`). The selection confirms **asynchronously** via `call.audio` (Bluetooth +can take a few seconds), so the highlight follows the flow, not the tap. + +```kotlin +val audio by call.audio.collectAsStateWithLifecycle() + +FilterChip(selected = autoOutput, label = { Text("Auto") }, + onClick = { autoOutput = true; scope.launch { call.setAudioDevice(null) } }) // follow the accessory/system +audio.availableDevices.forEach { device -> + FilterChip( + selected = !autoOutput && device == audio.selectedDevice, + onClick = { autoOutput = false; scope.launch { call.setAudioDevice(device) } }, // pin this device + label = { Text(labelFor(device)) }, // device.type: SPEAKER_PHONE / EARPIECE / WIRED_HEADSET / BLUETOOTH + ) +} +``` + +When nothing's plugged in it falls back to the **loudspeaker** (`VoiceOptions(speakerphone = false)` → +earpiece). Bluetooth devices only appear because this example declares **`BLUETOOTH_CONNECT`** in its +[manifest](src/main/AndroidManifest.xml) — the SDK doesn't add that dangerous permission for you. + +### Survive the background — `CallForegroundService` + +The SDK won't end a call when you background the app, but Android cuts background mic + throttles the media +threads, so without help the call drops ~15s in. This example starts a microphone foreground service (+ a +wake lock — see [`CallForegroundService.kt`](src/main/kotlin/ai/poly/examples/voice/compose/CallForegroundService.kt)) +**before** `start()`, and stops it when the call ends: + +```kotlin +fun startCall() { + CallForegroundService.start(context) // mic FGS + wake lock keep the call alive backgrounded + scope.launch { runCatching { call.start() } } +} + +// stop it when the call leaves an active state, and on teardown: +LaunchedEffect(state) { + if (state is CallState.Ended || state is CallState.Failed) CallForegroundService.stop(context) +} +DisposableEffect(Unit) { onDispose { CallForegroundService.stop(context); call.close() } } +``` + +The required manifest entries (`FOREGROUND_SERVICE`, `FOREGROUND_SERVICE_MICROPHONE`, `WAKE_LOCK`, +`POST_NOTIFICATIONS`, and the ``) are in the +[manifest](src/main/AndroidManifest.xml). + +## Use your own agent + +You need **two credentials**, both on your agent in **[Agent Studio](https://studio.poly.ai) › Connector +Settings**: the **API key** (connector token) and the **WebRTC token**. Set them in the +`PolyVoice.call(...)` block at the top of `MainActivity.kt`: + +```kotlin +PolyVoice.call( + context = context, + config = Configuration( + apiKey = "YOUR_API_KEY", // connector token, sent as X-Token — required + // environment defaults to Environment.US — set .UK / .EUW / .cluster("…") only if your agent is elsewhere + // hostIdentifier defaults to this app's package name (sent as X-Host) — override only if your + // connector is registered against a specific host + ), + options = VoiceOptions(webrtcToken = "YOUR_WEBRTC_TOKEN"), // gateway token; omit if one token does both +) +``` + +`environment` (US) and `hostIdentifier` (your app's package name) have sensible defaults, so most agents +need only the two tokens — add `environment` / `hostIdentifier` to the `Configuration` only if your agent +lives in another region or your connector is registered against a specific host. diff --git a/examples/voice/compose/build.gradle.kts b/examples/voice/compose/build.gradle.kts new file mode 100644 index 0000000..00b19c9 --- /dev/null +++ b/examples/voice/compose/build.gradle.kts @@ -0,0 +1,42 @@ +// Copyright PolyAI Limited + +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) +} + +android { + namespace = "ai.poly.examples.voice.compose" + compileSdk = 36 + + defaultConfig { + applicationId = "ai.poly.examples.voice.compose" + minSdk = 24 + targetSdk = 36 + versionCode = 1 + versionName = "0.8.0" + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildFeatures { compose = true } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } +} + +kotlin { jvmToolchain(17) } + +dependencies { + // The voice SDK (transitively brings in :polymessaging for Configuration / CallState / PolyError). + implementation(project(":polyvoice")) + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.activity.compose) + implementation(libs.androidx.lifecycle.runtime.compose) + implementation(platform(libs.compose.bom)) + implementation(libs.compose.ui) + implementation(libs.compose.material3) + implementation(libs.compose.ui.tooling.preview) +} diff --git a/examples/voice/compose/src/main/AndroidManifest.xml b/examples/voice/compose/src/main/AndroidManifest.xml new file mode 100644 index 0000000..bf8ce05 --- /dev/null +++ b/examples/voice/compose/src/main/AndroidManifest.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/voice/compose/src/main/kotlin/ai/poly/examples/voice/compose/CallForegroundService.kt b/examples/voice/compose/src/main/kotlin/ai/poly/examples/voice/compose/CallForegroundService.kt new file mode 100644 index 0000000..a818e95 --- /dev/null +++ b/examples/voice/compose/src/main/kotlin/ai/poly/examples/voice/compose/CallForegroundService.kt @@ -0,0 +1,85 @@ +// Copyright PolyAI Limited + +package ai.poly.examples.voice.compose + +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.Service +import android.content.Context +import android.content.Intent +import android.content.pm.ServiceInfo +import android.os.Build +import android.os.IBinder +import android.os.PowerManager +import androidx.core.app.NotificationCompat +import androidx.core.app.ServiceCompat + +/** + * Keeps the process foregrounded — with a **microphone**-type foreground service — while a call is + * live, so Android doesn't cut background mic access or throttle the connection when the app is + * backgrounded. Without it, the OS tears the WebRTC peer down a few seconds after you leave the app + * and the SDK reports `CallState.Failed(PolyError.Voice.Disconnected)`. + * + * This belongs in the **app**, not the headless SDK (the SDK has no notification UI to show). Start it + * right before `call.start()` and [stop] it when the call ends. + */ +class CallForegroundService : Service() { + + private var wakeLock: PowerManager.WakeLock? = null + + override fun onBind(intent: Intent?): IBinder? = null + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + // Keep the CPU running for the WebRTC media/network threads while backgrounded — without it the + // OS throttles them, RTP stops, and the gateway times the call out even though the mic is alive. + if (wakeLock == null) { + wakeLock = getSystemService(PowerManager::class.java) + .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "poly:voice-call") + .apply { setReferenceCounted(false); acquire(60 * 60 * 1000L /* 1h safety cap */) } + } + createChannel() + val notification = NotificationCompat.Builder(this, CHANNEL_ID) + .setContentTitle("PolyAI voice call") + .setContentText("Call in progress") + .setSmallIcon(android.R.drawable.ic_btn_speak_now) + .setOngoing(true) + .build() + val type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE else 0 + ServiceCompat.startForeground(this, NOTIFICATION_ID, notification, type) + return START_NOT_STICKY + } + + override fun onDestroy() { + super.onDestroy() + wakeLock?.let { if (it.isHeld) it.release() } + wakeLock = null + } + + private fun createChannel() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val mgr = getSystemService(NotificationManager::class.java) + if (mgr.getNotificationChannel(CHANNEL_ID) == null) { + mgr.createNotificationChannel( + NotificationChannel(CHANNEL_ID, "Voice calls", NotificationManager.IMPORTANCE_LOW), + ) + } + } + } + + companion object { + private const val CHANNEL_ID = "poly_voice_call" + private const val NOTIFICATION_ID = 1001 + + /** Start the service (call from a foreground Activity, right before `call.start()`). */ + fun start(context: Context) { + val intent = Intent(context, CallForegroundService::class.java) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) context.startForegroundService(intent) + else context.startService(intent) + } + + /** Stop the service when the call ends. Safe to call when it isn't running. */ + fun stop(context: Context) { + context.stopService(Intent(context, CallForegroundService::class.java)) + } + } +} diff --git a/examples/voice/compose/src/main/kotlin/ai/poly/examples/voice/compose/MainActivity.kt b/examples/voice/compose/src/main/kotlin/ai/poly/examples/voice/compose/MainActivity.kt new file mode 100644 index 0000000..38ad452 --- /dev/null +++ b/examples/voice/compose/src/main/kotlin/ai/poly/examples/voice/compose/MainActivity.kt @@ -0,0 +1,201 @@ +// Copyright PolyAI Limited + +package ai.poly.examples.voice.compose + +import ai.poly.messaging.Configuration +import ai.poly.messaging.voice.CallState +import ai.poly.voice.AudioDevice +import ai.poly.voice.PolyVoice +import ai.poly.voice.VoiceOptions +import android.Manifest +import android.content.pm.PackageManager +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.compose.setContent +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.FilterChip +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.core.content.ContextCompat +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import kotlinx.coroutines.launch + +/** + * The smallest thing that makes a voice call: build a [ai.poly.voice.VoiceCall], request the mic + * permission, start/end it, and render its [CallState]. One screen, one button. + */ +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + MaterialTheme { + Surface(modifier = Modifier.fillMaxSize()) { CallScreen() } + } + } + } +} + +@Composable +private fun CallScreen() { + val context = androidx.compose.ui.platform.LocalContext.current + val scope = rememberCoroutineScope() + + // One call object for this screen; closed when the screen leaves the composition. + // Fill in your connector from Agent Studio › Connector Settings (see the README's "Use your own agent"). + val call = remember { + PolyVoice.call( + context = context, + config = Configuration( + apiKey = "YOUR_API_KEY", // connector token, sent as X-Token + // environment defaults to Environment.US; hostIdentifier defaults to this app's package name + ), + options = VoiceOptions(webrtcToken = "YOUR_WEBRTC_TOKEN"), // the connector's WebRTC token (distinct from apiKey) + ) + } + DisposableEffect(Unit) { onDispose { CallForegroundService.stop(context); call.close() } } + + val state by call.state.collectAsStateWithLifecycle() + val audio by call.audio.collectAsStateWithLifecycle() + var muted by remember { mutableStateOf(false) } + var autoOutput by remember { mutableStateOf(true) } // false once the user pins an output device + + // Stop the foreground service once the call leaves an active state (ended / failed). + LaunchedEffect(state) { + if (state is CallState.Ended || state is CallState.Failed) CallForegroundService.stop(context) + } + + // Start the mic foreground service BEFORE the call so it survives the app being backgrounded. + fun startCall() { + autoOutput = true + CallForegroundService.start(context) + scope.launch { runCatching { call.start() } } + } + + val requestMic = rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { granted -> + if (granted) startCall() + } + + fun toggleCall() { + when (state) { + is CallState.Connecting, is CallState.Connected -> scope.launch { call.end() } + else -> { + muted = false + val granted = ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO) == + PackageManager.PERMISSION_GRANTED + if (granted) startCall() else requestMic.launch(Manifest.permission.RECORD_AUDIO) + } + } + } + + val inCall = state is CallState.Connecting || state is CallState.Connected + val (status, statusColor) = statusFor(state) + + Column( + modifier = Modifier.fillMaxSize().padding(24.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + Text("PolyAI Voice", style = MaterialTheme.typography.headlineMedium) + Spacer(Modifier.height(8.dp)) + Text( + text = status, + color = statusColor, + textAlign = TextAlign.Center, + style = MaterialTheme.typography.bodyLarge, + ) + Spacer(Modifier.height(40.dp)) + + Button( + onClick = ::toggleCall, + enabled = state !is CallState.Connecting, + modifier = Modifier.fillMaxWidth().height(56.dp), + colors = if (inCall) ButtonDefaults.buttonColors(containerColor = Color(0xFFD32F2F)) else ButtonDefaults.buttonColors(), + ) { + Text( + when (state) { + is CallState.Connecting -> "Connecting…" + is CallState.Connected -> "End call" + else -> "Start call" + }, + ) + } + + if (state is CallState.Connected) { + Spacer(Modifier.height(12.dp)) + OutlinedButton( + onClick = { muted = !muted; scope.launch { call.setMuted(muted) } }, + modifier = Modifier.fillMaxWidth().height(48.dp), + ) { + Text(if (muted) "Unmute" else "Mute") + } + + // Audio output picker — tap to route the live call. The selection confirms via call.audio + // (Bluetooth can take a few seconds), so the highlight follows the flow, not the tap. + if (audio.availableDevices.isNotEmpty()) { + Spacer(Modifier.height(20.dp)) + Text("Audio output", style = MaterialTheme.typography.labelLarge, color = Color.DarkGray) + Spacer(Modifier.height(8.dp)) + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) { + // "Auto" follows the connected accessory / system default; tapping a device pins it. + FilterChip( + selected = autoOutput, + onClick = { autoOutput = true; scope.launch { call.setAudioDevice(null) } }, + label = { Text("Auto") }, + modifier = Modifier.padding(horizontal = 4.dp), + ) + audio.availableDevices.forEach { device -> + FilterChip( + selected = !autoOutput && device == audio.selectedDevice, + onClick = { autoOutput = false; scope.launch { call.setAudioDevice(device) } }, + label = { Text(labelFor(device)) }, + modifier = Modifier.padding(horizontal = 4.dp), + ) + } + } + } + } + } +} + +private fun labelFor(device: AudioDevice): String = when (device.type) { + AudioDevice.Type.SPEAKER_PHONE -> "Speaker" + AudioDevice.Type.EARPIECE -> "Phone" + AudioDevice.Type.WIRED_HEADSET -> "Headset" + AudioDevice.Type.BLUETOOTH -> device.name + AudioDevice.Type.UNKNOWN -> device.name +} + +private fun statusFor(state: CallState): Pair = when (state) { + is CallState.Idle -> "Tap to call the agent" to Color.DarkGray + is CallState.Connecting -> "Connecting…" to Color(0xFFEF6C00) + is CallState.Connected -> "Connected — say hello 👋" to Color(0xFF2E7D32) + is CallState.Ended -> "Call ended" to Color.DarkGray + is CallState.Failed -> "Failed: ${state.error.message}" to Color(0xFFD32F2F) +} diff --git a/examples/voice/compose/src/main/res/values/strings.xml b/examples/voice/compose/src/main/res/values/strings.xml new file mode 100644 index 0000000..4a66f1a --- /dev/null +++ b/examples/voice/compose/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Poly Voice + diff --git a/examples/voice/compose/src/main/res/values/themes.xml b/examples/voice/compose/src/main/res/values/themes.xml new file mode 100644 index 0000000..58ebef6 --- /dev/null +++ b/examples/voice/compose/src/main/res/values/themes.xml @@ -0,0 +1,5 @@ + + + +