Skip to content

Commit 4725c28

Browse files
committed
Refactor message handling
1 parent df5cebc commit 4725c28

File tree

13 files changed

+94
-52
lines changed

13 files changed

+94
-52
lines changed
Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
11
package com.instructure.canvasapi2.models.journey
22

33
data class JourneyAssistChatMessage(
4-
val id: String,
5-
val prompt: String = "",
64
val text: String = "",
75
val role: JourneyAssistRole,
8-
val chipOptions: List<JourneyAssistChipOption> = emptyList(),
9-
val flashCards: List<JourneyAssistFlashCard> = emptyList(),
10-
val quizItems: List<JourneyAssistQuizItem> = emptyList(),
11-
val citations: List<JourneyAssistCitation> = emptyList(),
126
)
137

libs/horizon/src/main/java/com/instructure/horizon/features/aiassistant/chat/AiAssistChatScreen.kt

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ import androidx.compose.ui.text.input.TextFieldValue
3131
import androidx.compose.ui.tooling.preview.Preview
3232
import androidx.compose.ui.unit.dp
3333
import androidx.navigation.NavHostController
34-
import com.instructure.canvasapi2.models.journey.JourneyAssistChatMessage
3534
import com.instructure.canvasapi2.models.journey.JourneyAssistRole
3635
import com.instructure.canvasapi2.utils.ContextKeeper
3736
import com.instructure.horizon.features.aiassistant.common.composable.AiAssistMessage
3837
import com.instructure.horizon.features.aiassistant.common.composable.AiAssistScaffold
38+
import com.instructure.horizon.features.aiassistant.common.model.AiAssistMessage
3939
import com.instructure.horizon.features.aiassistant.navigation.AiAssistRoute
4040
import com.instructure.horizon.horizonui.foundation.HorizonColors
4141
import com.instructure.horizon.horizonui.molecules.Spinner
@@ -107,15 +107,11 @@ private fun AssistChatScreenPreview() {
107107
ContextKeeper.appContext = LocalContext.current
108108
val state = AiAssistChatUiState(
109109
messages = listOf(
110-
JourneyAssistChatMessage(
111-
id = "1",
112-
prompt = "Hello",
110+
AiAssistMessage(
113111
text = "Hello",
114112
role = JourneyAssistRole.User,
115113
),
116-
JourneyAssistChatMessage(
117-
id = "2",
118-
prompt = "Hi there! How can I assist you today?",
114+
AiAssistMessage(
119115
text = "Hi there! How can I assist you today?",
120116
role = JourneyAssistRole.Assistant
121117
)

libs/horizon/src/main/java/com/instructure/horizon/features/aiassistant/chat/AiAssistChatUiState.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package com.instructure.horizon.features.aiassistant.chat
22

33
import androidx.compose.ui.text.input.TextFieldValue
4-
import com.instructure.canvasapi2.models.journey.JourneyAssistChatMessage
4+
import com.instructure.horizon.features.aiassistant.common.model.AiAssistMessage
55

66
data class AiAssistChatUiState(
7-
val messages: List<JourneyAssistChatMessage> = emptyList(),
7+
val messages: List<AiAssistMessage> = emptyList(),
88
val isLoading: Boolean = false,
99
val error: String? = null,
1010
val isFeedbackEnabled: Boolean = false,

libs/horizon/src/main/java/com/instructure/horizon/features/aiassistant/chat/AiAssistChatViewModel.kt

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,18 @@ package com.instructure.horizon.features.aiassistant.chat
1919
import androidx.compose.ui.text.input.TextFieldValue
2020
import androidx.lifecycle.ViewModel
2121
import androidx.lifecycle.viewModelScope
22-
import com.instructure.canvasapi2.models.journey.JourneyAssistChatMessage
2322
import com.instructure.canvasapi2.models.journey.JourneyAssistRole
2423
import com.instructure.canvasapi2.utils.weave.catch
2524
import com.instructure.canvasapi2.utils.weave.tryLaunch
2625
import com.instructure.horizon.features.aiassistant.common.AiAssistContextProvider
2726
import com.instructure.horizon.features.aiassistant.common.AiAssistRepository
27+
import com.instructure.horizon.features.aiassistant.common.model.AiAssistMessage
2828
import com.instructure.horizon.features.aiassistant.common.model.toContextSourceList
29+
import com.instructure.horizon.features.aiassistant.common.model.toJourneyAssistChatMessages
2930
import dagger.hilt.android.lifecycle.HiltViewModel
3031
import kotlinx.coroutines.flow.MutableStateFlow
3132
import kotlinx.coroutines.flow.asStateFlow
3233
import kotlinx.coroutines.flow.update
33-
import java.util.UUID
3434
import javax.inject.Inject
3535

3636
@HiltViewModel
@@ -72,13 +72,13 @@ class AiAssistChatViewModel @Inject constructor(
7272
evaluatePrompt(message)
7373
}
7474

75-
private fun evaluatePrompt(message: JourneyAssistChatMessage) {
75+
private fun evaluatePrompt(message: AiAssistMessage) {
7676
viewModelScope.tryLaunch {
7777
_uiState.update {
7878
it.copy(isLoading = true)
7979
}
8080

81-
val response = answerPrompt(message.prompt)
81+
val response = answerPrompt(message.text)
8282
aiAssistMessages.add(response)
8383

8484
_uiState.update {
@@ -96,21 +96,19 @@ class AiAssistChatViewModel @Inject constructor(
9696
}
9797
}
9898

99-
private suspend fun answerPrompt(prompt: String): JourneyAssistChatMessage {
99+
private suspend fun answerPrompt(prompt: String): AiAssistMessage {
100100
val response = repository.answerPrompt(
101101
prompt,
102-
aiAssistMessages,
102+
aiAssistMessages.toJourneyAssistChatMessages(),
103103
aiAssistContextState
104104
)
105105
aiAssistContextState = response.state ?: aiAssistContextState
106106
return response.message
107107
}
108108

109-
private fun addMessage(prompt: String): JourneyAssistChatMessage {
110-
val message = JourneyAssistChatMessage(
111-
id = UUID.randomUUID().toString(),
109+
private fun addMessage(prompt: String): AiAssistMessage {
110+
val message = AiAssistMessage(
112111
text = prompt,
113-
prompt = prompt,
114112
role = JourneyAssistRole.User,
115113
)
116114
aiAssistMessages.add(message)

libs/horizon/src/main/java/com/instructure/horizon/features/aiassistant/common/AiAssistContextProvider.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,18 @@
1616
*/
1717
package com.instructure.horizon.features.aiassistant.common
1818

19-
import com.instructure.canvasapi2.models.journey.JourneyAssistChatMessage
2019
import com.instructure.canvasapi2.models.journey.JourneyAssistState
2120
import com.instructure.horizon.features.aiassistant.common.model.AiAssistContext
2221
import com.instructure.horizon.features.aiassistant.common.model.AiAssistContextSource
22+
import com.instructure.horizon.features.aiassistant.common.model.AiAssistMessage
2323
import javax.inject.Inject
2424
import javax.inject.Singleton
2525

2626
@Singleton
2727
class AiAssistContextProvider @Inject constructor() {
2828
var aiAssistContext = AiAssistContext()
2929

30-
fun addMessageToChatHistory(message: JourneyAssistChatMessage) {
30+
fun addMessageToChatHistory(message: AiAssistMessage) {
3131
aiAssistContext = aiAssistContext.copy(
3232
chatHistory = aiAssistContext.chatHistory + message
3333
)

libs/horizon/src/main/java/com/instructure/horizon/features/aiassistant/common/AiAssistRepository.kt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ import com.instructure.canvasapi2.models.journey.JourneyAssistChatMessage
55
import com.instructure.canvasapi2.models.journey.JourneyAssistRequestBody
66
import com.instructure.canvasapi2.models.journey.JourneyAssistRole
77
import com.instructure.canvasapi2.models.journey.JourneyAssistState
8-
import java.util.UUID
8+
import com.instructure.horizon.features.aiassistant.common.model.AiAssistMessage
99
import javax.inject.Inject
1010

1111
data class AiAssistResponse(
12-
val message: JourneyAssistChatMessage,
12+
val message: AiAssistMessage,
1313
val state: JourneyAssistState?
1414
)
1515

@@ -23,15 +23,14 @@ class AiAssistRepository @Inject constructor(
2323
): AiAssistResponse {
2424
val requestBody = JourneyAssistRequestBody(prompt, history, state)
2525
val response = journeyAssistAPI.answerPrompt(requestBody)
26-
val message = JourneyAssistChatMessage(
27-
id = UUID.randomUUID().toString(),
28-
prompt = response.response.orEmpty(),
26+
val message = AiAssistMessage(
2927
text = response.response.orEmpty(),
3028
role = JourneyAssistRole.Assistant,
3129
chipOptions = response.chips,
3230
flashCards = response.flashCards,
3331
quizItems = response.quizItems,
34-
citations = response.citations
32+
citations = response.citations,
33+
errorMessage = response.error,
3534
)
3635
return AiAssistResponse(message, response.state)
3736
}

libs/horizon/src/main/java/com/instructure/horizon/features/aiassistant/common/composable/AiAssistMessage.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,19 @@ import androidx.compose.foundation.layout.fillMaxWidth
2222
import androidx.compose.runtime.Composable
2323
import androidx.compose.ui.Alignment
2424
import androidx.compose.ui.Modifier
25-
import com.instructure.canvasapi2.models.journey.JourneyAssistChatMessage
2625
import com.instructure.canvasapi2.models.journey.JourneyAssistRole
26+
import com.instructure.horizon.features.aiassistant.common.model.AiAssistMessage
2727

2828
@Composable
2929
fun AiAssistMessage(
30-
message: JourneyAssistChatMessage,
30+
message: AiAssistMessage,
3131
onSendPrompt: (String) -> Unit
3232
) {
33-
if (message.role == JourneyAssistRole.Assistant) {
33+
if (!message.errorMessage.isNullOrBlank()) {
34+
AiAssistResponseTextBlock(
35+
text = message.errorMessage
36+
)
37+
} else if (message.role == JourneyAssistRole.Assistant) {
3438
AiAssistResponseTextBlock(
3539
text = message.text,
3640
footerState = AiAssistResponseTextBlockFooterState(

libs/horizon/src/main/java/com/instructure/horizon/features/aiassistant/common/model/AiAssistContext.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
package com.instructure.horizon.features.aiassistant.common.model
22

3-
import com.instructure.canvasapi2.models.journey.JourneyAssistChatMessage
43
import com.instructure.canvasapi2.models.journey.JourneyAssistState
54

65
data class AiAssistContext(
76
val contextString: String? = null,
87
val contextSources: List<AiAssistContextSource> = emptyList(),
9-
val chatHistory: List<JourneyAssistChatMessage> = emptyList(),
8+
val chatHistory: List<AiAssistMessage> = emptyList(),
109
) {
1110
val state: JourneyAssistState
1211
get() {
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright (C) 2026 - present Instructure, Inc.
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, version 3 of the License.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
*
13+
* You should have received a copy of the GNU General Public License
14+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
15+
*
16+
*/
17+
package com.instructure.horizon.features.aiassistant.common.model
18+
19+
import com.instructure.canvasapi2.models.journey.JourneyAssistChatMessage
20+
import com.instructure.canvasapi2.models.journey.JourneyAssistChipOption
21+
import com.instructure.canvasapi2.models.journey.JourneyAssistCitation
22+
import com.instructure.canvasapi2.models.journey.JourneyAssistFlashCard
23+
import com.instructure.canvasapi2.models.journey.JourneyAssistQuizItem
24+
import com.instructure.canvasapi2.models.journey.JourneyAssistRole
25+
26+
data class AiAssistMessage(
27+
val text: String = "",
28+
val role: JourneyAssistRole,
29+
val chipOptions: List<JourneyAssistChipOption> = emptyList(),
30+
val flashCards: List<JourneyAssistFlashCard> = emptyList(),
31+
val quizItems: List<JourneyAssistQuizItem> = emptyList(),
32+
val citations: List<JourneyAssistCitation> = emptyList(),
33+
val errorMessage: String? = null
34+
)
35+
36+
fun List<JourneyAssistChatMessage>.toAiAssistMessages(): List<AiAssistMessage> {
37+
return this.map {
38+
AiAssistMessage(
39+
text = it.text,
40+
role = it.role,
41+
)
42+
}
43+
}
44+
45+
fun List<AiAssistMessage>.toJourneyAssistChatMessages(): List<JourneyAssistChatMessage> {
46+
return this.map {
47+
JourneyAssistChatMessage(
48+
text = it.text,
49+
role = it.role,
50+
)
51+
}
52+
}

libs/horizon/src/main/java/com/instructure/horizon/features/aiassistant/flashcard/AiAssistFlashcardViewModel.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import com.instructure.canvasapi2.utils.weave.catch
2323
import com.instructure.canvasapi2.utils.weave.tryLaunch
2424
import com.instructure.horizon.features.aiassistant.common.AiAssistContextProvider
2525
import com.instructure.horizon.features.aiassistant.common.AiAssistRepository
26+
import com.instructure.horizon.features.aiassistant.common.model.toJourneyAssistChatMessages
2627
import dagger.hilt.android.lifecycle.HiltViewModel
2728
import kotlinx.coroutines.flow.MutableStateFlow
2829
import kotlinx.coroutines.flow.asStateFlow
@@ -73,8 +74,8 @@ class AiAssistFlashcardViewModel @Inject constructor(
7374

7475
val response = aiAssistRepository.answerPrompt(
7576
prompt = aiAssistContextProvider.aiAssistContext.chatHistory
76-
.lastOrNull { it.role == JourneyAssistRole.User }?.prompt.orEmpty(),
77-
history = aiAssistContextProvider.aiAssistContext.chatHistory,
77+
.lastOrNull { it.role == JourneyAssistRole.User }?.text.orEmpty(),
78+
history = aiAssistContextProvider.aiAssistContext.chatHistory.toJourneyAssistChatMessages(),
7879
state = aiAssistContextProvider.aiAssistContext.state
7980
)
8081

0 commit comments

Comments
 (0)