Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 25 additions & 15 deletions desktop-shared/src/main/kotlin/io/askimo/ui/chat/ChatInputField.kt
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ import io.askimo.core.chat.domain.ChatDirective
import io.askimo.core.chat.domain.DirectiveScope
import io.askimo.core.chat.dto.ChatMessageDTO
import io.askimo.core.chat.dto.FileAttachmentDTO
import io.askimo.core.chat.service.DirectiveImportResult
import io.askimo.core.chat.service.ChatDirectiveService
import io.askimo.core.chat.util.FileContentExtractor
import io.askimo.core.config.AppConfig
import io.askimo.core.context.AppContext
Expand Down Expand Up @@ -185,15 +185,8 @@ fun chatInputField(
placeholder: String = stringResource("chat.input.placeholder"),
onEnabledServerIdsChange: ((Set<String>) -> Unit)? = null,
onNavigateToMcpSettings: (() -> Unit)? = null,
// Directives chip
availableDirectives: List<ChatDirective> = emptyList(),
selectedDirective: String? = null,
onToggleDirective: (String?) -> Unit = {},
onDirectiveCreated: ((name: String, content: String, applyToCurrent: Boolean) -> Unit)? = null,
onDirectiveUpdated: ((id: String, newName: String, newContent: String) -> Unit)? = null,
onDirectiveDeleted: ((id: String) -> Unit)? = null,
onDirectiveExported: (() -> String)? = null,
onDirectiveImported: ((json: String) -> DirectiveImportResult)? = null,
modifier: Modifier = Modifier,
) {
val inputFocusRequester = remember { FocusRequester() }
Expand Down Expand Up @@ -328,6 +321,14 @@ fun chatInputField(
var showNewDirectiveDialog by remember { mutableStateOf(false) }
var showManageDirectivesDialog by remember { mutableStateOf(false) }

val directiveService = remember {
KoinJavaComponent.get<ChatDirectiveService>(ChatDirectiveService::class.java)
}
var availableDirectives by remember { mutableStateOf<List<ChatDirective>>(emptyList()) }
LaunchedEffect(Unit) {
availableDirectives = directiveService.listAllDirectives()
}

// State for resizable text field.
val fontScale = LocalFontScale.current
val inlineControlsBottomPadding = 44.dp
Expand Down Expand Up @@ -980,28 +981,37 @@ fun chatInputField(
newDirectiveDialog(
onDismiss = { showNewDirectiveDialog = false },
onConfirm = { name, content, applyToCurrent ->
onDirectiveCreated?.invoke(name, content, applyToCurrent)
val newDirective = directiveService.createDirective(name, content)
availableDirectives = directiveService.listAllDirectives()
if (applyToCurrent) onToggleDirective(newDirective.id)
showNewDirectiveDialog = false
},
)
}

if (showManageDirectivesDialog && onDirectiveUpdated != null) {
if (showManageDirectivesDialog) {
manageDirectivesDialog(
directives = availableDirectives,
onDismiss = { showManageDirectivesDialog = false },
onAdd = { name, content, applyToCurrent ->
onDirectiveCreated?.invoke(name, content, applyToCurrent)
val newDirective = directiveService.createDirective(name, content)
availableDirectives = directiveService.listAllDirectives()
if (applyToCurrent) onToggleDirective(newDirective.id)
},
onUpdate = { id, newName, newContent ->
onDirectiveUpdated.invoke(id, newName, newContent)
directiveService.updateDirective(id, newName, newContent)
availableDirectives = directiveService.listAllDirectives()
},
onDelete = { id ->
onDirectiveDeleted?.invoke(id)
directiveService.deleteDirective(id)
if (selectedDirective == id) onToggleDirective(null)
availableDirectives = directiveService.listAllDirectives()
},
onExport = { onDirectiveExported?.invoke() ?: "" },
onExport = { directiveService.exportToJson() },
onImport = { json ->
onDirectiveImported?.invoke(json) ?: DirectiveImportResult(0, 0, 0)
val result = directiveService.importFromJson(json)
availableDirectives = directiveService.listAllDirectives()
result
},
)
}
Expand Down
36 changes: 1 addition & 35 deletions desktop-shared/src/main/kotlin/io/askimo/ui/chat/ChatView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,9 @@ import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import io.askimo.core.chat.domain.ChatDirective
import io.askimo.core.chat.domain.Project
import io.askimo.core.chat.dto.ChatMessageDTO
import io.askimo.core.chat.dto.FileAttachmentDTO
import io.askimo.core.chat.service.ChatDirectiveService
import io.askimo.core.config.AppConfig
import io.askimo.core.db.DatabaseManager
import io.askimo.core.event.EventBus
Expand Down Expand Up @@ -276,13 +274,6 @@ fun chatView(
onStateChange(inputText, attachments, editingMessage)
}

val directiveService = remember {
GlobalContext.get().get<ChatDirectiveService>()
}

// Load all directives
var availableDirectives by remember { mutableStateOf<List<ChatDirective>>(emptyList()) }

// Session memory dialog state
var showSessionMemoryDialog by remember { mutableStateOf(false) }
var sessionMemorySessionId by remember { mutableStateOf<String?>(null) }
Expand Down Expand Up @@ -389,10 +380,6 @@ fun chatView(
}
}

LaunchedEffect(Unit) {
availableDirectives = directiveService.listAllDirectives()
}

// Focus requester for search field
val searchFocusRequester = remember { FocusRequester() }

Expand Down Expand Up @@ -1197,30 +1184,9 @@ fun chatView(
sessionId = sessionId,
onEnabledServerIdsChange = { currentEnabledServerIds = it },
onNavigateToMcpSettings = onNavigateToMcpSettings,
// Directives chip
availableDirectives = availableDirectives,
// Directives chip — selection controlled here; CRUD managed inside chatInputField
selectedDirective = selectedDirective,
onToggleDirective = { id -> actions.setDirective(id) },
onDirectiveCreated = { name, content, applyToCurrent ->
val newDirective = directiveService.createDirective(name, content)
availableDirectives = directiveService.listAllDirectives()
if (applyToCurrent) actions.setDirective(newDirective.id)
},
onDirectiveUpdated = { id, newName, newContent ->
directiveService.updateDirective(id, newName, newContent)
availableDirectives = directiveService.listAllDirectives()
},
onDirectiveDeleted = { id ->
directiveService.deleteDirective(id)
if (selectedDirective == id) actions.setDirective(null)
availableDirectives = directiveService.listAllDirectives()
},
onDirectiveExported = { directiveService.exportToJson() },
onDirectiveImported = { json ->
val result = directiveService.importFromJson(json)
availableDirectives = directiveService.listAllDirectives()
result
},
modifier = Modifier
.widthIn(max = ThemePreferences.CONTENT_MAX_WIDTH)
.fillMaxWidth()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,7 @@ class SessionManager(
message: String,
attachments: List<FileAttachmentDTO> = emptyList(),
enabledServerIds: Set<String> = emptySet(),
directiveId: String? = null,
onComplete: () -> Unit,
) {
scope.launch {
Expand All @@ -540,7 +541,7 @@ class SessionManager(
ChatSession(
id = "",
title = message,
directiveId = null,
directiveId = directiveId,
projectId = projectId,
),
)
Expand All @@ -556,6 +557,7 @@ class SessionManager(

// Now send the message - ViewModel is ready
val viewModel = getOrCreateChatViewModel(newSession.id)
if (directiveId != null) viewModel.setDirective(directiveId)
viewModel.sendMessage(projectId, mode, message, attachments, enabledServerIds)
} catch (e: Exception) {
log.error("Failed to create project session and send message", e)
Expand Down
3 changes: 2 additions & 1 deletion desktop/src/main/kotlin/io/askimo/desktop/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2100,13 +2100,14 @@ fun mainContent(
projectView(
project = project,
onBack = onNavigateToProjects,
onStartChat = { projId, mode, message, attachments, enabledServerIds ->
onStartChat = { projId, mode, message, attachments, enabledServerIds, directiveId ->
sessionManager.createProjectSessionAndSendMessage(
projectId = projId,
mode = mode,
message = message,
attachments = attachments,
enabledServerIds = enabledServerIds,
directiveId = directiveId,
onComplete = { onNavigateToChat() },
)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ import kotlin.let
fun projectView(
project: Project,
onBack: () -> Unit,
onStartChat: (projectId: String, mode: CreationMode, message: String, attachments: List<FileAttachmentDTO>, enabledServerIds: Set<String>) -> Unit,
onStartChat: (projectId: String, mode: CreationMode, message: String, attachments: List<FileAttachmentDTO>, enabledServerIds: Set<String>, directiveId: String?) -> Unit,
onResumeSession: (String) -> Unit,
onDeleteSession: (sessionId: String, projectId: String) -> Unit,
onRenameSession: (String, String) -> Unit,
Expand All @@ -131,6 +131,7 @@ fun projectView(
var inputText by remember { mutableStateOf(TextFieldValue("")) }
var attachments by remember { mutableStateOf<List<FileAttachmentDTO>>(emptyList()) }
var currentEnabledServerIds by remember { mutableStateOf(emptySet<String>()) }
var selectedDirective by remember { mutableStateOf<String?>(null) }
var showProjectMenu by remember { mutableStateOf(false) }
var showDeleteDialog by remember { mutableStateOf(false) }
var showReIndexConfirmDialog by remember { mutableStateOf(false) }
Expand Down Expand Up @@ -377,13 +378,15 @@ fun projectView(
onAttachmentsChange = { attachments = it },
onSendMessage = { mode ->
if (inputText.text.isNotBlank()) {
onStartChat(currentProject.id, mode, inputText.text, attachments, currentEnabledServerIds)
onStartChat(currentProject.id, mode, inputText.text, attachments, currentEnabledServerIds, selectedDirective)
inputText = TextFieldValue("")
attachments = emptyList()
}
},
onEnabledServerIdsChange = { currentEnabledServerIds = it },
onNavigateToMcpSettings = onNavigateToMcpSettings,
selectedDirective = selectedDirective,
onToggleDirective = { selectedDirective = it },
sessionId = currentProject.id,
placeholder = stringResource("project.new.chat.placeholder", currentProject.name),
modifier = Modifier.padding(top = Spacing.large),
Expand Down