diff --git a/src/tau_coding/cli.py b/src/tau_coding/cli.py index 3df3a530..d1d052b5 100644 --- a/src/tau_coding/cli.py +++ b/src/tau_coding/cli.py @@ -205,6 +205,13 @@ def main( "(text, json, or transcript).", ), ] = None, + auto_name_session: Annotated[ + bool, + typer.Option( + "--auto-name-session/--no-auto-name-session", + help="Enable/disable automatic session naming in print mode.", + ), + ] = False, output: Annotated[ PrintOutputMode | None, typer.Option( @@ -391,15 +398,16 @@ def main( try: ok = anyio.run( run_openai_print_mode, - prompt, - model, - cwd or Path.cwd(), - effective_output, - provider, - None, - extension_paths, - not no_extensions, - project_extensions, + prompt=prompt, + model=model, + cwd=cwd or Path.cwd(), + output=effective_output, + provider_name=provider, + session_manager=None, + extension_paths=extension_paths, + extensions_enabled=not no_extensions, + project_extensions_enabled=project_extensions, + auto_name_session=auto_name_session, ) except (RuntimeError, ValueError) as exc: raise typer.BadParameter(str(exc)) from exc @@ -436,6 +444,7 @@ async def run_openai_tui( extension_paths=extension_paths, extensions_enabled=extensions_enabled, project_extensions_enabled=project_extensions_enabled, + tui_settings=None, # Will load defaults in run_tui_app ) @@ -655,6 +664,7 @@ async def run_openai_print_mode( extension_paths: tuple[Path, ...] = (), extensions_enabled: bool = True, project_extensions_enabled: bool = False, + auto_name_session: bool = False, ) -> bool: """Run print mode with the OpenAI-compatible provider configured from the environment.""" settings = load_provider_settings() @@ -684,6 +694,7 @@ async def run_openai_print_mode( extension_paths=extension_paths, extensions_enabled=extensions_enabled, project_extensions_enabled=project_extensions_enabled, + auto_name_session=auto_name_session, ) finally: await provider.aclose() @@ -707,6 +718,7 @@ async def run_print_mode( extension_paths: tuple[Path, ...] = (), extensions_enabled: bool = True, project_extensions_enabled: bool = False, + auto_name_session: bool = False, ) -> bool: """Run one non-interactive prompt and print streamed events. @@ -729,6 +741,7 @@ async def run_print_mode( extension_paths=extension_paths, extensions_enabled=extensions_enabled, project_extensions_enabled=project_extensions_enabled, + auto_name_session=auto_name_session, ) ) session.extension_runtime.set_ui_bridge(StderrUiBridge()) diff --git a/src/tau_coding/session.py b/src/tau_coding/session.py index 671a226f..537f7e15 100644 --- a/src/tau_coding/session.py +++ b/src/tau_coding/session.py @@ -235,6 +235,7 @@ class CodingSessionConfig: extensions_enabled: bool = True project_extensions_enabled: bool = False extension_runtime: ExtensionRuntime | None = None + auto_name_session: bool = True class CodingSession: @@ -278,6 +279,7 @@ def __init__( self._resource_paths = resource_paths_with_cwd(config.resource_paths, config.cwd) self._auto_compact_token_threshold = config.auto_compact_token_threshold self._auto_compact_enabled = config.auto_compact_enabled + self._auto_name_session = config.auto_name_session self._thinking_level = _state_thinking_level( state, default=_default_thinking_level_for_active_model(self), @@ -1300,6 +1302,7 @@ async def resume(self, session_id: str) -> str: runtime_provider_config=runtime_provider_config, auto_compact_token_threshold=self._auto_compact_token_threshold, auto_compact_enabled=self._auto_compact_enabled, + auto_name_session=self._auto_name_session, thinking_level=self._thinking_level, shell_command_prefix=self._config.shell_command_prefix, skills_enabled=self._config.skills_enabled, @@ -1882,6 +1885,10 @@ async def _try_auto_name_session( context: AgentCallDiagnosticContext, ) -> None: if not self._should_auto_name_session(): + # When auto-naming is disabled, use first 4 words of the user message + title = _fallback_session_name(first_message) + if title: + self._set_auto_session_title(title) return try: title = await self._generate_session_name(first_message) @@ -1899,6 +1906,8 @@ async def _try_auto_name_session( self._set_auto_session_title(title) def _should_auto_name_session(self) -> bool: + if not self._auto_name_session: + return False if self._config.session_id is None or self._config.session_manager is None: return False record = self._config.session_manager.get_session(self._config.session_id) diff --git a/src/tau_coding/tui/app.py b/src/tau_coding/tui/app.py index 9bbd254b..8ebf1f38 100644 --- a/src/tau_coding/tui/app.py +++ b/src/tau_coding/tui/app.py @@ -4479,6 +4479,7 @@ def _replace_tui_settings(self, *, theme: TuiThemeName) -> None: keybindings=self.tui_settings.keybindings, theme=theme, auto_copy_selection=self.tui_settings.auto_copy_selection, + auto_name_session=self.tui_settings.auto_name_session, sidebar_position=self.tui_settings.sidebar_position, turn_notification=self.tui_settings.turn_notification, ) @@ -6604,6 +6605,7 @@ async def run_tui_app( extension_paths: tuple[Path, ...] = (), extensions_enabled: bool = True, project_extensions_enabled: bool = False, + tui_settings: TuiSettings | None = None, ) -> str | None: """Run the Textual app and return the active id when its session is persisted.""" if new_session and session_id is not None: @@ -6612,6 +6614,7 @@ async def run_tui_app( provider_settings = load_provider_settings() shell_settings = load_shell_settings() manager = session_manager or SessionManager() + effective_tui_settings = tui_settings or load_tui_settings() record = _explicit_resume_record( manager, session_id=session_id, @@ -6677,6 +6680,7 @@ async def run_tui_app( extension_paths=extension_paths, extensions_enabled=extensions_enabled, project_extensions_enabled=project_extensions_enabled, + auto_name_session=effective_tui_settings.auto_name_session, ) ) custom_themes, theme_diagnostics = load_custom_tui_themes( diff --git a/src/tau_coding/tui/config.py b/src/tau_coding/tui/config.py index dfe54fbf..cb950d4d 100644 --- a/src/tau_coding/tui/config.py +++ b/src/tau_coding/tui/config.py @@ -92,11 +92,13 @@ class TuiSettings: auto_copy_selection: bool = False sidebar_position: Literal["left", "right", "off"] = "right" turn_notification: TurnNotificationMode = "desktop" + auto_name_session: bool = True def to_json(self) -> dict[str, Any]: """Serialize these settings to JSON-compatible data.""" return { "auto_copy_selection": self.auto_copy_selection, + "auto_name_session": self.auto_name_session, "keybindings": self.keybindings.to_json(), "sidebar_position": self.sidebar_position, "theme": self.theme, @@ -161,6 +163,10 @@ def tui_settings_from_json(data: dict[str, Any]) -> TuiSettings: data.get("auto_copy_selection", False), "auto_copy_selection", ), + auto_name_session=_bool_setting( + data.get("auto_name_session", True), + "auto_name_session", + ), sidebar_position=cast(Literal["left", "right", "off"], raw_sidebar), turn_notification=cast(TurnNotificationMode, raw_notification), )