@@ -34,8 +34,10 @@ import androidx.compose.ui.Modifier
3434import androidx.compose.ui.draw.clip
3535import androidx.compose.ui.platform.LocalContext
3636import androidx.compose.ui.semantics.Role
37+import androidx.compose.ui.semantics.contentDescription
3738import androidx.compose.ui.semantics.role
3839import androidx.compose.ui.semantics.semantics
40+import androidx.compose.ui.semantics.stateDescription
3941import androidx.compose.ui.text.font.FontFamily
4042import androidx.compose.ui.res.stringResource
4143import androidx.compose.ui.unit.dp
@@ -92,12 +94,17 @@ private fun ReasoningBlock(text: String, streaming: Boolean, modifier: Modifier)
9294 if (text.isBlank()) return
9395 val context = LocalContext.current
9496 var expanded by remember { mutableStateOf(false) }
97+ val expandedState = stringResource(R.string.state_expanded)
98+ val collapsedState = stringResource(R.string.state_collapsed)
9599 Column(modifier = modifier.fillMaxWidth()) {
96100 Row(
97101 modifier = Modifier
98102 .clickable { expanded = !expanded }
99103 .padding(vertical = 4.dp)
100− .semantics { role = Role.Button },
104+ .semantics {
105+ role = Role.Button
106+ stateDescription = if (expanded) expandedState else collapsedState
107+ },
101108 verticalAlignment = Alignment.CenterVertically,
102109 ) {
103110 if (streaming) {
@@ -167,6 +174,8 @@ private fun ToolCallView(part: ToolPart, modifier: Modifier) {
167174 if (detail != null) {
168175 val collapsed = remember(detail) { detail.take(COLLAPSED_LIMIT) }
169176 var expanded by remember(detail) { mutableStateOf(false) }
177+ val expandedState = stringResource(R.string.state_expanded)
178+ val collapsedState = stringResource(R.string.state_collapsed)
170179 val display = if (expanded || detail.length <= COLLAPSED_LIMIT) detail else collapsed
171180 if (looksLikeDiff(display)) {
172181 DiffView(display)
@@ -182,6 +191,9 @@ private fun ToolCallView(part: ToolPart, modifier: Modifier) {
182191 TextButton(
183192 onClick = { expanded = !expanded },
184193 contentPadding = androidx.compose.foundation.layout.PaddingValues(horizontal = 0.dp),
194+ modifier = Modifier.semantics {
195+ stateDescription = if (expanded) expandedState else collapsedState
196+ },
185197 ) {
186198 Icon(
187199 if (expanded) Icons.Filled.ExpandLess else Icons.Filled.ExpandMore,
@@ -210,13 +222,26 @@ private fun ToolCallView(part: ToolPart, modifier: Modifier) {
210222private fun ToolStatusIcon(state: ToolState) {
211223 when (state) {
212224 is ToolPending, is ToolRunning ->
213− CircularProgressIndicator(modifier = Modifier.size(16.dp), strokeWidth = 2.dp)
225+ CircularProgressIndicator(
226+ modifier = Modifier.size(16.dp).semantics { contentDescription = "" },
227+ strokeWidth = 2.dp,
228+ )
214229 is ToolCompleted ->
215− Icon(Icons.Filled.CheckCircle, null, Modifier.size(16.dp), tint = MaterialTheme.colorScheme.primary)
230+ Icon(
231+ Icons.Filled.CheckCircle,
232+ contentDescription = stringResource(R.string.tool_completed),
233+ modifier = Modifier.size(16.dp),
234+ tint = MaterialTheme.colorScheme.primary,
235+ )
216236 is ToolError ->
217− Icon(Icons.Filled.Error, null, Modifier.size(16.dp), tint = MaterialTheme.colorScheme.error)
237+ Icon(
238+ Icons.Filled.Error,
239+ contentDescription = stringResource(R.string.tool_error),
240+ modifier = Modifier.size(16.dp),
241+ tint = MaterialTheme.colorScheme.error,
242+ )
218243 is ToolUnknown ->
219− Icon(Icons.Filled.Bolt, null, Modifier.size(16.dp))
244+ Icon(Icons.Filled.Bolt, contentDescription = null, modifier = Modifier.size(16.dp))
220245 }
221246}
222247