dsh-agora 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +88 -0
  3. package/assets/agora/SKILL.md +113 -0
  4. package/assets/agora/references/cli/README.md +161 -0
  5. package/assets/agora/references/cli/automation.md +189 -0
  6. package/assets/agora/references/cli/doctor.md +129 -0
  7. package/assets/agora/references/cli/env.md +158 -0
  8. package/assets/agora/references/cli/install-auth.md +152 -0
  9. package/assets/agora/references/cli/projects.md +116 -0
  10. package/assets/agora/references/cli/quickstarts.md +117 -0
  11. package/assets/agora/references/cloud-recording/README.md +86 -0
  12. package/assets/agora/references/conversational-ai/README.md +285 -0
  13. package/assets/agora/references/conversational-ai/agent-client-toolkit-react.md +182 -0
  14. package/assets/agora/references/conversational-ai/agent-samples.md +101 -0
  15. package/assets/agora/references/conversational-ai/agent-toolkit-android.md +209 -0
  16. package/assets/agora/references/conversational-ai/agent-toolkit-ios.md +208 -0
  17. package/assets/agora/references/conversational-ai/agent-toolkit.md +201 -0
  18. package/assets/agora/references/conversational-ai/agent-ui-kit.md +63 -0
  19. package/assets/agora/references/conversational-ai/architecture.md +221 -0
  20. package/assets/agora/references/conversational-ai/auth-flow.md +154 -0
  21. package/assets/agora/references/conversational-ai/conversational-ai-studio.md +173 -0
  22. package/assets/agora/references/conversational-ai/go-sdk.md +184 -0
  23. package/assets/agora/references/conversational-ai/integration-from-quickstart.md +203 -0
  24. package/assets/agora/references/conversational-ai/python-sdk.md +122 -0
  25. package/assets/agora/references/conversational-ai/quickstarts.md +710 -0
  26. package/assets/agora/references/conversational-ai/server-custom-llm.md +45 -0
  27. package/assets/agora/references/conversational-ai/server-mcp.md +40 -0
  28. package/assets/agora/references/conversational-ai/server-sdk-rename.md +78 -0
  29. package/assets/agora/references/conversational-ai/server-sdks.md +128 -0
  30. package/assets/agora/references/doc-fetching.md +67 -0
  31. package/assets/agora/references/integration-patterns.md +201 -0
  32. package/assets/agora/references/mcp-tools.md +49 -0
  33. package/assets/agora/references/rtc/README.md +104 -0
  34. package/assets/agora/references/rtc/android.md +344 -0
  35. package/assets/agora/references/rtc/cross-platform-coordination.md +61 -0
  36. package/assets/agora/references/rtc/flutter.md +282 -0
  37. package/assets/agora/references/rtc/ios.md +306 -0
  38. package/assets/agora/references/rtc/nextjs.md +87 -0
  39. package/assets/agora/references/rtc/react-native.md +266 -0
  40. package/assets/agora/references/rtc/react.md +186 -0
  41. package/assets/agora/references/rtc/web.md +506 -0
  42. package/assets/agora/references/rtm/README.md +80 -0
  43. package/assets/agora/references/rtm/android.md +277 -0
  44. package/assets/agora/references/rtm/ios.md +231 -0
  45. package/assets/agora/references/rtm/web.md +348 -0
  46. package/assets/agora/references/server/README.md +22 -0
  47. package/assets/agora/references/server/tokens.md +74 -0
  48. package/assets/agora/references/server-gateway/README.md +80 -0
  49. package/assets/agora/references/server-gateway/linux-cpp.md +251 -0
  50. package/assets/agora/references/testing-guidance/SKILL.md +65 -0
  51. package/assets/agora/references/testing-guidance/completeness-gate.md +28 -0
  52. package/assets/agora/references/testing-guidance/convoai-rest.md +83 -0
  53. package/assets/agora/references/testing-guidance/mobile-rtm-and-renewal.md +109 -0
  54. package/assets/agora/references/testing-guidance/rtc-android.md +70 -0
  55. package/assets/agora/references/testing-guidance/rtc-ios.md +73 -0
  56. package/assets/agora/references/testing-guidance/rtc-react.md +51 -0
  57. package/assets/agora/references/testing-guidance/rtc-web.md +94 -0
  58. package/cordis.patch.yml +5 -0
  59. package/index.js +53 -0
  60. package/package.json +49 -0
@@ -0,0 +1,209 @@
1
+ # ConvoAI Agent Toolkit — Android (Kotlin)
2
+
3
+ The Android agent toolkit (`ConversationalAIAPIImpl`) wraps RTC + RTM to deliver AI transcripts, agent state, interrupts, and metrics. It is sourced from the Conversational AI Demo repo — not from the Agora SDK packages.
4
+
5
+ Source: `convoaiApi/IConversationalAIAPI.kt` and `ConversationalAIAPIImpl.kt` in the demo repo.
6
+
7
+ ## Table of Contents
8
+
9
+ - [Setup](#setup)
10
+ - [Initialization](#initialization)
11
+ - [Audio Configuration](#audio-configuration)
12
+ - [Subscribing to Events](#subscribing-to-events)
13
+ - [Sending Messages to the Agent](#sending-messages-to-the-agent)
14
+ - [Interrupting the Agent](#interrupting-the-agent)
15
+ - [Handling Events](#handling-events)
16
+ - [Cleanup](#cleanup)
17
+
18
+ ## Setup
19
+
20
+ The toolkit takes an existing `RtcEngine` and `RtmClient` — initialize both SDKs first.
21
+
22
+ ```kotlin
23
+ import io.agora.rtc2.RtcEngine
24
+ import io.agora.rtm.RtmClient
25
+ // Copy or import from the demo repo:
26
+ // io.agora.scene.convoai.convoaiApi.*
27
+ ```
28
+
29
+ ## Initialization
30
+
31
+ ```kotlin
32
+ // 1. Create your RTC engine and RTM client first (standard SDK init)
33
+ val rtcEngine: RtcEngine = // ... your existing engine
34
+ val rtmClient: RtmClient = // ... your existing RTM client (already logged in)
35
+
36
+ // 2. Create the toolkit config
37
+ val config = ConversationalAIAPIConfig(
38
+ rtcEngine = rtcEngine,
39
+ rtmClient = rtmClient,
40
+ renderMode = TranscriptRenderMode.Word, // Word (word-by-word) or Text (full sentence)
41
+ enableLog = true,
42
+ enableRenderModeFallback = true // fall back to Text if server lacks word timestamps
43
+ )
44
+
45
+ // 3. Create the API instance
46
+ val api = ConversationalAIAPIImpl(config)
47
+
48
+ // 4. Register your event handler
49
+ api.addHandler(eventHandler)
50
+ ```
51
+
52
+ ## Audio Configuration
53
+
54
+ **Must be called before `rtcEngine.joinChannel()`** to configure optimal AI audio settings.
55
+
56
+ ```kotlin
57
+ // Standard ConvoAI mode
58
+ api.loadAudioSettings()
59
+ // Equivalent to: api.loadAudioSettings(Constants.AUDIO_SCENARIO_AI_CLIENT)
60
+
61
+ // If using Avatar (requires audio mixing)
62
+ api.loadAudioSettings(Constants.AUDIO_SCENARIO_DEFAULT)
63
+
64
+ // Then join RTC channel
65
+ rtcEngine.joinChannel(token, channelName, uid, channelMediaOptions)
66
+ ```
67
+
68
+ ## Subscribing to Events
69
+
70
+ Subscribe after logging in to RTM and before the agent starts speaking.
71
+
72
+ ```kotlin
73
+ api.subscribeMessage(channelName) { error ->
74
+ if (error != null) {
75
+ Log.e("ConvoAI", "Subscribe failed: ${error.errorMessage}")
76
+ return@subscribeMessage
77
+ }
78
+ Log.d("ConvoAI", "Subscribed — ready to receive agent events")
79
+ }
80
+
81
+ // When done
82
+ api.unsubscribeMessage(channelName) { error -> }
83
+ ```
84
+
85
+ ## Sending Messages to the Agent
86
+
87
+ ```kotlin
88
+ // Text message (default priority: INTERRUPT)
89
+ val textMsg = TextMessage(
90
+ text = "What is the weather today?",
91
+ priority = Priority.INTERRUPT,
92
+ responseInterruptable = true
93
+ )
94
+ api.chat(agentUserId, textMsg) { error ->
95
+ if (error != null) Log.e("ConvoAI", "Chat failed: ${error.errorMessage}")
96
+ }
97
+
98
+ // Text with APPEND priority (queue after current response)
99
+ val appendMsg = TextMessage(text = "And tomorrow?", priority = Priority.APPEND)
100
+ api.chat(agentUserId, appendMsg) { }
101
+
102
+ // Image message (URL-based; keep base64 under 32KB total)
103
+ val imageMsg = ImageMessage(uuid = UUID.randomUUID().toString(), imageUrl = "https://example.com/photo.jpg")
104
+ api.chat(agentUserId, imageMsg) { error -> }
105
+ ```
106
+
107
+ ## Interrupting the Agent
108
+
109
+ ```kotlin
110
+ api.interrupt(agentUserId) { error ->
111
+ if (error != null) Log.e("ConvoAI", "Interrupt failed: ${error.errorMessage}")
112
+ }
113
+ ```
114
+
115
+ ## Handling Events
116
+
117
+ Implement `IConversationalAIAPIEventHandler`:
118
+
119
+ ```kotlin
120
+ val eventHandler = object : IConversationalAIAPIEventHandler {
121
+
122
+ // Agent state: IDLE | SILENT | LISTENING | THINKING | SPEAKING | UNKNOWN
123
+ override fun onAgentStateChanged(agentUserId: String, event: StateChangeEvent) {
124
+ Log.d("ConvoAI", "Agent $agentUserId state: ${event.state}, turn: ${event.turnId}")
125
+ runOnUiThread { updateStateIndicator(event.state) }
126
+ }
127
+
128
+ // Transcript update (fires frequently — dedup by turnId if needed)
129
+ override fun onTranscriptUpdated(agentUserId: String, transcript: Transcript) {
130
+ // transcript.type: TranscriptType.AGENT or .USER
131
+ // transcript.status: IN_PROGRESS | END | INTERRUPTED | UNKNOWN
132
+ // transcript.renderMode: Word or Text
133
+ runOnUiThread { updateTranscriptUI(transcript) }
134
+ }
135
+
136
+ // Agent interrupted mid-speech
137
+ override fun onAgentInterrupted(agentUserId: String, event: InterruptEvent) {
138
+ Log.d("ConvoAI", "Interrupted turn: ${event.turnId}")
139
+ }
140
+
141
+ // Performance metrics (LLM/TTS latency)
142
+ override fun onAgentMetrics(agentUserId: String, metric: Metric) {
143
+ Log.d("ConvoAI", "Metric: ${metric.type} ${metric.name} = ${metric.value}ms")
144
+ }
145
+
146
+ // Agent-side error (LLM/TTS failure)
147
+ override fun onAgentError(agentUserId: String, error: ModuleError) {
148
+ Log.e("ConvoAI", "Agent error: ${error.type} code=${error.code} ${error.message}")
149
+ }
150
+
151
+ // Message send error (e.g., image too large)
152
+ override fun onMessageError(agentUserId: String, error: MessageError) {
153
+ Log.e("ConvoAI", "Message error: ${error.chatMessageType} code=${error.code}")
154
+ }
155
+
156
+ // Message receipt (server acknowledged image/text)
157
+ override fun onMessageReceiptUpdated(agentUserId: String, receipt: MessageReceipt) {
158
+ Log.d("ConvoAI", "Receipt: ${receipt.type} turnId=${receipt.turnId}")
159
+ }
160
+
161
+ // Voiceprint registration status (technical preview)
162
+ override fun onAgentVoiceprintStateChanged(agentUserId: String, event: VoiceprintStateChangeEvent) {
163
+ Log.d("ConvoAI", "Voiceprint: ${event.status}")
164
+ }
165
+
166
+ // Internal debug messages — useful during development
167
+ override fun onDebugLog(log: String) {
168
+ Log.v("ConvoAI", log)
169
+ }
170
+ }
171
+ ```
172
+
173
+ ## Cleanup
174
+
175
+ ```kotlin
176
+ fun cleanup() {
177
+ api.unsubscribeMessage(channelName) { }
178
+ api.removeHandler(eventHandler)
179
+ api.destroy()
180
+ }
181
+ ```
182
+
183
+ Call `destroy()` when the conversation session ends. After this call the instance cannot be reused.
184
+
185
+ ## Key Types Reference
186
+
187
+ | Type | Purpose |
188
+ |------|---------|
189
+ | `ConversationalAIAPIConfig` | Init config: `rtcEngine`, `rtmClient`, `renderMode`, `enableLog` |
190
+ | `ConversationalAIAPIImpl` | Concrete implementation — create one per session |
191
+ | `IConversationalAIAPIEventHandler` | Interface for receiving all events |
192
+ | `TextMessage` | Text to send: `text`, `priority`, `responseInterruptable` |
193
+ | `ImageMessage` | Image to send: `uuid`, `imageUrl` or `imageBase64` (≤32KB) |
194
+ | `Priority` | `INTERRUPT` / `APPEND` / `IGNORE` |
195
+ | `AgentState` | `IDLE` / `SILENT` / `LISTENING` / `THINKING` / `SPEAKING` |
196
+ | `Transcript` | `turnId`, `text`, `type` (AGENT/USER), `status`, `renderMode` |
197
+ | `TranscriptRenderMode` | `Word` (word-level) or `Text` (full sentence) |
198
+ | `StateChangeEvent` | `state`, `turnId`, `timestamp` |
199
+ | `Metric` | `type` (LLM/TTS), `name`, `value` (ms), `timestamp` |
200
+ | `ConversationalAIAPIError` | Sealed: `RtmError(code, msg)`, `RtcError(code, msg)`, `UnknownError(msg)` |
201
+
202
+ ## Notes
203
+
204
+ - `onTranscriptUpdated` fires at high frequency. Deduplicate on `turnId` in your UI if needed.
205
+ - All callbacks are dispatched on the main thread — safe for UI updates.
206
+ - The `renderMode = Word` setting falls back to `Text` automatically if the server doesn't provide word timestamps (when `enableRenderModeFallback = true`).
207
+ - Agent state arrives via RTM presence events (REMOTE_STATE_CHANGED); transcripts arrive via RTM channel messages.
208
+ - Image payloads via `imageBase64` must keep the total JSON message under 32KB. Use `imageUrl` for larger images.
209
+ - Audio routing changes re-apply audio parameters automatically via `onAudioRouteChanged`.
@@ -0,0 +1,208 @@
1
+ # ConvoAI Agent Toolkit — iOS (Swift)
2
+
3
+ The iOS agent toolkit (`ConversationalAIAPIImpl`) wraps RTC + RTM to deliver AI transcripts, agent state, interrupts, and metrics. It is sourced from the Conversational AI Demo repo — not from the Agora SDK packages.
4
+
5
+ Source: `ConversationalAIAPI/ConversationalAIAPI.swift` and `ConversationalAIAPIImpl.swift` in the demo repo.
6
+
7
+ ## Table of Contents
8
+
9
+ - [Setup](#setup)
10
+ - [Initialization](#initialization)
11
+ - [Audio Configuration](#audio-configuration)
12
+ - [Subscribing to Events](#subscribing-to-events)
13
+ - [Sending Messages to the Agent](#sending-messages-to-the-agent)
14
+ - [Interrupting the Agent](#interrupting-the-agent)
15
+ - [Handling Events](#handling-events)
16
+ - [Cleanup](#cleanup)
17
+
18
+ ## Setup
19
+
20
+ The toolkit takes an existing `AgoraRtcEngineKit` and `AgoraRtmClientKit` — initialize both SDKs first.
21
+
22
+ ```swift
23
+ import AgoraRtcKit
24
+ import AgoraRtmKit
25
+ import ConversationalAIAPI // or copy files directly from the demo repo
26
+ ```
27
+
28
+ ## Initialization
29
+
30
+ ```swift
31
+ // 1. Create your RTC engine and RTM client first (standard SDK init)
32
+ let rtcEngine: AgoraRtcEngineKit = // ... your existing engine
33
+ let rtmKit: AgoraRtmClientKit = // ... your existing RTM client (already logged in)
34
+
35
+ // 2. Create the toolkit config
36
+ let config = ConversationalAIAPIConfig(
37
+ rtcEngine: rtcEngine,
38
+ rtmEngine: rtmKit,
39
+ renderMode: .words, // .words (word-by-word) or .text (full sentence)
40
+ enableLog: true,
41
+ enableRenderModeFallback: true // fall back to .text if server lacks word timestamps
42
+ )
43
+
44
+ // 3. Create the API instance
45
+ let api = ConversationalAIAPIImpl(config: config)
46
+
47
+ // 4. Register your event handler
48
+ api.addHandler(handler: self) // self implements ConversationalAIAPIEventHandler
49
+ ```
50
+
51
+ ## Audio Configuration
52
+
53
+ **Must be called before `joinChannel`** on every join to configure optimal AI audio settings.
54
+
55
+ ```swift
56
+ // Standard ConvoAI mode
57
+ api.loadAudioSettings()
58
+ // Equivalent to: api.loadAudioSettings(secnario: .aiClient)
59
+
60
+ // If using Avatar (requires audio mixing)
61
+ api.loadAudioSettings(secnario: .default)
62
+
63
+ // Then join RTC channel
64
+ rtcEngine.joinChannel(byToken: token, channelId: channelName, info: nil, uid: userId)
65
+ ```
66
+
67
+ ## Subscribing to Events
68
+
69
+ Subscribe after logging in to RTM and before the agent starts speaking.
70
+
71
+ ```swift
72
+ api.subscribeMessage(channelName: channelName) { error in
73
+ if let error = error {
74
+ print("Subscribe failed: \(error)")
75
+ return
76
+ }
77
+ print("Subscribed — ready to receive agent events")
78
+ }
79
+
80
+ // When done
81
+ api.unsubscribeMessage(channelName: channelName) { error in }
82
+ ```
83
+
84
+ ## Sending Messages to the Agent
85
+
86
+ ```swift
87
+ // Text message (default priority: INTERRUPT)
88
+ let textMsg = TextMessage(
89
+ text: "What is the weather today?",
90
+ priority: .interrupt,
91
+ responseInterruptable: true
92
+ )
93
+ api.chat(agentUserId: agentUid, message: textMsg) { error in
94
+ if let error = error { print("Chat failed: \(error)") }
95
+ }
96
+
97
+ // Text with APPEND priority (queue after current response)
98
+ let appendMsg = TextMessage(text: "And tomorrow?", priority: .append)
99
+ api.chat(agentUserId: agentUid, message: appendMsg) { _ in }
100
+
101
+ // Image message (URL-based; keep base64 under 32KB total)
102
+ let imageMsg = ImageMessage(uuid: UUID().uuidString, imageUrl: "https://example.com/photo.jpg")
103
+ api.chat(agentUserId: agentUid, message: imageMsg) { error in }
104
+ ```
105
+
106
+ ## Interrupting the Agent
107
+
108
+ ```swift
109
+ api.interrupt(agentUserId: agentUid) { error in
110
+ if let error = error { print("Interrupt failed: \(error)") }
111
+ }
112
+ ```
113
+
114
+ ## Handling Events
115
+
116
+ Implement `ConversationalAIAPIEventHandler`:
117
+
118
+ ```swift
119
+ extension YourViewController: ConversationalAIAPIEventHandler {
120
+
121
+ // Agent state: .silent | .listening | .thinking | .speaking | .idle | .unknown
122
+ func onAgentStateChanged(agentUserId: String, event: StateChangeEvent) {
123
+ print("Agent \(agentUserId) state: \(event.state), turn: \(event.turnId)")
124
+ DispatchQueue.main.async {
125
+ self.updateStateIndicator(event.state)
126
+ }
127
+ }
128
+
129
+ // Transcript update (fires frequently — dedup by turnId if needed)
130
+ func onTranscriptUpdated(agentUserId: String, transcript: Transcript) {
131
+ // transcript.type: .agent or .user
132
+ // transcript.status: .inProgress | .end | .interrupted | .unknown
133
+ // transcript.renderMode: .words or .text
134
+ DispatchQueue.main.async {
135
+ self.updateTranscriptUI(transcript)
136
+ }
137
+ }
138
+
139
+ // Agent interrupted mid-speech
140
+ func onAgentInterrupted(agentUserId: String, event: InterruptEvent) {
141
+ print("Interrupted turn: \(event.turnId)")
142
+ }
143
+
144
+ // Performance metrics (LLM/TTS latency)
145
+ func onAgentMetrics(agentUserId: String, metrics: Metric) {
146
+ print("Metric: \(metrics.type) \(metrics.name) = \(metrics.value)ms")
147
+ }
148
+
149
+ // Agent-side error (LLM/TTS failure)
150
+ func onAgentError(agentUserId: String, error: ModuleError) {
151
+ print("Agent error: \(error.type) code=\(error.code) \(error.message)")
152
+ }
153
+
154
+ // Message send error (e.g., image too large)
155
+ func onMessageError(agentUserId: String, error: MessageError) {
156
+ print("Message error: \(error.chatMessageType) code=\(error.code)")
157
+ }
158
+
159
+ // Message receipt (server acknowledged image/text)
160
+ func onMessageReceiptUpdated(agentUserId: String, messageReceipt: MessageReceipt) {
161
+ print("Receipt: \(messageReceipt.type) turnId=\(messageReceipt.turnId)")
162
+ }
163
+
164
+ // Voiceprint registration status (technical preview)
165
+ func onAgentVoiceprintStateChanged(agentUserId: String, event: VoiceprintStateChangeEvent) {
166
+ print("Voiceprint: \(event.status)")
167
+ }
168
+
169
+ func onDebugLog(log: String) {
170
+ // Internal debug messages — useful during development
171
+ }
172
+ }
173
+ ```
174
+
175
+ ## Cleanup
176
+
177
+ ```swift
178
+ func cleanup() {
179
+ api.unsubscribeMessage(channelName: channelName) { _ in }
180
+ api.removeHandler(handler: self)
181
+ api.destroy()
182
+ }
183
+ ```
184
+
185
+ Call `destroy()` when the conversation session ends. After this call the instance cannot be reused.
186
+
187
+ ## Key Types Reference
188
+
189
+ | Type | Purpose |
190
+ |------|---------|
191
+ | `ConversationalAIAPIConfig` | Init config: `rtcEngine`, `rtmEngine`, `renderMode`, `enableLog` |
192
+ | `ConversationalAIAPIImpl` | Concrete implementation — create one per session |
193
+ | `ConversationalAIAPIEventHandler` | Protocol for receiving all events |
194
+ | `TextMessage` | Text to send: `text`, `priority`, `responseInterruptable` |
195
+ | `ImageMessage` | Image to send: `uuid`, `imageUrl` or `imageBase64` (≤32KB) |
196
+ | `Priority` | `.interrupt` / `.append` / `.ignore` |
197
+ | `AgentState` | `.silent` / `.listening` / `.thinking` / `.speaking` |
198
+ | `Transcript` | `turnId`, `text`, `type` (agent/user), `status`, `renderMode` |
199
+ | `TranscriptRenderMode` | `.words` (word-level) or `.text` (full sentence) |
200
+ | `StateChangeEvent` | `state`, `turnId`, `timestamp` |
201
+ | `Metric` | `type` (LLM/TTS), `name`, `value` (ms), `timestamp` |
202
+
203
+ ## Notes
204
+
205
+ - `onTranscriptUpdated` fires at high frequency. Deduplicate on `turnId` in your UI if needed.
206
+ - The `renderMode: .words` setting falls back to `.text` automatically if the server doesn't provide word timestamps (when `enableRenderModeFallback: true`).
207
+ - Agent state arrives via RTM presence events; transcripts arrive via RTM channel messages.
208
+ - Image payloads via `imageBase64` must keep the total JSON message under 32KB. Use `imageUrl` for larger images.
@@ -0,0 +1,201 @@
1
+ ---
2
+ name: agora-agent-client-toolkit
3
+ description: |
4
+ Client-side TypeScript SDK for adding Agora Conversational AI features to applications
5
+ already using the Agora RTC SDK. Use when the user needs to integrate agora-agent-client-toolkit
6
+ or agora-agent-client-toolkit-react, receive transcripts, track agent state, send messages
7
+ to an AI agent, handle agent events, or build a ConvoAI front-end client. Triggers on
8
+ agora-agent-client-toolkit, AgoraVoiceAI, useConversationalAI, useTranscript, useAgentState,
9
+ agent transcript, agent state, TRANSCRIPT_UPDATED, AGENT_STATE_CHANGED, ConversationalAIProvider.
10
+ license: MIT
11
+ metadata:
12
+ author: agora
13
+ version: '1.0.0'
14
+ ---
15
+
16
+ # Agent Client Toolkit
17
+
18
+ Client-side SDK for adding Agora Conversational AI features to applications already using the Agora RTC SDK. Runs in the browser — adds transcript rendering, agent state tracking, and RTM-based messaging controls on top of `agora-rtc-sdk-ng`.
19
+
20
+ **npm:** `agora-agent-client-toolkit` (core) · `agora-agent-client-toolkit-react` (React hooks)
21
+ **Repo:** <https://github.com/AgoraIO-Conversational-AI/agent-client-toolkit-ts>
22
+
23
+ > This toolkit is a **client add-on** — it does not start agents. Start agents via the ConvoAI REST API first. See [README.md](README.md) for the REST API.
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ npm install agora-agent-client-toolkit agora-rtc-sdk-ng agora-rtm
29
+
30
+ # React
31
+ npm install agora-agent-client-toolkit-react agora-rtc-react agora-rtm
32
+ ```
33
+
34
+ ## Initialization
35
+
36
+ `AgoraVoiceAI.init()` is **async** — always `await` it. Pass the RTC client you already have.
37
+
38
+ ```typescript
39
+ import AgoraRTC from 'agora-rtc-sdk-ng';
40
+ import AgoraRTM from 'agora-rtm';
41
+ import { AgoraVoiceAI } from 'agora-agent-client-toolkit';
42
+
43
+ // Your existing RTC + RTM setup
44
+ const rtcClient = AgoraRTC.createClient({ mode: 'rtc', codec: 'vp8' });
45
+ const rtmClient = new AgoraRTM.RTM('APP_ID', 'RTM_USER_ID'); // must match the RTM token subject; often String(rtcUid)
46
+ await rtmClient.login({ token: 'RTM_TOKEN' });
47
+
48
+ // Initialize the toolkit — pass your existing clients
49
+ const ai = await AgoraVoiceAI.init({
50
+ rtcEngine: rtcClient,
51
+ rtmConfig: { rtmEngine: rtmClient }, // optional — needed for sendText/interrupt
52
+ });
53
+
54
+ // Join + publish via RTC directly (toolkit does not wrap join/publish)
55
+ await rtcClient.join('APP_ID', 'CHANNEL', 'RTC_TOKEN', null);
56
+ const micTrack = await AgoraRTC.createMicrophoneAudioTrack();
57
+ await rtcClient.publish([micTrack]);
58
+
59
+ // Start receiving agent messages
60
+ ai.subscribeMessage('CHANNEL');
61
+ ```
62
+
63
+ ## Configuration
64
+
65
+ | Field | Type | Required | Description |
66
+ | -------------------- | -------------------------- | -------- | ------------------------------------------------------------------- |
67
+ | `rtcEngine` | `IAgoraRTCClient` | Yes | Your existing Agora RTC client |
68
+ | `rtmConfig` | `{ rtmEngine: RTMClient }` | No | Pass your RTM client for sendText/interrupt |
69
+ | `renderMode` | `TranscriptHelperMode` | No | `TEXT`, `WORD`, `CHUNK`, `AUTO` (default: `AUTO`) — see table below |
70
+ | `enableLog` | `boolean` | No | Debug logging (default: `false`) |
71
+ | `enableAgoraMetrics` | `boolean` | No | Load `@agora-js/report` for usage metrics |
72
+
73
+ ### Render Modes
74
+
75
+ | Mode | Update cadence | Word timing in metadata | PTS required | When to use |
76
+ | ------- | ---------------------------- | --------------------------------------- | ------------------------------------ | ------------------------------------------------------------- |
77
+ | `TEXT` | Per sentence (`final: true`) | No | No | Lowest overhead; subtitles |
78
+ | `WORD` | Per word | Yes (`words[].start_ms`, `duration_ms`) | **Yes** (before RTC client creation) | Karaoke-style highlight |
79
+ | `CHUNK` | When all parts reassembled | No | No | Fragmented transport |
80
+ | `AUTO` | Detected from first message | Depends on detected mode | If WORD detected | Default; fine unless you need WORD and must pre-configure PTS |
81
+
82
+ ## Events
83
+
84
+ Register handlers before calling `subscribeMessage()`. All 9 events:
85
+
86
+ ```typescript
87
+ import { AgoraVoiceAIEvents } from 'agora-agent-client-toolkit';
88
+
89
+ // Transcript — delivers FULL history every time, replace don't append
90
+ ai.on(AgoraVoiceAIEvents.TRANSCRIPT_UPDATED, (transcript) => {
91
+ renderTranscript(transcript);
92
+ });
93
+
94
+ // Agent state — requires RTM + enable_rtm: true in agent start config
95
+ ai.on(AgoraVoiceAIEvents.AGENT_STATE_CHANGED, (agentUserId, event) => {
96
+ // event.state: 'idle' | 'listening' | 'thinking' | 'speaking' | 'silent'
97
+ updateStatusUI(event.state);
98
+ });
99
+
100
+ // Agent interrupted (user cut off agent's response)
101
+ ai.on(AgoraVoiceAIEvents.AGENT_INTERRUPTED, (agentUserId, event) => {
102
+ // event: { turnID: number, timestamp: number }
103
+ });
104
+
105
+ // Performance metrics — requires enable_metrics: true in agent start config
106
+ ai.on(AgoraVoiceAIEvents.AGENT_METRICS, (agentUserId, metrics) => {
107
+ // metrics: { type: ModuleType, name: string, value: number, timestamp: number }
108
+ // ModuleType: 'llm' | 'mllm' | 'tts' | 'context' | 'unknown'
109
+ });
110
+
111
+ // Agent pipeline error — requires enable_error_message: true in agent start config
112
+ ai.on(AgoraVoiceAIEvents.AGENT_ERROR, (agentUserId, error) => {
113
+ // error: { type: ModuleType, code: number, message: string, timestamp: number }
114
+ showErrorToast(error.message);
115
+ });
116
+
117
+ // Message delivery receipt — requires RTM
118
+ ai.on(AgoraVoiceAIEvents.MESSAGE_RECEIPT_UPDATED, (agentUserId, receipt) => {});
119
+
120
+ // RTM message delivery failure
121
+ ai.on(AgoraVoiceAIEvents.MESSAGE_ERROR, (agentUserId, error) => {});
122
+
123
+ // Speech Activity Level registration status — requires RTM
124
+ ai.on(AgoraVoiceAIEvents.MESSAGE_SAL_STATUS, (agentUserId, salStatus) => {});
125
+
126
+ // Internal debug log
127
+ ai.on(AgoraVoiceAIEvents.DEBUG_LOG, (message) => {});
128
+ ```
129
+
130
+ ## Sending Messages & Interrupting
131
+
132
+ Requires `rtmConfig` — throws `RTMRequiredError` if called without RTM.
133
+
134
+ ```typescript
135
+ import {
136
+ ChatMessageType,
137
+ ChatMessagePriority,
138
+ } from 'agora-agent-client-toolkit';
139
+
140
+ // Send text to the agent
141
+ await ai.sendText(agentUserId, {
142
+ messageType: ChatMessageType.TEXT,
143
+ text: 'What is the weather like today?',
144
+ priority: ChatMessagePriority.INTERRUPTED, // interrupts current agent speech
145
+ responseInterruptable: true,
146
+ });
147
+
148
+ // Send image to the agent
149
+ await ai.sendImage(agentUserId, {
150
+ messageType: ChatMessageType.IMAGE,
151
+ uuid: crypto.randomUUID(), // caller-generated unique ID for receipt correlation
152
+ url: 'https://example.com/image.png', // or: base64: '<inline data>'
153
+ });
154
+
155
+ // Interrupt the agent's current speech
156
+ await ai.interrupt(agentUserId);
157
+ ```
158
+
159
+ ### `ChatMessagePriority` values
160
+
161
+ | Value | Behavior |
162
+ | ------------- | ------------------------------------------------------------------------------------------------------ |
163
+ | `INTERRUPTED` | Sends the message and immediately interrupts any speech the agent is currently producing |
164
+ | `APPEND` | Queues the message to be processed after the agent finishes its current speech turn |
165
+ | `IGNORE` | Drops the message silently if the agent is busy — use for low-priority updates only relevant when idle |
166
+
167
+ `responseInterruptable: boolean` on `ChatMessageText` — when `true`, the agent's response to this message can itself be interrupted by subsequent user input.
168
+
169
+ ### `ChatMessageImage` fields
170
+
171
+ | Field | Required | Description |
172
+ | ------------- | ----------------- | -------------------------------------------------------------------------------- |
173
+ | `messageType` | Yes | Must be `ChatMessageType.IMAGE` |
174
+ | `uuid` | Yes | Caller-generated unique ID for receipt correlation via `MESSAGE_RECEIPT_UPDATED` |
175
+ | `url` | One of url/base64 | Publicly accessible image URL |
176
+ | `base64` | One of url/base64 | Inline image data |
177
+
178
+ ## Cleanup
179
+
180
+ ```typescript
181
+ ai.unsubscribe(); // stop receiving channel messages
182
+ ai.destroy(); // remove all event handlers, clear singleton
183
+
184
+ await rtmClient.logout(); // you manage RTM lifecycle
185
+ ```
186
+
187
+ ## Critical Rules
188
+
189
+ 1. **`init()` is async** — always `await AgoraVoiceAI.init()`. Missing the await causes `getInstance()` to throw `NotInitializedError`.
190
+ 2. **Register events before `subscribeMessage()`** — events from messages already in the stream will be missed otherwise.
191
+ 3. **Transcript replaces, never appends** — `TRANSCRIPT_UPDATED` delivers the complete history every time. Set state to the full array, not `prev.concat(next)`.
192
+ 4. **`AgoraVoiceAI` is a singleton** — calling `init()` twice replaces the first instance. Call `destroy()` before re-initializing.
193
+ 5. **RTM is optional but required for several features** — `sendText`, `sendImage`, and `interrupt` throw `RTMRequiredError` without `rtmConfig`. `AGENT_STATE_CHANGED`, `MESSAGE_RECEIPT_UPDATED`, `MESSAGE_ERROR`, `MESSAGE_SAL_STATUS` only fire with RTM.
194
+ 6. **Agent start config flags are required for some events** — `AGENT_STATE_CHANGED` requires `advanced_features.enable_rtm: true` AND `parameters.data_channel: "rtm"`. `AGENT_METRICS` requires `parameters.enable_metrics: true`. `AGENT_ERROR` requires `parameters.enable_error_message: true`.
195
+ 7. **Toolkit does not wrap join/publish** — call `rtcClient.join()` and `rtcClient.publish()` yourself before `subscribeMessage()`.
196
+ 8. **WORD mode requires PTS metadata enabled before RTC client creation** — if `renderMode` is `TranscriptHelperMode.WORD`, call `AgoraRTC.setParameter('ENABLE_AUDIO_PTS_METADATA', true)` before calling `AgoraRTC.createClient()`. Setting it after client creation produces no error — word-level timing data simply never arrives. This also applies when using `AUTO` mode if WORD is detected; prefer explicit `WORD` mode when karaoke display is required so the pre-configuration step is obvious.
197
+ 9. **RTM identity must match the RTM token subject** — if your RTM token was minted for `String(rtcUid)`, create or log in the RTM client with that same identity. Do not mint an RTM token for one user and log in RTM with another random ID; that can show up as generic conversation-start failures instead of a clear auth error.
198
+
199
+ ## React Hooks
200
+
201
+ For React integration, see **[agent-client-toolkit-react.md](agent-client-toolkit-react.md)**.
@@ -0,0 +1,63 @@
1
+ # Agent UI Kit
2
+
3
+ React component library (`@agora/agent-ui-kit`) — pre-built UI for ConvoAI interfaces.
4
+
5
+ **Repo:** <https://github.com/AgoraIO-Conversational-AI/agent-ui-kit>
6
+ **npm:** `@agora/agent-ui-kit`
7
+
8
+ ## Voice Components
9
+
10
+ - `MicButton` — microphone toggle
11
+ - `AgentVisualizer` — agent state indicator (not-joined/listening/talking/thinking)
12
+ - `AudioVisualizer` — audio level bars
13
+ - `LiveWaveform` — real-time waveform display
14
+ - `MicSelector` — microphone device picker
15
+ - `SimpleVisualizer` — simplified audio visualizer
16
+ - `MicButtonWithVisualizer` — combined mic toggle + audio visualization
17
+
18
+ > **[README — Voice Components](https://github.com/AgoraIO-Conversational-AI/agent-ui-kit#voice-components)**
19
+
20
+ ## Chat Components
21
+
22
+ - `Conversation` — auto-scroll chat container
23
+ - `Message` — user/assistant message bubbles
24
+ - `ConvoTextStream` — typewriter streaming text effect
25
+ - `Response` — structured agent response display
26
+
27
+ > **[README — Chat Components](https://github.com/AgoraIO-Conversational-AI/agent-ui-kit#chat-components)**
28
+
29
+ ## Video Components
30
+
31
+ - `LocalVideoPreview` — local camera with mirror mode
32
+ - `AvatarVideoDisplay` — remote avatar video with connection states
33
+ - `CameraSelector` — camera device picker
34
+ - `Avatar` — avatar video display with connection-aware states
35
+
36
+ > **[README — Video Components](https://github.com/AgoraIO-Conversational-AI/agent-ui-kit#video-components)**
37
+
38
+ ## Settings Components
39
+
40
+ - `AgentSettings` — AIVAD toggle, language, prompt, greeting
41
+ - `SettingsDialog` — modal wrapper
42
+
43
+ > **[README — Settings Components](https://github.com/AgoraIO-Conversational-AI/agent-ui-kit#settings-components)**
44
+
45
+ ## Layout Components
46
+
47
+ - `VideoGrid` — 2x2 desktop grid
48
+ - `MobileTabs` — tab switcher
49
+ - `VideoGridWithControls` — video grid with integrated media controls
50
+
51
+ > **[README — Layout Components](https://github.com/AgoraIO-Conversational-AI/agent-ui-kit#layout-components)**
52
+
53
+ ## Hooks
54
+
55
+ - `useRTMSubscription` — generic RTM message subscription by object type
56
+
57
+ > **[README — Hooks](https://github.com/AgoraIO-Conversational-AI/agent-ui-kit#hooks)**
58
+
59
+ ## Theming
60
+
61
+ Tailwind CSS-based theming.
62
+
63
+ > **[README — Theming](https://github.com/AgoraIO-Conversational-AI/agent-ui-kit#theming)**