AI Writing Assistant Text Field¶
Overview¶
The AiWritingAssistantTextField is a unified composable that provides both standard and AI-enhanced text input capabilities. It automatically adapts its behavior based on whether an AI data provider is supplied:
- Plain Mode: When
writingAssistDataProvider = null, renders a standardFioriNoteTextFieldwithout any AI features - AI-Enhanced Mode: When
writingAssistDataProvideris provided, adds a floating AI button and expandable bottom sheet intended for AI capabilities

Key Features¶
- Seamless Mode Switching: Pass
nullto use standard text field, or provide a data provider for AI features - Full
FioriNoteTextFieldSupport: All properties ofFioriNoteTextFieldare exposed and available - Floating AI Entry Button: Appears above the keyboard when focused
- Expandable Bottom Sheet: Displays AI actions and version controls
- Version Management: Built-in undo/redo with version tracking
- Feedback System: Thumbs up/down with detailed feedback collection
- Prompt Group Pages: Support for categorized AI prompts
- Customizable Content: Pass custom loading overlays and action layouts
- Keyboard Aware: Proper
IMEhandling for scrollable containers - Testable: Comprehensive test tags for UI automation
Quick Start¶
Using as Plain Text Field¶
Pass null for writingAssistDataProvider to use the component as a standard FioriNoteTextField:
var text by remember { mutableStateOf("") }
AiWritingAssistantTextField(
value = text,
onValueChange = { text = it },
writingAssistDataProvider = null, // No AI capabilities
content = FioriTextFieldContent(
label = "Enter your text",
required = true
)
)
Using with AI Capabilities¶
You enable AI features by providing the AiWritingAssistantDataProvider:
var text by remember { mutableStateOf("Initial text") }
val scope = rememberCoroutineScope()
val dataProvider = remember { MyAiDataProvider(text) }
// IMPORTANT: Initialize the data provider's state
dataProvider.RememberSavable()
AiWritingAssistantTextField(
value = text,
onValueChange = { text = it },
writingAssistDataProvider = dataProvider,
content = FioriTextFieldContent(label = "Goal Description"),
writingAssistEntryButtonText = "Writing Assistant",
aiActionsContent = { data ->
Column(
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.background(MaterialTheme.fioriHorizonAttributes.SapFioriColorBackground)
.padding(16.dp)
) {
AIActionButton(
text = "Make it shorter",
options = AIActionButtonOptions(
icon = FioriIcon(resId = R.drawable.ic_sap_icon_scissors),
enabled = !data.isLoading.value,
contentDescription = "Make Shorter"
)
) {
(data as MyAiDataProvider).makeItShort(scope)
}
AiActionDivider()
AIActionButton(
text = "Enhance writing",
options = AIActionButtonOptions(
icon = FioriIcon(resId = R.drawable.ic_sap_icon_write),
enabled = !data.isLoading.value
)
) {
(data as MyAiDataProvider).enhanceWriting(scope)
}
}
}
)
Parameters¶
AiWritingAssistantTextField exposes all parameters of FioriNoteTextField. It adds artificial intelligence-specific settings:
Core Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
value |
String |
Required | Current text value (ignored when writingAssistDataProvider is provided) |
onValueChange |
(String) -> Unit |
Auto | Callback when text changes. Default updates provider's state |
modifier |
Modifier |
Modifier |
Modifier for styling the text field |
writingAssistDataProvider |
AiWritingAssistantDataProvider? |
null |
Pass null for plain text field, or provide instance for AI features |
Fiori Note Text Field Properties¶
All properties from FioriNoteTextField are fully supported:
| Parameter | Type | Default | Description |
|---|---|---|---|
enabled |
Boolean |
true |
Whether the text field is enabled for interaction |
readOnly |
Boolean |
false |
Whether the text field is read-only |
textSelectable |
Boolean |
true |
Whether text can be selected when read-only |
isError |
Boolean |
false |
Whether to show error state |
content |
FioriTextFieldContent |
Default | Configuration (label, placeholder, inline notice, error message, etc.) |
trailingIcon |
FioriTextFieldIcon? |
Clear icon (AI mode) / null (plain) |
Trailing icon for the text field |
textStyles |
FioriTextFieldTextStyles |
Default | Text styles for field components |
colors |
FioriTextFieldColors |
Default | Color configuration for the text field |
styles |
FioriTextFieldStyles |
Default | Styles for the text field (min/max height, lines, etc.) |
keyboardOptions |
KeyboardOptions |
Default | Software keyboard options (keyboard type, IME action) |
keyboardActions |
KeyboardActions |
Default | Actions to handle IME events |
visualTransformation |
VisualTransformation |
None | Visual transformation (e.g., password masking) |
interactionSource |
MutableInteractionSource |
Default | Interaction source for tracking user interactions |
onHyperlinkClick |
(() -> Unit)? |
null |
Callback for hyperlink click in inline notice |
contentDescription |
String |
Auto | Accessibility description |
AI-Specific Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
sheetConfig |
AiWritingAssistantSheetConfig |
Default | Configuration for assistant sheet behavior (enabled, error states, feedback visibility) |
writingAssistCallbacks |
AiWritingAssistantSheetCallbacks |
Default | Runtime callbacks (thumbs up/down, feedback submission, navigation) |
writingAssistEntryButtonText |
String |
"Writing Assistant" | Label for the floating AI entry button |
aiActionsContent |
@Composable (AiWritingAssistantDataProvider) -> Unit |
Empty | Content for the assistant sheet (your AI action buttons) |
defaultFeedbackChips |
MutableList<ChipData> |
Default | Feedback options shown to users |
sheetColors |
WritingAssistantSheetColors |
Default | Color configuration for the sheet |
sheetStyles |
WritingAssistantSheetStyles |
Default | Style configuration for the sheet (max height, padding, etc.) |
sheetTextStyles |
WritingAssistantSheetTextStyles |
Default | Text style configuration for the sheet |
Writing Assistant Data Provider¶
An abstract class that manages text revisions and state for AI writing assistance. You must call RememberSavable() in a @Composable context before using it.
Key Properties¶
| Property | Type | Description |
|---|---|---|
textFieldValue |
MutableState<String> |
Current text value |
currentVersion |
MutableState<Int> |
Current revision version (1-based) |
totalVersions |
MutableState<Int> |
Total number of revisions |
isLoading |
MutableState<Boolean> |
Whether an AI operation is in progress |
versionFeedback |
MutableState<List<FeedbackData>> |
Feedback data for each version |
Key Methods¶
RememberSavable()- Required - Initializes state properties with proper state managementaddRevision(text: String)- Adds new text revisionacceptCurrentText()- Accepts current revision and clears historydiscardAllChanges()- Reverts to initial textgoPrevious()/goNext()- Navigate through revisionsenablePromptGroupPage(enable: Boolean, title: String = "")- Enable/disable categorized promptsgetCurrentText()- Get the current text valuesetCurrentText(text: String)- Set current text without creating revision
Implementation Example¶
class MyAiWritingAssistant(
initialText: String,
private val aiService: AiService
) : AiWritingAssistantDataProvider(initialText) {
fun makeItShort(scope: CoroutineScope) {
isLoading.value = true // Disables sheet interactions
scope.launch {
try {
val shortened = aiService.shortenText(getCurrentText())
addRevision(shortened)
} catch (e: Exception) {
// Handle error
} finally {
isLoading.value = false
}
}
}
fun enhanceWriting(scope: CoroutineScope) {
isLoading.value = true
scope.launch {
try {
val enhanced = aiService.enhanceText(getCurrentText())
addRevision(enhanced)
} finally {
isLoading.value = false
}
}
}
}
Configuration¶
Sheet Configuration¶
The AiWritingAssistantSheetConfig controls the assistant sheet’s behavior and appearance.
sheetConfig = AiWritingAssistantSheetConfig(
enabled = true,
isError = false,
errorMessageHeadline = "Unable to generate content",
errorActionText = "Retry",
showInlineFeedback = true,
thumbsEnabled = true,
showFooter = true
)
| Property | Type | Default | Description |
|---|---|---|---|
enabled |
Boolean |
true |
Whether interactive elements are enabled. Set to !data.isLoading.value to disable during requests |
isError |
Boolean |
false |
Shows error state in the default page |
isFeedbackError |
Boolean |
false |
[Deprecated] Error handling is now automatic via onFeedbackSubmitted callback |
errorMessageHeadline |
String? |
null |
Error message headline |
errorMessageDescription |
String? |
null |
Error message description |
errorActionText |
String? |
null |
Error action button text |
showInlineFeedback |
Boolean |
true |
Show inline thumbs up/down in the sheet |
thumbsEnabled |
Boolean |
true |
Enable thumbs buttons for interaction |
showFooter |
Boolean |
true |
Show the footer row (done/undo/redo buttons and version text) |
Sheet Callbacks¶
Use AiWritingAssistantSheetCallbacks to handle user interactions:
writingAssistCallbacks = AiWritingAssistantSheetCallbacks(
errorActionOnClick = { retryGeneration() },
onThumbsUpClicked = { version ->
analytics.trackThumbsUp(version)
},
onThumbsDownClicked = { version ->
analytics.trackThumbsDown(version)
},
onFeedbackSubmitted = { version, feedbackData ->
val deferred = CompletableDeferred<Unit>()
scope.launch {
try {
// Simulate network delay
delay(350)
apiService.submitFeedback(feedbackData)
deferred.complete(Unit)
} catch (e: Exception) {
// Error state will be shown automatically
deferred.completeExceptionally(e)
}
}
deferred
},
onVersionFeedbackChanged = { feedbackList ->
// Sync feedback state externally if needed
dataProvider.versionFeedback.value = feedbackList
},
onPromptGroupNavigateUp = {
dataProvider.disablePromptGroupPage()
}
)
| Callback | Parameters | Description |
|---|---|---|
errorActionOnClick |
() -> Unit |
Called when error action button is clicked |
onThumbsUpClicked |
(version: Int) -> Unit |
Called when thumbs up is clicked |
onThumbsDownClicked |
(version: Int) -> Unit |
Called when thumbs down is clicked |
onFeedbackSubmitted |
(version: Int, feedbackData: FeedbackData) -> Job |
Returns Job for async submission. If Job completes exceptionally, error state shown automatically |
onVersionFeedbackChanged |
(List<FeedbackData>) -> Unit |
Called when feedback list changes (for external state sync) |
onPromptGroupNavigateUp |
() -> Unit |
Called when navigating back from prompt group page |
Sheet Styles¶
You can customize the appearance of sheets with the WritingAssistantSheetStyles parameter:
sheetStyles = WritingAssistantSheetDefaults.styles(
sheetMaxHeight = 450.dp,
sheetMaxWidth = 640.dp,
sheetCornerRadius = 28.dp,
entryButtonPadding = 16.dp,
entryButtonTopPadding = 12.dp,
entryButtonBottomPadding = 12.dp,
entryButtonHeight = 64.dp,
feedbackTextToThumbsSpacing = 8.dp,
thumbsButtonSpacing = 4.dp
)
| Parameter | Type | Default | Description |
|---|---|---|---|
sheetMaxHeight |
Dp |
460.dp |
Maximum height of the expanded sheet |
sheetMaxWidth |
Dp |
640.dp |
Maximum width (useful for tablets/landscape) |
sheetCornerRadius |
Dp |
28.dp |
Corner radius for the top corners |
sheetPeakHeight |
Dp |
56.dp |
Height when in peek state |
sheetShadowElevation |
Dp |
1.dp |
Shadow elevation |
sheetTonalElevation |
Dp |
1.dp |
Tonal elevation for Material 3 |
entryButtonPadding |
Dp |
16.dp |
Horizontal padding for entry button |
entryButtonTopPadding |
Dp |
12.dp |
Top padding for entry button |
entryButtonBottomPadding |
Dp |
12.dp |
Bottom padding for entry button |
entryButtonHeight |
Dp |
64.dp |
Height of the entry button |
feedbackTextToThumbsSpacing |
Dp |
8.dp |
Spacing between feedback text and thumbs |
thumbsButtonSpacing |
Dp |
4.dp |
Spacing between thumbs up and down |
footerStyles |
WritingAssistantSheetFooterStyles |
Default | Styles for the footer section |
Advanced Usage¶
Using AI Action Button¶
Use the AIActionButton to create action buttons in the assistant sheet. It provides consistent styling, accessibility, and icon management:
aiActionsContent = { data ->
Column(
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.background(MaterialTheme.fioriHorizonAttributes.SapFioriColorBackground)
.padding(16.dp)
) {
AIActionButton(
text = "Enhance Writing",
options = AIActionButtonOptions(
icon = FioriIcon(resId = R.drawable.ic_sap_icon_write),
enabled = !data.isLoading.value,
contentDescription = "Enhance Writing",
showIcon = true
)
) {
(data as MyAiDataProvider).enhanceWriting(scope)
}
AiActionDivider()
AIActionButton(
text = "Make Shorter",
options = AIActionButtonOptions(
icon = FioriIcon(resId = R.drawable.ic_sap_icon_scissors),
enabled = !data.isLoading.value,
contentDescription = "Make Shorter"
)
) {
(data as MyAiDataProvider).makeItShort(scope)
}
AiActionDivider()
// Button without icon
AIActionButton(
text = "Other Options",
options = AIActionButtonOptions(
icon = FioriIcon(resId = R.drawable.ic_sap_icon_navigation_right_arrow),
enabled = !data.isLoading.value,
showIcon = false // Hide the icon
)
) {
data.enablePromptGroupPage(title = "Other Options", enable = true)
}
}
}
AI Action Button Options Properties:
contentDescription: Accessibility label for screen readersicon:FioriIconfor the button (defaults to AI icon)enabled: Whether the button is clickableshowIcon: Whether to display the icon (default:true)
Disabling Sheet Content During Requests¶
To prevent user interactions while processing AI requests, set isLoading.value to true in your data provider. This disables all sheet interactions:
class MyAiDataProvider(initialText: String) : AiWritingAssistantDataProvider(initialText) {
fun enhanceWriting(scope: CoroutineScope) {
// Disable all sheet interactions
isLoading.value = true
scope.launch {
try {
val response = aiService.enhance(getCurrentText())
addRevision(response)
} catch (e: Exception) {
// Handle error
} finally {
// Re-enable sheet interactions
isLoading.value = false
}
}
}
}
Then, in your sheet config, bind the enabled property:
sheetConfig = AiWritingAssistantSheetConfig(
enabled = !data.isLoading.value, // Disables during requests
// ... other config
)
Custom Loading Overlays¶

You can replace the default sheet content with custom loading indicators during request processing:
aiActionsContent = { data ->
if ((data as MyAiDataProvider).showCustomLoadingOverlay.value) {
// Show custom loading overlay
Box(
modifier = Modifier
.fillMaxWidth()
.background(Color.White)
.padding(vertical = 48.dp),
contentAlignment = Alignment.Center
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
AnimatedListDrawables(color = MaterialTheme.fioriHorizonAttributes.SapFioriColorS2)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = "Analyzing Text",
style = MaterialTheme.typography.bodyMedium
)
}
}
} else {
// Show normal action buttons
SheetActionsContent(data, scope)
}
}
In your data provider:
class MyAiDataProvider(initialText: String) : AiWritingAssistantDataProvider(initialText) {
var showCustomLoadingOverlay = mutableStateOf(false)
fun customAction(scope: CoroutineScope) {
showCustomLoadingOverlay.value = true
isLoading.value = true
scope.launch {
delay(3.seconds) // Simulate delay
addRevision("Custom action result: " + getCurrentText())
isLoading.value = false
showCustomLoadingOverlay.value = false
}
}
}
Scrollable Container Support¶
When AiWritingAssistantTextField components are in scrollable containers, you must apply imePadding() before verticalScroll(). This ensures proper keyboard handling.
Column(
modifier = Modifier
.padding(paddingValues)
.fillMaxSize()
.imePadding() // IMPORTANT: Must be BEFORE verticalScroll
.verticalScroll(scrollState)
) {
AiWritingAssistantTextField(
writingAssistDataProvider = data,
value = "Goal Description",
// ... other parameters
)
// Other scrollable content
}
Important: The correct order is:
imePadding()- Adjusts for keyboardverticalScroll()- Enables scrolling
This ensures the text field scrolls into view when the keyboard opens.
Prompt Group Pages¶
Support for categorized AI prompts with navigation:
AIActionButton(
text = "Other Options",
options = AIActionButtonOptions(
icon = FioriIcon(resId = R.drawable.ic_sap_icon_navigation_right_arrow),
enabled = !data.isLoading.value
)
) {
// Enable prompt group page with custom title
data.enablePromptGroupPage(title = "More Options", enable = true)
}
// Handle back navigation
writingAssistCallbacks = AiWritingAssistantSheetCallbacks(
onPromptGroupNavigateUp = {
data.enablePromptGroupPage(enable = false)
}
)
Hiding/Showing Footer¶
Control the visibility of the version-control footer (Done, Undo, and Redo buttons and version text):
sheetConfig = AiWritingAssistantSheetConfig(
showFooter = false // Hide the footer row
)
Use this when you show custom loading overlays. It provides a cleaner user interface during specific operations.
Writing Assistant Sheet¶
The sheet is used internally by AiWritingAssistantTextField and displays AI-generated content with version control and feedback.

Sheet Features¶
- Version control with undo/redo
- Thumbs up/down feedback
- Detailed feedback collection
- Error state handling
- Default page, feedback page, and prompt group page support
For detailed sheet configuration, see the Configuration section above.
Testing¶
The AI Writing Assistant provides comprehensive test tags for UI automation through AIWritingAssistantTestTags.
Enabling Test Mode¶
To test the entry button without a real keyboard, enable test mode:
@Test
fun testWritingAssistantButton() {
composeTestRule.setContent {
CompositionLocalProvider(LocalAIWritingAssistantTestMode provides true) {
AiWritingAssistantTextField(
writingAssistDataProvider = testDataProvider,
value = "Test"
)
}
}
// Entry button will be visible after focusing
composeTestRule.onNodeWithTag(AIWritingAssistantTestTags.TAG_ENTRY_BUTTON)
.assertIsDisplayed()
}
Available Test Tags¶
Access test tags through AIWritingAssistantTestTags or via the composition local:
val tags = AIWritingAssistantTestTags.Builder().build()
// Text Field Components
composeTestRule.onNodeWithTag(tags.textFieldTag) // Main text field
composeTestRule.onNodeWithTag(tags.entryButtonTag) // Floating AI button
// Bottom Sheet Components
composeTestRule.onNodeWithTag(tags.sheetTag) // Sheet container
composeTestRule.onNodeWithTag(tags.sheetContentTag) // Content area
composeTestRule.onNodeWithTag(tags.topAppBarTag) // Top app bar
composeTestRule.onNodeWithTag(tags.closeButtonTag) // Close button
// Footer Controls
composeTestRule.onNodeWithTag(tags.footerTag) // Footer container
composeTestRule.onNodeWithTag(tags.undoButtonTag) // Undo button
composeTestRule.onNodeWithTag(tags.redoButtonTag) // Redo button
composeTestRule.onNodeWithTag(tags.doneButtonTag) // Done button
composeTestRule.onNodeWithTag(tags.versionTextTag) // Version text
// Feedback Components
composeTestRule.onNodeWithTag(tags.thumbsUpButtonTag) // Thumbs up
composeTestRule.onNodeWithTag(tags.thumbsDownButtonTag) // Thumbs down
composeTestRule.onNodeWithTag(tags.feedbackTextTag) // Feedback text
// Dialog
composeTestRule.onNodeWithTag(tags.alertDialogTag) // Alert dialog
composeTestRule.onNodeWithTag(tags.alertDialogConfirmTag) // Confirm button
composeTestRule.onNodeWithTag(tags.alertDialogDismissTag) // Dismiss button
// Action Buttons (AIActionButton)
composeTestRule.onNodeWithTag(tags.actionButtonTag) // Button container
composeTestRule.onNodeWithTag(tags.actionButtonLabelTag) // Button text
composeTestRule.onNodeWithTag(tags.actionButtonIconTag) // Button icon
Custom Test Tags¶
You can customize test tags with identifiers:
val customTags = AIWritingAssistantTestTags.Builder()
.set(AIWritingAssistantTestTags::identifier, "my_test_case")
.build()
CompositionLocalProvider(
LocalAIWritingAssistantTestTagsManager provides AIWritingAssistantTestTagsManager(customTags)
) {
AiWritingAssistantTextField(...)
}
// Now all tags will be prefixed with "my_test_case_"
Test Tag Constants¶
All default test tag values are available as constants:
AIWritingAssistantTestTags.TAG_TEXT_FIELD // "ai_writing_assistant_text_field"
AIWritingAssistantTestTags.TAG_ENTRY_BUTTON // "ai_writing_assistant_entry_button"
AIWritingAssistantTestTags.TAG_SHEET // "ai_writing_assistant_sheet"
AIWritingAssistantTestTags.TAG_SHEET_CONTENT // "ai_writing_assistant_sheet_content"
AIWritingAssistantTestTags.TAG_TOP_APP_BAR // "ai_writing_assistant_top_app_bar"
AIWritingAssistantTestTags.TAG_CLOSE_BUTTON // "ai_writing_assistant_close_button"
AIWritingAssistantTestTags.TAG_FOOTER // "ai_writing_assistant_footer"
AIWritingAssistantTestTags.TAG_UNDO_BUTTON // "ai_writing_assistant_undo_button"
AIWritingAssistantTestTags.TAG_REDO_BUTTON // "ai_writing_assistant_redo_button"
AIWritingAssistantTestTags.TAG_DONE_BUTTON // "ai_writing_assistant_done_button"
AIWritingAssistantTestTags.TAG_VERSION_TEXT // "ai_writing_assistant_version_text"
AIWritingAssistantTestTags.TAG_THUMBS_UP_BUTTON // "ai_writing_assistant_thumbs_up_button"
AIWritingAssistantTestTags.TAG_THUMBS_DOWN_BUTTON // "ai_writing_assistant_thumbs_down_button"
AIWritingAssistantTestTags.TAG_FEEDBACK_TEXT // "ai_writing_assistant_feedback_text"
AIWritingAssistantTestTags.TAG_ALERT_DIALOG // "ai_writing_assistant_alert_dialog"
AIWritingAssistantTestTags.TAG_ALERT_DIALOG_CONFIRM // "ai_writing_assistant_alert_dialog_confirm"
AIWritingAssistantTestTags.TAG_ALERT_DIALOG_DISMISS // "ai_writing_assistant_alert_dialog_dismiss"
AIWritingAssistantTestTags.TAG_ACTION_BUTTON // "ai_writing_assistant_action_button"
AIWritingAssistantTestTags.TAG_ACTION_BUTTON_LABEL // "ai_writing_assistant_action_button_label"
AIWritingAssistantTestTags.TAG_ACTION_BUTTON_ICON // "ai_writing_assistant_action_button_icon"
Example Test¶
@Test
fun testAIWritingAssistantFlow() {
val dataProvider = TestAiDataProvider("Initial text")
composeTestRule.setContent {
CompositionLocalProvider(LocalAIWritingAssistantTestMode provides true) {
AiWritingAssistantTextField(
writingAssistDataProvider = dataProvider,
value = ""
)
}
}
// Focus text field
composeTestRule.onNodeWithTag(AIWritingAssistantTestTags.TAG_TEXT_FIELD)
.performClick()
// Click entry button
composeTestRule.onNodeWithTag(AIWritingAssistantTestTags.TAG_ENTRY_BUTTON)
.assertIsDisplayed()
.performClick()
// Verify sheet is shown
composeTestRule.onNodeWithTag(AIWritingAssistantTestTags.TAG_SHEET)
.assertIsDisplayed()
// Click thumbs up
composeTestRule.onNodeWithTag(AIWritingAssistantTestTags.TAG_THUMBS_UP_BUTTON)
.performClick()
// Click done
composeTestRule.onNodeWithTag(AIWritingAssistantTestTags.TAG_DONE_BUTTON)
.performClick()
// Verify sheet is dismissed
composeTestRule.onNodeWithTag(AIWritingAssistantTestTags.TAG_SHEET)
.assertDoesNotExist()
}
Related Components¶
- Feedback Sheet - Standalone feedback collection component
- Inline AI Feedback - Lightweight thumbs up/down component
API Reference¶
com.sap.cloud.mobile.fiori.compose.ai.aiwritingassistant.AiWritingAssistantTextFieldcom.sap.cloud.mobile.fiori.compose.ai.aiwritingassistant.AiWritingAssistantDataProvidercom.sap.cloud.mobile.fiori.compose.ai.aiwritingassistant.sheet.WritingAssistantSheetcom.sap.cloud.mobile.fiori.compose.ai.aiwritingassistant.sheet.AIActionButtoncom.sap.cloud.mobile.fiori.compose.ai.aiwritingassistant.AIWritingAssistantTestTags