diff --git a/nanobot/channels/discord/tests/test_discord_channel.py b/nanobot/channels/discord/tests/test_discord_channel.py index a749363b0..af29ad0ae 100644 --- a/nanobot/channels/discord/tests/test_discord_channel.py +++ b/nanobot/channels/discord/tests/test_discord_channel.py @@ -145,14 +145,9 @@ class _FakeChannel: class _FakeInteractionResponse: def __init__(self) -> None: self.messages: list[dict] = [] - self._done = False async def send_message(self, content: str, *, ephemeral: bool = False) -> None: self.messages.append({"content": content, "ephemeral": ephemeral}) - self._done = True - - def is_done(self) -> bool: - return self._done def _make_interaction( diff --git a/nanobot/channels/mattermost/runtime.py b/nanobot/channels/mattermost/runtime.py index 048d67158..eb6b9e53f 100644 --- a/nanobot/channels/mattermost/runtime.py +++ b/nanobot/channels/mattermost/runtime.py @@ -53,7 +53,6 @@ class MattermostConfig(Base): include_thread_context: bool = True thread_context_limit: int = 20 streaming: bool = True - streaming_max_chars: int = 16000 react_emoji: str = "eyes" done_emoji: str = "white_check_mark" send_progress: bool = True @@ -106,7 +105,6 @@ class MattermostChannel(BaseChannel): self._ws_task: asyncio.Task[None] | None = None self._self_id: str | None = None self._self_username: str | None = None - self._self_email: str | None = None self._usernames: dict[str, str] = {} self._user_emails: dict[str, str] = {} self._channel_types: dict[str, str] = {} @@ -138,7 +136,6 @@ class MattermostChannel(BaseChannel): me = cast(dict[str, Any], resp.json()) self._self_id = me.get("id") self._self_username = me.get("username") - self._self_email = me.get("email", "") self.logger.info("bot @{} connected", self._self_username) except Exception as e: self.logger.error("Failed to identify bot user: {}", e) diff --git a/nanobot/channels/mattermost/tests/test_mattermost_channel.py b/nanobot/channels/mattermost/tests/test_mattermost_channel.py index 3ca99738d..b44d9c6ad 100644 --- a/nanobot/channels/mattermost/tests/test_mattermost_channel.py +++ b/nanobot/channels/mattermost/tests/test_mattermost_channel.py @@ -31,8 +31,6 @@ class _FakeHTTPClient: self.delete_calls: list[dict[str, Any]] = [] self._get_responses: dict[str, Any] = {} self._post_responses: dict[str, Any] = {} - self._put_responses: dict[str, Any] = {} - self._delete_status: int | None = None def _req(self, method: str, path: str) -> httpx.Request: return httpx.Request(method, f"https://chat.example.com{path}") @@ -46,12 +44,6 @@ class _FakeHTTPClient: def set_post_response(self, path: str, data: Any) -> None: self._post_responses[path] = data - def set_put_response(self, path: str, data: Any) -> None: - self._put_responses[path] = data - - def set_delete_status(self, status: int) -> None: - self._delete_status = status - async def get(self, path: str, **kwargs) -> httpx.Response: self.get_calls.append({"path": path, **kwargs}) data = self._get_responses.get(path, {"id": "resp_" + path.split("/")[-1]}) @@ -71,13 +63,11 @@ class _FakeHTTPClient: async def put(self, path: str, *, json: dict[str, Any] | None = None, **kwargs) -> httpx.Response: self.put_calls.append({"path": path, "json": json}) - data = self._put_responses.get(path, {"id": path.split("/")[-1]}) - return self._resp(200, data, "PUT", path) + return self._resp(200, {"id": path.split("/")[-1]}, "PUT", path) async def delete(self, path: str, **kwargs) -> httpx.Response: self.delete_calls.append({"path": path}) - status = self._delete_status if self._delete_status is not None else 200 - return self._resp(status, {}, "DELETE", path) + return self._resp(200, {}, "DELETE", path) async def aclose(self) -> None: pass @@ -119,7 +109,6 @@ def test_config_defaults(): assert config.server_url == "" assert config.token == "" assert config.streaming is True - assert config.streaming_max_chars == 16000 assert config.send_tool_hints is True assert config.dm.enabled is True assert config.dm.policy == "open" @@ -150,7 +139,6 @@ def test_config_camelcase_aliases(): "serverUrl": "https://mm.example.com", "token": "abc123", "allowFromMatchMode": "username", - "streamingMaxChars": 8000, "replyInThread": False, "sendToolHints": False, } @@ -158,7 +146,6 @@ def test_config_camelcase_aliases(): assert config.server_url == "https://mm.example.com" assert config.token == "abc123" assert config.allow_from_match_mode == "username" - assert config.streaming_max_chars == 8000 assert config.reply_in_thread is False assert config.send_tool_hints is False @@ -194,7 +181,6 @@ async def test_start_identifies_bot(): assert channel._self_id == "botuserid123" assert channel._self_username == "nanobot" - assert channel._self_email == "bot@example.com" assert not start_task.done() user_me_calls = [c for c in fake.get_calls[calls_before:] if "/api/v4/users/me" in c["path"]] assert len(user_me_calls) == 1 diff --git a/nanobot/channels/mochat/runtime.py b/nanobot/channels/mochat/runtime.py index e5e44e863..b91828000 100644 --- a/nanobot/channels/mochat/runtime.py +++ b/nanobot/channels/mochat/runtime.py @@ -277,7 +277,7 @@ class MochatChannel(BaseChannel): self.config: MochatConfig = config self._http: httpx.AsyncClient | None = None self._socket: Any = None - self._ws_connected = self._ws_ready = False + self._ws_ready = False self._state_dir = get_runtime_subdir("mochat") self._cursor_path = self._state_dir / "session_cursors.json" @@ -346,7 +346,7 @@ class MochatChannel(BaseChannel): if self._http: await self._http.aclose() self._http = None - self._ws_connected = self._ws_ready = False + self._ws_ready = False async def send(self, msg: OutboundMessage) -> None: """Send outbound message to session or panel.""" @@ -422,7 +422,7 @@ class MochatChannel(BaseChannel): ) async def connect() -> None: - self._ws_connected, self._ws_ready = True, False + self._ws_ready = False self.logger.info("websocket connected") subscribed = await self._subscribe_all() self._ws_ready = subscribed @@ -431,7 +431,7 @@ class MochatChannel(BaseChannel): async def disconnect() -> None: if not self._running: return - self._ws_connected = self._ws_ready = False + self._ws_ready = False self.logger.warning("websocket disconnected") await self._ensure_fallback_workers() diff --git a/nanobot/channels/signal/tests/test_signal_markdown.py b/nanobot/channels/signal/tests/test_signal_markdown.py index 7cb62a282..2ab8d4cce 100644 --- a/nanobot/channels/signal/tests/test_signal_markdown.py +++ b/nanobot/channels/signal/tests/test_signal_markdown.py @@ -363,13 +363,6 @@ def test_reported_daily_brief_pattern(): # --------------------------------------------------------------------------- -def _resolve_chunk_styles(text: str, max_len: int) -> tuple[list[str], list[list[str]]]: - """Helper: full markdown → signal pipeline, including chunking.""" - plain, styles = _markdown_to_signal(text) - chunks = split_message(plain, max_len) if plain else [""] - return chunks, _partition_styles(plain, chunks, styles) - - def test_partition_styles_single_chunk_passthrough(): plain, styles = _markdown_to_signal("**bold** plain *it*") parts = _partition_styles(plain, [plain], styles) diff --git a/nanobot/channels/slack/runtime.py b/nanobot/channels/slack/runtime.py index ff000c25f..eb81a9d6b 100644 --- a/nanobot/channels/slack/runtime.py +++ b/nanobot/channels/slack/runtime.py @@ -69,7 +69,6 @@ class SlackConfig(Base): webhook_path: str = "/slack/events" bot_token: str = "" app_token: str = "" - user_token_read_only: bool = True reply_in_thread: bool = True react_emoji: str = "eyes" done_emoji: str = "white_check_mark" diff --git a/nanobot/channels/websocket/tests/test_websocket_http_routes.py b/nanobot/channels/websocket/tests/test_websocket_http_routes.py index aba12221b..5e1566cc2 100644 --- a/nanobot/channels/websocket/tests/test_websocket_http_routes.py +++ b/nanobot/channels/websocket/tests/test_websocket_http_routes.py @@ -1244,39 +1244,6 @@ async def test_pairing_routes_require_token_and_approve_or_deny( assert "Missing pairing code" in missing_code.text -def test_api_service_settings_read_api_key_from_webui_payload(bus: MagicMock) -> None: - channel = _ch(bus) - request = _FakeReq(path="/api/settings/api-service/start") - setattr( - request, - "_nanobot_webui_mutation_payload", - {"host": "0.0.0.0", "port": 8900, "timeout": 120, "api_key": "secret-token"}, - ) - - query = channel.gateway.http.settings_routes._parse_api_service_settings_query(request) - - assert query == { - "host": ["0.0.0.0"], - "port": ["8900"], - "timeout": ["120"], - "api_key": ["secret-token"], - } - - -def test_api_service_settings_reject_non_string_api_key(bus: MagicMock) -> None: - from nanobot.webui.settings_api import WebUISettingsError - - channel = _ch(bus) - request = _FakeReq(path="/api/settings/api-service/start") - setattr( - request, - "_nanobot_webui_mutation_payload", - {"host": "127.0.0.1", "api_key": 123}, - ) - - with pytest.raises(WebUISettingsError, match="API key must be a string"): - channel.gateway.http.settings_routes._parse_api_service_settings_query(request) - @pytest.mark.asyncio async def test_nanobot_feature_remote_install_requires_opt_in( bus: MagicMock, diff --git a/nanobot/channels/websocket/tests/ws_test_client.py b/nanobot/channels/websocket/tests/ws_test_client.py index ae3fbc490..d5e183e37 100644 --- a/nanobot/channels/websocket/tests/ws_test_client.py +++ b/nanobot/channels/websocket/tests/ws_test_client.py @@ -202,12 +202,6 @@ class WsTestClient: assert msg.event == "delta", f"Expected 'delta' event, got '{msg.event}'" return msg - async def recv_stream_end(self, timeout: float = 10.0) -> WsMessage: - """Receive and validate a 'stream_end' event.""" - msg = await self.recv(timeout) - assert msg.event == "stream_end", f"Expected 'stream_end' event, got '{msg.event}'" - return msg - async def collect_stream(self, timeout: float = 10.0) -> list[WsMessage]: """Collect all deltas and the final stream_end into a list.""" messages: list[WsMessage] = [] @@ -232,10 +226,6 @@ class WsTestClient: """Send a JSON frame.""" await self.ws.send(json.dumps(data, ensure_ascii=False)) - async def send_content(self, content: str) -> None: - """Send content in the preferred JSON format ``{"content": ...}``.""" - await self.send_json({"content": content}) - # -- Connection introspection ----------------------------------------- @property diff --git a/nanobot/process_runtime.py b/nanobot/process_runtime.py index 359fed8a6..c5e425511 100644 --- a/nanobot/process_runtime.py +++ b/nanobot/process_runtime.py @@ -96,22 +96,6 @@ class ManagedProcessRuntime(Generic[_StartOptionsT]): # it; poll() both reaps it and reports the real lifecycle state. self._owned_process: Any | None = None - @classmethod - def refresh_state_pid(cls, *, paths: ProcessRuntimePaths) -> None: - """Update a managed state file after the recorded process restarts.""" - if not paths.state_path.exists(): - return - try: - state = json.loads(paths.state_path.read_text(encoding="utf-8")) - except (json.JSONDecodeError, OSError): - return - state["pid"] = os.getpid() - runtime = cls(paths=paths) - state.pop("stable_identity", None) - state.update(runtime.process_identity_record(os.getpid())) - state["started_at"] = _utc_now() - runtime._write_state(state) - def start_background(self, options: _StartOptionsT) -> ProcessResult: """Start the configured command as a detached process.""" with self._lifecycle_lock(): diff --git a/nanobot/session/webui_turns.py b/nanobot/session/webui_turns.py index 6bb719096..8085f78ce 100644 --- a/nanobot/session/webui_turns.py +++ b/nanobot/session/webui_turns.py @@ -685,15 +685,6 @@ class WebuiTurnCoordinator: ) ) - async def publish_run_status( - self, - msg: InboundMessage, - status: str, - *, - started_at: float | None = None, - ) -> None: - await publish_turn_run_status(self.bus, msg, status, started_at=started_at) - async def handle_turn_end( self, msg: InboundMessage, diff --git a/nanobot/webui/gateway_tokens.py b/nanobot/webui/gateway_tokens.py index 0b3d9d3d7..22fe46cc7 100644 --- a/nanobot/webui/gateway_tokens.py +++ b/nanobot/webui/gateway_tokens.py @@ -63,9 +63,6 @@ class GatewayTokenStore: self.api_tokens[token_value] = expiry return token_value - def take_issued_token_if_valid(self, token_value: str | None) -> bool: - return self.take_issued_token_audience(token_value) is not None - def take_issued_token_audience( self, token_value: str | None, diff --git a/nanobot/webui/settings_routes.py b/nanobot/webui/settings_routes.py index c938ae106..25f79ccdf 100644 --- a/nanobot/webui/settings_routes.py +++ b/nanobot/webui/settings_routes.py @@ -36,7 +36,6 @@ from nanobot.webui.nanobot_features_api import ( nanobot_features_payload, ) from nanobot.webui.settings_api import ( - WebUISettingsError, complete_oauth_provider, create_model_configuration, create_provider_settings, @@ -490,17 +489,6 @@ class WebUISettingsRouter: lambda: request_image_generation_reload(self.bus), ) - async def _apply_image_generation_runtime_change( - self, - payload: dict[str, Any], - ) -> dict[str, Any]: - updated, restart_cleared = ( - await self._apply_image_generation_runtime_change_result(payload) - ) - if restart_cleared: - self._restart_sections.discard("image") - return updated - async def _reload_mcp_runtime(self) -> dict[str, Any]: if self._mcp_reload is None: return { @@ -531,47 +519,9 @@ class WebUISettingsRouter: def _parse_mcp_settings_query(self, request: WsRequest) -> QueryParams: return self._query(request) - def _parse_provider_settings_query(self, request: WsRequest) -> QueryParams: - return self._query(request) - - def _parse_api_service_settings_query(self, request: WsRequest) -> QueryParams: - payload = _mutation_payload(request) - if payload is not None: - api_key = payload.get("api_key") - if api_key is not None and not isinstance(api_key, str): - raise WebUISettingsError("API service API key must be a string") - return self._query(request) - def _api_runtime(self) -> ApiRuntime: return ApiRuntime(paths=api_runtime_paths(self.settings.config.path)) - def _api_service_payload( - self, - *, - last_action: str | None = None, - ) -> dict[str, Any]: - return capability_domain.api_service_payload( - self.settings, - self._api_runtime(), - last_action=last_action, - ) - - @staticmethod - def _masked_secret(value: str) -> str | None: - return capability_domain.masked_api_secret(value) - - @staticmethod - def _api_runtime_message(message: str) -> str: - return capability_domain.api_runtime_message(message) - - def _parse_channel_values(self, request: WsRequest) -> dict[str, Any]: - return self._system.parse_channel_values( - SettingsRequest( - query=self._query(request), - payload=_mutation_payload(request), - ) - ) - def _save_channel_config_values( self, name: str, @@ -610,17 +560,6 @@ class WebUISettingsRouter: allow_install=allow_install, ) - @staticmethod - def _feature_runtime_fallback( - payload: dict[str, Any], - *, - message: str, - ) -> dict[str, Any]: - return system_domain.SystemSettingsHandler.feature_runtime_fallback( - payload, - message=message, - ) - def _allow_feature_package_install( self, connection: Any, diff --git a/pyproject.toml b/pyproject.toml index f0bf5fa46..c7f75d1f8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,6 @@ dependencies = [ "pydantic-settings>=2.12.0,<3.0.0", # Feishu's lark-oapi currently requires websockets<16; core supports 15 and 16. "websockets>=15.0,<17.0", - "websocket-client>=1.9.0,<2.0.0", "httpx[socks]>=0.28.0,<1.0.0", "ddgs>=9.5.5,<10.0.0", "oauth-cli-kit>=0.1.6,<1.0.0", diff --git a/tui/src/command-menu.ts b/tui/src/command-menu.ts index 2b13c94ef..31e403318 100644 --- a/tui/src/command-menu.ts +++ b/tui/src/command-menu.ts @@ -5,7 +5,7 @@ import { PickerMenu, type PickerMenuTheme } from "./picker-menu" export type CommandMenuTheme = PickerMenuTheme -export type TuiCommandAction = +type TuiCommandAction = | "sessions" | "new-chat" | "context" diff --git a/tui/src/protocol.ts b/tui/src/protocol.ts index 0f190a040..abd4cb2f6 100644 --- a/tui/src/protocol.ts +++ b/tui/src/protocol.ts @@ -29,14 +29,14 @@ export interface FileEditEvent { diff?: FileDiff } -export interface FileDiff { +interface FileDiff { format: "unified" | string context?: number truncated?: boolean text?: string } -export interface MediaAttachment { +interface MediaAttachment { kind: "image" | "video" | "file" url: string name?: string @@ -225,7 +225,7 @@ export interface SessionContextSnapshot { lastUsage: TokenUsage | null } -export interface SessionMention { +interface SessionMention { name: string session_key: string title?: string diff --git a/webui/src/channel-plugins/i18n.ts b/webui/src/channel-plugins/i18n.ts index 95b8a2b51..10984e1da 100644 --- a/webui/src/channel-plugins/i18n.ts +++ b/webui/src/channel-plugins/i18n.ts @@ -1,6 +1,6 @@ import type { TFunction } from "i18next"; -export type ChannelFieldMessages = { +type ChannelFieldMessages = { label: string; placeholder?: string; help?: string; diff --git a/webui/src/components/CliAppMentionText.tsx b/webui/src/components/CliAppMentionText.tsx index 1abfb89b3..57e1e7acc 100644 --- a/webui/src/components/CliAppMentionText.tsx +++ b/webui/src/components/CliAppMentionText.tsx @@ -137,7 +137,7 @@ export function CapabilityMentionToken({ return ; } -export function SessionMentionToken({ +function SessionMentionToken({ mention, label, variant, @@ -172,7 +172,7 @@ export function SessionMentionToken({ ); } -export function CliAppMentionToken({ +function CliAppMentionToken({ app, label, variant, @@ -229,7 +229,7 @@ export function CliAppMentionToken({ ); } -export function McpPresetMentionToken({ +function McpPresetMentionToken({ preset, label, variant, diff --git a/webui/src/components/FileReferenceChip.tsx b/webui/src/components/FileReferenceChip.tsx index 80a63d592..9ce0e040a 100644 --- a/webui/src/components/FileReferenceChip.tsx +++ b/webui/src/components/FileReferenceChip.tsx @@ -151,7 +151,7 @@ export function splitFilePath(path: string): { directory: string; name: string } }; } -export function fileKindForPath(path: string): FileReferenceKind { +function fileKindForPath(path: string): FileReferenceKind { const normalized = path.toLowerCase(); const name = normalized.split(/[\\/]/).pop() ?? normalized; const ext = name.includes(".") ? name.split(".").pop() ?? "" : ""; @@ -193,7 +193,7 @@ export function fileKindForPath(path: string): FileReferenceKind { } } -export function FileReferenceIcon({ kind }: { kind: FileReferenceKind }) { +function FileReferenceIcon({ kind }: { kind: FileReferenceKind }) { if (kind === "python") { return ( ): string { +function channelFieldValue(field: ChannelConfigField, values: Record): string { return values[field.key] ?? field.defaultValue ?? field.options?.[0]?.value ?? ""; } diff --git a/webui/src/components/settings/channels/catalog.ts b/webui/src/components/settings/channels/catalog.ts index 883111626..e1f63ebcf 100644 --- a/webui/src/components/settings/channels/catalog.ts +++ b/webui/src/components/settings/channels/catalog.ts @@ -27,7 +27,7 @@ export type ChannelSetupPresentation = { presets?: ChannelProviderPreset[]; }; -export type ChannelCatalogSetupPresentation = { +type ChannelCatalogSetupPresentation = { mode?: "webui" | "credentials" | "connect"; command?: string; docsUrl?: string; @@ -38,15 +38,15 @@ export type ChannelCatalogSetupPresentation = { presets?: ChannelProviderPresetDefinition[]; }; -export type ChannelFieldPresentation = { +type ChannelFieldPresentation = { key: string; }; -export type ChannelSetupActionDefinition = Omit; +type ChannelSetupActionDefinition = Omit; export type ChannelProviderPresetDefinition = Omit; -export type ChannelSetupAction = { +type ChannelSetupAction = { id: string; label: string; url?: string; @@ -72,7 +72,7 @@ export type ChannelConfigField = { options?: ChannelConfigOption[]; }; -export type ChannelConfigOption = { +type ChannelConfigOption = { value: string; label: string; }; diff --git a/webui/src/components/settings/contracts.ts b/webui/src/components/settings/contracts.ts index b5380545b..f24cc7972 100644 --- a/webui/src/components/settings/contracts.ts +++ b/webui/src/components/settings/contracts.ts @@ -14,7 +14,7 @@ export type SettingsSectionKey = | "runtime" | "advanced"; -export type PendingRestartSection = "runtime" | "browser" | "image"; +type PendingRestartSection = "runtime" | "browser" | "image"; export type PendingRestartSections = Record; export type RestartAwarePayload = { diff --git a/webui/src/components/thread/AgentActivityCluster.tsx b/webui/src/components/thread/AgentActivityCluster.tsx index be35dcd1f..2e0cc4fb2 100644 --- a/webui/src/components/thread/AgentActivityCluster.tsx +++ b/webui/src/components/thread/AgentActivityCluster.tsx @@ -51,7 +51,7 @@ import type { CliAppInfo, McpPresetInfo, ToolProgressEvent, UIFileEdit, UIMessag const ACTIVITY_SCROLL_NEAR_BOTTOM_PX = 24; -export { isAgentActivityMember, isReasoningOnlyAssistant }; +export { isAgentActivityMember }; interface ActivityCounts { reasoningSteps: number; diff --git a/webui/src/components/thread/activity/FileEditRow.tsx b/webui/src/components/thread/activity/FileEditRow.tsx index f87e36b12..0579c7b4f 100644 --- a/webui/src/components/thread/activity/FileEditRow.tsx +++ b/webui/src/components/thread/activity/FileEditRow.tsx @@ -155,7 +155,7 @@ function FileEditRow({ ); } -export function hasVisibleDiffStats(edit: Pick): boolean { +function hasVisibleDiffStats(edit: Pick): boolean { return edit.added > 0 || edit.deleted > 0; } diff --git a/webui/src/components/thread/activity/generic-tool-model.ts b/webui/src/components/thread/activity/generic-tool-model.ts index 8d1cbd912..35befc2ef 100644 --- a/webui/src/components/thread/activity/generic-tool-model.ts +++ b/webui/src/components/thread/activity/generic-tool-model.ts @@ -3,7 +3,7 @@ import { compactActivityPath, redactActivityText } from "./activity-text"; export type GenericToolStatus = "running" | "done" | "error"; export type ToolFamily = "content-search" | "file-search" | "list" | "read" | "memory" | "generic"; -export interface ToolField { +interface ToolField { key: | "query" | "pattern" diff --git a/webui/src/components/thread/activity/web-search-model.ts b/webui/src/components/thread/activity/web-search-model.ts index e5c030d72..8236c96e9 100644 --- a/webui/src/components/thread/activity/web-search-model.ts +++ b/webui/src/components/thread/activity/web-search-model.ts @@ -7,7 +7,7 @@ import { displayWebHost, formatCompactWebUrl, parseSafeActivityHttpUrl } from ". export type WebSearchStatus = "running" | "done" | "error"; export type WebSearchTarget = "web" | "x"; -export interface WebSearchSource { +interface WebSearchSource { title: string; href: string; host: string; diff --git a/webui/src/components/thread/promptNavigation.ts b/webui/src/components/thread/promptNavigation.ts index 3cc08fdc1..967576ee7 100644 --- a/webui/src/components/thread/promptNavigation.ts +++ b/webui/src/components/thread/promptNavigation.ts @@ -26,13 +26,13 @@ export function userPromptAnchors(messages: UIMessage[]): PromptAnchor[] { }); } -export function promptLabel(content: string, index: number): string { +function promptLabel(content: string, index: number): string { const text = content.replace(/\s+/g, " ").trim(); if (!text) return `Prompt ${index + 1}`; return truncatePreview(text, 80); } -export function promptPreview(content: string, index: number): string { +function promptPreview(content: string, index: number): string { const text = compactPreview(content); if (!text) return `Prompt ${index + 1}`; return truncatePreview(text, 320); diff --git a/webui/src/components/ui/button.tsx b/webui/src/components/ui/button.tsx index b03d56e7a..b96a0db4d 100644 --- a/webui/src/components/ui/button.tsx +++ b/webui/src/components/ui/button.tsx @@ -33,7 +33,7 @@ const buttonVariants = cva( }, ); -export interface ButtonProps +interface ButtonProps extends React.ButtonHTMLAttributes, VariantProps { asChild?: boolean; diff --git a/webui/src/components/ui/input.tsx b/webui/src/components/ui/input.tsx index 593ec1ba4..9cba282f2 100644 --- a/webui/src/components/ui/input.tsx +++ b/webui/src/components/ui/input.tsx @@ -3,7 +3,7 @@ import * as React from "react"; import { formControlFocusClassName } from "@/components/ui/form-control"; import { cn } from "@/lib/utils"; -export type InputProps = React.InputHTMLAttributes; +type InputProps = React.InputHTMLAttributes; const Input = React.forwardRef( ({ className, type, ...props }, ref) => { diff --git a/webui/src/components/ui/textarea.tsx b/webui/src/components/ui/textarea.tsx index 60c42d5fa..74cddc263 100644 --- a/webui/src/components/ui/textarea.tsx +++ b/webui/src/components/ui/textarea.tsx @@ -3,7 +3,7 @@ import * as React from "react"; import { formControlFocusClassName } from "@/components/ui/form-control"; import { cn } from "@/lib/utils"; -export type TextareaProps = React.TextareaHTMLAttributes; +type TextareaProps = React.TextareaHTMLAttributes; const Textarea = React.forwardRef( ({ className, ...props }, ref) => { diff --git a/webui/src/components/workbench/workbench-model.ts b/webui/src/components/workbench/workbench-model.ts index 6b8db2266..03a0d721d 100644 --- a/webui/src/components/workbench/workbench-model.ts +++ b/webui/src/components/workbench/workbench-model.ts @@ -12,7 +12,7 @@ export type { export const MAX_WORKBENCH_PANES = 4; -export const WORKBENCH_LAYOUTS = [ +const WORKBENCH_LAYOUTS = [ "columns", "rows", "grid", diff --git a/webui/src/hooks/useAttachedImages.ts b/webui/src/hooks/useAttachedImages.ts index a76b9a09c..f75cb7427 100644 --- a/webui/src/hooks/useAttachedImages.ts +++ b/webui/src/hooks/useAttachedImages.ts @@ -9,10 +9,10 @@ import type { WebUIIngressLimits } from "@/lib/types"; * - ``ready`` — ``dataUrl`` available; safe to submit * - ``error`` — validation / decode failure; chip shows inline error */ -export type AttachmentStatus = "encoding" | "ready" | "error"; +type AttachmentStatus = "encoding" | "ready" | "error"; export type AttachmentKind = "image" | "file"; -export interface AttachedAttachment { +interface AttachedAttachment { id: string; kind: AttachmentKind; file: File; @@ -32,7 +32,7 @@ export interface AttachedAttachment { export type AttachedImage = AttachedAttachment; -export interface RestoredReadyAttachment { +interface RestoredReadyAttachment { dataUrl: string; name?: string; kind?: AttachmentKind; @@ -55,8 +55,8 @@ export type AttachmentError = | "io"; // file read failed at the browser layer export const MAX_ATTACHMENTS_PER_MESSAGE = 4; -export const MAX_ATTACHMENT_BYTES = 6 * 1024 * 1024; -export const MAX_TOTAL_ATTACHMENT_BYTES = 24 * 1024 * 1024; +const MAX_ATTACHMENT_BYTES = 6 * 1024 * 1024; +const MAX_TOTAL_ATTACHMENT_BYTES = 24 * 1024 * 1024; /** MIME whitelist — mirrors the server's and the ``