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
18 changes: 18 additions & 0 deletions jetwhale-host/app/src/main/composeResources/values-ja/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,22 @@
<string name="mcp_tools_no_match">一致するツールがありません</string>
<string name="mcp_tools_parameters">パラメータ</string>
<string name="mcp_tools_required">必須</string>
<string name="mcp_tools_tab_tools">ツール</string>
<string name="mcp_tools_tab_history">履歴</string>
<string name="mcp_history_empty">MCP tools の呼び出し履歴はありません</string>
<string name="mcp_history_succeeded">成功</string>
<string name="mcp_history_failed">失敗</string>
<string name="mcp_history_copy_tool_name">ツール名をコピー</string>
<string name="mcp_history_copy_arguments">引数をコピー</string>
<string name="mcp_history_copy_details">詳細をコピー</string>
<string name="mcp_history_copy_response">レスポンスをコピー</string>
<string name="mcp_history_no_arguments">引数なし</string>
<string name="mcp_history_response">レスポンス</string>
<string name="mcp_history_no_response">レスポンスなし</string>
<string name="mcp_tools_open_all">MCP tools を閲覧</string>
<string name="mcp_tools_filter_plugin">プラグイン</string>
<string name="mcp_tools_filter_session">セッション</string>
<string name="mcp_tools_filter_all">すべて</string>
<string name="mcp_tools_filter_add">フィルターを追加</string>
<string name="mcp_tools_filter_remove">フィルターを解除</string>
</resources>
18 changes: 18 additions & 0 deletions jetwhale-host/app/src/main/composeResources/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,22 @@
<string name="mcp_tools_no_match">No matching tools</string>
<string name="mcp_tools_parameters">Parameters</string>
<string name="mcp_tools_required">required</string>
<string name="mcp_tools_tab_tools">Tools</string>
<string name="mcp_tools_tab_history">History</string>
<string name="mcp_history_empty">No MCP tool calls yet</string>
<string name="mcp_history_succeeded">Succeeded</string>
<string name="mcp_history_failed">Failed</string>
<string name="mcp_history_copy_tool_name">Copy tool name</string>
<string name="mcp_history_copy_arguments">Copy arguments</string>
<string name="mcp_history_copy_details">Copy details</string>
<string name="mcp_history_copy_response">Copy response</string>
<string name="mcp_history_no_arguments">No arguments</string>
<string name="mcp_history_response">Response</string>
<string name="mcp_history_no_response">No response</string>
<string name="mcp_tools_open_all">Browse MCP tools</string>
<string name="mcp_tools_filter_plugin">Plugin</string>
<string name="mcp_tools_filter_session">Session</string>
<string name="mcp_tools_filter_all">All</string>
<string name="mcp_tools_filter_add">Add filter</string>
<string name="mcp_tools_filter_remove">Remove filter</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import com.kitakkun.jetwhale.host.navigation.addSingleTop
import com.kitakkun.jetwhale.host.navigation.bringPluginBackToMainWindow
import com.kitakkun.jetwhale.host.navigation.followPluginToSession
import com.kitakkun.jetwhale.host.navigation.isPluginPoppedOut
import com.kitakkun.jetwhale.host.navigation.openMcpTools
import com.kitakkun.jetwhale.host.settings.SettingsScreenSegmentedMenu
import com.kitakkun.jetwhale.host.ui.AppEnvironment
import com.kitakkun.jetwhale.host.ui.JetWhaleTheme
Expand Down Expand Up @@ -139,6 +140,9 @@ fun JetWhaleApp() {
onClickPlugin = { pluginId, sessionId ->
backStack.addSingleTop(PluginNavKey(pluginId, sessionId))
},
onOpenMcpTools = { pluginId, sessionId ->
backStack.openMcpTools(pluginId = pluginId, sessionId = sessionId)
},
onClickPopout = { pluginId, pluginName, sessionId ->
backStack.addSingleTop(
PluginPopoutNavKey(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ fun ToolingDrawer(
onClickPluginSettings: () -> Unit,
onClickInfo: () -> Unit,
onClickPlugin: (String) -> Unit,
onOpenMcpTools: (pluginId: String) -> Unit,
onOpenAllMcpTools: () -> Unit,
onSelectSession: (DebugSession) -> Unit,
onClickPopout: (DrawerPluginItemUiState) -> Unit,
isPoppedOut: (pluginId: String) -> Boolean,
Expand All @@ -45,6 +47,8 @@ fun ToolingDrawer(
onClickShrinkDrawer = { expandMenu = false },
onClickSettings = onClickSettings,
onClickPluginSettings = onClickPluginSettings,
onOpenMcpTools = onOpenMcpTools,
onOpenAllMcpTools = onOpenAllMcpTools,
onClickPlugin = { onClickPlugin(it.id) },
onSelectSession = onSelectSession,
onClickPopout = onClickPopout,
Expand All @@ -64,6 +68,7 @@ fun ToolingDrawer(
onClickExpandMenu = { expandMenu = true },
onClickSettings = onClickSettings,
onClickInfo = onClickInfo,
onOpenAllMcpTools = onOpenAllMcpTools,
onSelectSession = onSelectSession,
)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.kitakkun.jetwhale.host.di
import com.kitakkun.jetwhale.host.ApplicationLifecycleOwner
import com.kitakkun.jetwhale.host.BuildConfig
import com.kitakkun.jetwhale.host.architecture.ScreenContext
import com.kitakkun.jetwhale.host.drawer.McpToolsScreenContext
import com.kitakkun.jetwhale.host.drawer.ToolingScaffoldScreenContext
import com.kitakkun.jetwhale.host.mcp.McpServerService
import com.kitakkun.jetwhale.host.model.AppearanceSettingsSubscriptionKey
Expand Down Expand Up @@ -38,6 +39,7 @@ interface JetWhaleAppGraph : ScreenContext {
val swrClient: SwrClientPlus

val toolingScaffoldScreenContext: ToolingScaffoldScreenContext
val mcpToolsScreenContext: McpToolsScreenContext
val licensesScreenContext: LicensesScreenContext
val settingsScreenContext: SettingsScreenContext
val pluginScreenContextFactory: PluginScreenContext.Factory
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package com.kitakkun.jetwhale.host.drawer

import com.kitakkun.jetwhale.host.model.McpToolSummary
import com.kitakkun.jetwhale.host.model.PluginAvailability
import com.kitakkun.jetwhale.host.model.PluginIconResource
import kotlinx.collections.immutable.ImmutableList

data class DrawerPluginItemUiState(
val name: String,
Expand All @@ -13,8 +11,6 @@ data class DrawerPluginItemUiState(
val pluginAvailability: PluginAvailability,
/** True while an AI agent is driving this plugin's UI in the selected session. */
val underAiControl: Boolean,
/** The MCP tools this plugin exposes for the selected session; empty when it publishes none. */
val mcpTools: ImmutableList<McpToolSummary>,
) {
val exposesMcpTools: Boolean get() = mcpTools.isNotEmpty()
}
/** True when this plugin publishes MCP tools of its own for the selected session. */
val exposesMcpTools: Boolean,
)
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ fun ExpandedToolingDrawerView(
onClickShrinkDrawer: () -> Unit,
onClickSettings: () -> Unit,
onClickPluginSettings: () -> Unit,
onOpenMcpTools: (pluginId: String) -> Unit,
onOpenAllMcpTools: () -> Unit,
onClickPlugin: (DrawerPluginItemUiState) -> Unit,
onSelectSession: (DebugSession) -> Unit,
onClickPopout: (DrawerPluginItemUiState) -> Unit,
Expand All @@ -82,11 +84,16 @@ fun ExpandedToolingDrawerView(
contentDescription = null,
)
}
IconButton(onClick = onClickSettings) {
Icon(
imageVector = Icons.Default.Settings,
contentDescription = null,
)
Row {
// Opens the browser unscoped, so the tools an agent can reach are visible without
// first finding a plugin that happens to publish some.
McpToolsDrawerButton(onClick = onOpenAllMcpTools)
IconButton(onClick = onClickSettings) {
Icon(
imageVector = Icons.Default.Settings,
contentDescription = null,
)
}
}
}
Column(
Expand Down Expand Up @@ -169,7 +176,8 @@ fun ExpandedToolingDrawerView(
inactiveIconResource = it.inactiveIconResource,
selected = it.id == selectedPluginId,
underAiControl = it.underAiControl,
mcpTools = it.mcpTools,
exposesMcpTools = it.exposesMcpTools,
onClickMcpBadge = { onOpenMcpTools(it.id) },
onClick = { onClickPlugin(it) },
popupMenuContent = { dismiss ->
DropdownMenuItem(
Expand Down Expand Up @@ -241,7 +249,8 @@ fun ExpandedToolingDrawerView(
inactiveIconResource = it.inactiveIconResource,
selected = false,
underAiControl = it.underAiControl,
mcpTools = it.mcpTools,
exposesMcpTools = it.exposesMcpTools,
onClickMcpBadge = { onOpenMcpTools(it.id) },
onClick = {
// do nothing
},
Expand Down Expand Up @@ -287,7 +296,8 @@ fun ExpandedToolingDrawerView(
inactiveIconResource = it.inactiveIconResource,
selected = false,
underAiControl = it.underAiControl,
mcpTools = it.mcpTools,
exposesMcpTools = it.exposesMcpTools,
onClickMcpBadge = { onOpenMcpTools(it.id) },
onClick = {
// do nothing
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ fun ToolingScaffold(
onClickPluginSettings: () -> Unit,
onClickInfo: () -> Unit,
onClickPlugin: (String) -> Unit,
onOpenMcpTools: (pluginId: String) -> Unit,
onOpenAllMcpTools: () -> Unit,
onClickPopout: (DrawerPluginItemUiState) -> Unit,
isPoppedOut: (pluginId: String) -> Boolean,
onClickBringBack: (DrawerPluginItemUiState) -> Unit,
Expand All @@ -41,6 +43,8 @@ fun ToolingScaffold(
onClickPluginSettings = onClickPluginSettings,
onClickInfo = onClickInfo,
onClickPlugin = onClickPlugin,
onOpenMcpTools = onOpenMcpTools,
onOpenAllMcpTools = onOpenAllMcpTools,
onSelectSession = onSelectSession,
onClickPopout = onClickPopout,
isPoppedOut = isPoppedOut,
Expand Down Expand Up @@ -72,6 +76,8 @@ private fun ToolingScaffoldPreview() {
onClickPluginSettings = {},
onClickInfo = {},
onClickPlugin = {},
onOpenMcpTools = {},
onOpenAllMcpTools = {},
onSelectSession = {},
onClickPopout = {},
isPoppedOut = { false },
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.kitakkun.jetwhale.host.drawer

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Build
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.PlainTooltip
import androidx.compose.material3.Text
import androidx.compose.material3.TooltipAnchorPosition
import androidx.compose.material3.TooltipBox
import androidx.compose.material3.TooltipDefaults
import androidx.compose.material3.rememberTooltipState
import androidx.compose.runtime.Composable
import com.kitakkun.jetwhale.host.Res
import com.kitakkun.jetwhale.host.mcp_tools_open_all
import org.jetbrains.compose.resources.stringResource

/**
* Drawer entry point to the MCP tools browser that is not tied to a plugin, so the browser is
* reachable even when no plugin badge is on screen.
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun McpToolsDrawerButton(onClick: () -> Unit) {
val label = stringResource(Res.string.mcp_tools_open_all)
TooltipBox(
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
tooltip = { PlainTooltip { Text(label) } },
state = rememberTooltipState(),
) {
IconButton(onClick = onClick) {
Icon(
imageVector = Icons.Default.Build,
contentDescription = label,
)
}
}
}
Loading
Loading