From feb27a682f482fe5518f39c01f9edeec2ae51d40 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 7 Jul 2026 00:45:32 -0500 Subject: [PATCH 1/7] refac --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 48d2294..b1d43ee 100644 --- a/README.md +++ b/README.md @@ -214,4 +214,4 @@ This is safe when you are the only user and you control the network. It is not s ## License -Open Use License. Source available. All rights reserved. See [LICENSE](LICENSE). [Enterprise licenses available](mailto:sales@openwebui.com). +Open Use License. Source available. All rights reserved. See [LICENSE](LICENSE). [Commercial licenses](https://openwebui.com/computer/license) and [enterprise licenses](mailto:sales@openwebui.com) available. From 1b9a346991bc5f754e44789bf703302926367e2d Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 7 Jul 2026 00:59:19 -0500 Subject: [PATCH 2/7] refac --- cptr/frontend/src/lib/components/chat/ChatInput.svelte | 4 ++-- cptr/frontend/src/lib/components/chat/ChatPanel.svelte | 8 +------- cptr/utils/chat_task.py | 2 -- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/cptr/frontend/src/lib/components/chat/ChatInput.svelte b/cptr/frontend/src/lib/components/chat/ChatInput.svelte index bb3bc9f..9fa9f03 100644 --- a/cptr/frontend/src/lib/components/chat/ChatInput.svelte +++ b/cptr/frontend/src/lib/components/chat/ChatInput.svelte @@ -939,7 +939,7 @@ } }); - const slashCommandQuery = $derived(inputText.trim().toLowerCase()); + const slashCommandQuery = $derived(inputText.trimStart().toLowerCase()); const slashCommandIds = $derived.by(() => { if (!slashCommandQuery.startsWith('/')) return []; const ids: string[] = []; @@ -979,7 +979,7 @@ $effect(() => { const query = slashCommandQuery; const requestId = ++slashSkillsRequestId; - if (!query.startsWith('/') || !workspace) { + if (!query.startsWith('/') || /\s/.test(query.slice(1)) || !workspace) { slashSkillSuggestions = []; return; } diff --git a/cptr/frontend/src/lib/components/chat/ChatPanel.svelte b/cptr/frontend/src/lib/components/chat/ChatPanel.svelte index 68e4a10..1d1d4a0 100644 --- a/cptr/frontend/src/lib/components/chat/ChatPanel.svelte +++ b/cptr/frontend/src/lib/components/chat/ChatPanel.svelte @@ -299,9 +299,7 @@ const streaming = $derived(allMessages.some((m) => m.role === 'assistant' && !m.done)); const isLanding = $derived(allMessages.length === 0 && !chatId); const hasChatContent = $derived( - activePath.some( - ({ msg }) => msg.role === 'user' && msg.content.trim() && !msg.content.trim().startsWith('/') - ) + activePath.some(({ msg }) => msg.role === 'user' && msg.content.trim()) ); const workspaceDisplayName = $derived(getPathDisplayName(workspace, 'workspace')); const displayChatTitle = $derived(chatTitle || firstUserMessageTitle() || workspaceDisplayName); @@ -722,10 +720,6 @@ let text = inputText.trim(); if (!text || !selectedModel) return; if (sending) return; - if (!hasChatContent && text.startsWith('/') && text !== '/plan') { - toast.error('Only /plan is available before this chat has content'); - return; - } if (hasChatContent && text === '/compact') { await handleManualCompact(); return; diff --git a/cptr/utils/chat_task.py b/cptr/utils/chat_task.py index ad19611..9d596ce 100644 --- a/cptr/utils/chat_task.py +++ b/cptr/utils/chat_task.py @@ -172,8 +172,6 @@ def _build_skill_create_prompt(user_request: str) -> str: def _message_has_real_content(message: dict) -> bool: text = _plain_message_text(message.get("content")).strip() - if message.get("role") == "user" and text.startswith("/"): - return False return bool( text or message.get("tool_calls") or message.get("reasoning_items") or message.get("output") ) From c156aea2ae212bce85ad431caf0443d7a7aea4ab Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 7 Jul 2026 01:00:35 -0500 Subject: [PATCH 3/7] refac --- .../frontend/src/lib/components/chat/ChatInput.svelte | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/cptr/frontend/src/lib/components/chat/ChatInput.svelte b/cptr/frontend/src/lib/components/chat/ChatInput.svelte index 9fa9f03..d4e8d32 100644 --- a/cptr/frontend/src/lib/components/chat/ChatInput.svelte +++ b/cptr/frontend/src/lib/components/chat/ChatInput.svelte @@ -132,6 +132,13 @@ : $t('chat.voiceModeOn') ); + function isMobileInput(): boolean { + return ( + typeof window !== 'undefined' && + window.matchMedia('(hover: none) and (pointer: coarse)').matches + ); + } + // ── Lowlight setup ────────────────────────────── const lowlight = createLowlight(all); const _origHighlight = lowlight.highlight.bind(lowlight); @@ -313,6 +320,7 @@ return true; } if (event.key === 'Enter') { + if (isMobileInput()) return false; const item = currentItems[selectedIndex]; if (item && command) command(item); return true; @@ -477,6 +485,7 @@ return true; } if (event.key === 'Enter') { + if (isMobileInput()) return false; const item = currentItems[selectedIndex]; if (item && command) command(item); return true; @@ -554,6 +563,8 @@ spellcheck: 'true' }, handleKeyDown: (view, event) => { + if (event.key === 'Enter' && isMobileInput()) return false; + if (showSlashCommands) { if (event.key === 'ArrowDown') { event.preventDefault(); From b3f2aad51a6065f20d2be7ca890c9d5c30a22389 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 7 Jul 2026 01:06:29 -0500 Subject: [PATCH 4/7] refac --- cptr/env.py | 3 +++ cptr/utils/agents/claude_code.py | 2 ++ 2 files changed, 5 insertions(+) diff --git a/cptr/env.py b/cptr/env.py index b71f82b..aaa9d50 100644 --- a/cptr/env.py +++ b/cptr/env.py @@ -64,6 +64,9 @@ def _env_int(name: str, default: int) -> int: CHAT_TOOL_MAX_CHARS = int(os.environ.get("CHAT_TOOL_MAX_CHARS", "50000")) CHAT_TOOL_COMMAND_MAX_CHARS = int(os.environ.get("CHAT_TOOL_COMMAND_MAX_CHARS", "8000")) CHAT_COMPACT_TOKEN_THRESHOLD = int(os.environ.get("CHAT_COMPACT_TOKEN_THRESHOLD", "80000")) +# Claude SDK stdout JSON buffer; chat/tool output caps apply later after parsing. +CLAUDE_CODE_MAX_BUFFER_SIZE = _env_int("CPTR_CLAUDE_CODE_MAX_BUFFER_SIZE", 128 * 1024 * 1024) +CLAUDE_CODE_MAX_BUFFER_SIZE = _env_int("CPTR_CLAUDE_CODE_MAX_BUFFER_SIZE", 128 * 1024 * 1024) # ── Execute timeout ───────────────────────────────────────── # Default wait (seconds) for run_command / check_task when the caller diff --git a/cptr/utils/agents/claude_code.py b/cptr/utils/agents/claude_code.py index ecc8792..e0e4a18 100644 --- a/cptr/utils/agents/claude_code.py +++ b/cptr/utils/agents/claude_code.py @@ -7,6 +7,7 @@ import shlex from typing import Any, AsyncIterator +from cptr.env import CLAUDE_CODE_MAX_BUFFER_SIZE from cptr.utils.agents.attachments import PreparedAgentAttachments from cptr.utils.agents.events import ( AgentDone, @@ -128,6 +129,7 @@ async def run_claude_code_agent( "permission_mode": permission_mode, "env": env, "include_partial_messages": True, + "max_buffer_size": CLAUDE_CODE_MAX_BUFFER_SIZE, } if workspace: options_kwargs["cwd"] = workspace From 5cafb96f8459e52a4353e2644a9a9557f4d262a9 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 7 Jul 2026 01:07:52 -0500 Subject: [PATCH 5/7] refac --- cptr/env.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cptr/env.py b/cptr/env.py index aaa9d50..a535f3c 100644 --- a/cptr/env.py +++ b/cptr/env.py @@ -20,6 +20,7 @@ def _env_int(name: str, default: int) -> int: except ValueError: return default + # ── Data directory ────────────────────────────────────────── # Where cptr stores its database, config, and user data. # Default: ~/.cptr @@ -32,9 +33,7 @@ def _env_int(name: str, default: int) -> int: LOG_FORMAT = os.environ.get("CPTR_LOG_FORMAT", "text").lower() AUDIT_LOG_LEVEL = os.environ.get("CPTR_AUDIT_LOG_LEVEL", "NONE").upper() -AUDIT_LOG_PATH = Path( - os.environ.get("CPTR_AUDIT_LOG_PATH", str(DATA_DIR / "logs" / "audit.jsonl")) -) +AUDIT_LOG_PATH = Path(os.environ.get("CPTR_AUDIT_LOG_PATH", str(DATA_DIR / "logs" / "audit.jsonl"))) AUDIT_LOG_ROTATION = os.environ.get("CPTR_AUDIT_LOG_ROTATION", "10 MB") AUDIT_MAX_BODY_SIZE = _env_int("CPTR_AUDIT_MAX_BODY_SIZE", 2048) AUDIT_EXCLUDED_PATHS = [ @@ -66,7 +65,6 @@ def _env_int(name: str, default: int) -> int: CHAT_COMPACT_TOKEN_THRESHOLD = int(os.environ.get("CHAT_COMPACT_TOKEN_THRESHOLD", "80000")) # Claude SDK stdout JSON buffer; chat/tool output caps apply later after parsing. CLAUDE_CODE_MAX_BUFFER_SIZE = _env_int("CPTR_CLAUDE_CODE_MAX_BUFFER_SIZE", 128 * 1024 * 1024) -CLAUDE_CODE_MAX_BUFFER_SIZE = _env_int("CPTR_CLAUDE_CODE_MAX_BUFFER_SIZE", 128 * 1024 * 1024) # ── Execute timeout ───────────────────────────────────────── # Default wait (seconds) for run_command / check_task when the caller From e75b109b27c1c43efd8175e536bba89813c82163 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 7 Jul 2026 01:08:11 -0500 Subject: [PATCH 6/7] refac --- cptr/env.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cptr/env.py b/cptr/env.py index a535f3c..fd9f47a 100644 --- a/cptr/env.py +++ b/cptr/env.py @@ -20,7 +20,6 @@ def _env_int(name: str, default: int) -> int: except ValueError: return default - # ── Data directory ────────────────────────────────────────── # Where cptr stores its database, config, and user data. # Default: ~/.cptr @@ -33,7 +32,9 @@ def _env_int(name: str, default: int) -> int: LOG_FORMAT = os.environ.get("CPTR_LOG_FORMAT", "text").lower() AUDIT_LOG_LEVEL = os.environ.get("CPTR_AUDIT_LOG_LEVEL", "NONE").upper() -AUDIT_LOG_PATH = Path(os.environ.get("CPTR_AUDIT_LOG_PATH", str(DATA_DIR / "logs" / "audit.jsonl"))) +AUDIT_LOG_PATH = Path( + os.environ.get("CPTR_AUDIT_LOG_PATH", str(DATA_DIR / "logs" / "audit.jsonl")) +) AUDIT_LOG_ROTATION = os.environ.get("CPTR_AUDIT_LOG_ROTATION", "10 MB") AUDIT_MAX_BODY_SIZE = _env_int("CPTR_AUDIT_MAX_BODY_SIZE", 2048) AUDIT_EXCLUDED_PATHS = [ From d8d64b8816d5d117dfe51dd6fa7c78ed15cc675e Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 7 Jul 2026 01:11:37 -0500 Subject: [PATCH 7/7] refac --- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- uv.lock | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ae46b8..1fb69cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.8.4] - 2026-07-07 + +### Fixed + +- 💬 **Slash commands at the start.** New chats no longer block slash commands before the first regular message. +- 📱 **Better mobile typing.** Pressing Enter on phones and tablets now behaves like normal typing instead of choosing a suggestion or sending too soon. +- 🤖 **Larger Claude Code replies.** Claude Code can now handle bigger answers before chat display limits are applied. + ## [0.8.3] - 2026-07-07 ### Fixed diff --git a/pyproject.toml b/pyproject.toml index 1286aad..68acd71 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "cptr" -version = "0.8.3" +version = "0.8.4" description = "Your computer, from anywhere. Code, manage, and control your machine from the web." license = {file = "LICENSE"} readme = "README.md" diff --git a/uv.lock b/uv.lock index 541b6f8..865902d 100644 --- a/uv.lock +++ b/uv.lock @@ -284,7 +284,7 @@ wheels = [ [[package]] name = "cptr" -version = "0.8.3" +version = "0.8.4" source = { editable = "." } dependencies = [ { name = "aiosqlite" },