From ffe3b6afd41edeaafee151b2006368486f298afe Mon Sep 17 00:00:00 2001 From: can1357 Date: Wed, 10 Jun 2026 09:23:59 +0200 Subject: [PATCH] fix(coding-agent): rehome TITLE_SYSTEM.md discovery and reload it on cwd change --- packages/coding-agent/CHANGELOG.md | 2 +- packages/coding-agent/src/main.ts | 15 +-------------- .../coding-agent/src/modes/interactive-mode.ts | 9 +++++++++ packages/coding-agent/src/system-prompt.ts | 14 ++++++++++++++ .../test/main-interactive-input.test.ts | 3 ++- 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 62e86cdf6..9c714f4ce 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -10,7 +10,7 @@ - Added `python.interpreter` to pin eval's Python backend to an explicit interpreter and skip automatic runtime discovery ([#1802](https://github.com/can1357/oh-my-pi/issues/1802)). - Added `!command` resolution for `models.yml` provider `apiKey` values and provider/model headers ([#1888](https://github.com/can1357/oh-my-pi/issues/1888)). - Documented the oMLX setup path through existing OpenAI-compatible local discovery ([#1957](https://github.com/can1357/oh-my-pi/issues/1957)). -- Added `TITLE_SYSTEM.md` discovery so users can override the automatic session-title generation prompt for online and local tiny title models without patching installed prompt files. +- Added `TITLE_SYSTEM.md` discovery so users can override the automatic session-title generation prompt for online and local tiny title models without patching installed prompt files. The override is re-discovered when the session working directory changes via `/cwd`. - Added a structured memory runtime surface for extensions and UI integrations to query backend status, search memories, and save explicit memories across the configured memory backend. - Added support for Git repositories using the `reftable` storage format by detecting `extensions.refStorage = reftable` in the repository configuration and falling back to shelling out to Git commands (`git symbolic-ref`, `git rev-parse`) for reference and HEAD resolution. - Added `/setup providers` (also available as `/setup` or `/providers`) to reopen the interactive provider setup scene from an active TUI session, letting users sign in and choose a web search provider without rerunning the full onboarding flow. diff --git a/packages/coding-agent/src/main.ts b/packages/coding-agent/src/main.ts index 9ed7b0e52..89f60ca4a 100644 --- a/packages/coding-agent/src/main.ts +++ b/packages/coding-agent/src/main.ts @@ -67,7 +67,7 @@ import { import type { AgentSession } from "./session/agent-session"; import type { AuthStorage } from "./session/auth-storage"; import { resolveResumableSession, type SessionInfo, SessionManager } from "./session/session-manager"; -import { resolvePromptInput } from "./system-prompt"; +import { discoverTitleSystemPromptFile, resolvePromptInput } from "./system-prompt"; import { initTelemetryExport, isTelemetryExportEnabled } from "./telemetry-export"; import { AUTO_THINKING } from "./thinking"; import { discoverStartupLspServers, type LspStartupServerInfo } from "./tools"; @@ -721,19 +721,6 @@ function discoverAppendSystemPromptFile(): string | undefined { return undefined; } -/** Discover TITLE_SYSTEM.md file for automatic session-title prompt overrides */ -export function discoverTitleSystemPromptFile(cwd?: string): string | undefined { - const projectPath = findConfigFile("TITLE_SYSTEM.md", { user: false, cwd }); - if (projectPath) { - return projectPath; - } - const globalPath = findConfigFile("TITLE_SYSTEM.md", { user: true, cwd }); - if (globalPath) { - return globalPath; - } - return undefined; -} - async function buildSessionOptions( parsed: Args, scopedModels: ScopedModel[], diff --git a/packages/coding-agent/src/modes/interactive-mode.ts b/packages/coding-agent/src/modes/interactive-mode.ts index c3e49fb9b..b1cfec78d 100644 --- a/packages/coding-agent/src/modes/interactive-mode.ts +++ b/packages/coding-agent/src/modes/interactive-mode.ts @@ -78,6 +78,7 @@ import type { ShakeMode } from "../session/shake-types"; import { BUILTIN_SLASH_COMMAND_RESERVED_NAMES } from "../slash-commands/builtin-registry"; import { formatDuration } from "../slash-commands/helpers/format"; import { STTController, type SttState } from "../stt"; +import { discoverTitleSystemPromptFile, resolvePromptInput } from "../system-prompt"; import type { LspStartupServerInfo } from "../tools"; import { normalizeLocalScheme } from "../tools/path-utils"; import { setAutoQaConsentHandler } from "../tools/report-tool-issue"; @@ -684,6 +685,13 @@ export class InteractiveMode implements InteractiveModeContext { this.updateEditorTopBorder(); } + /** Reload the title-generation system prompt override for the provided working directory. */ + async refreshTitleSystemPrompt(cwd?: string): Promise { + const basePath = cwd ?? this.sessionManager.getCwd(); + const titleSystemPromptSource = discoverTitleSystemPromptFile(basePath); + this.titleSystemPrompt = await resolvePromptInput(titleSystemPromptSource, "title system prompt"); + } + /** Reload slash commands and autocomplete for the provided working directory. */ async refreshSlashCommandState(cwd?: string): Promise { const basePath = cwd ?? this.sessionManager.getCwd(); @@ -718,6 +726,7 @@ export class InteractiveMode implements InteractiveModeContext { // Re-warm plugin roots, capabilities, slash commands, and the ssh tool so // the next prompt sees everything scoped to the new project directory. clearClaudePluginRootsCache(); + await this.refreshTitleSystemPrompt(newCwd); resetCapabilities(); await this.refreshSlashCommandState(newCwd); await this.session.refreshSshTool({ activateIfAvailable: true }); diff --git a/packages/coding-agent/src/system-prompt.ts b/packages/coding-agent/src/system-prompt.ts index 21dff32a2..79e98e152 100644 --- a/packages/coding-agent/src/system-prompt.ts +++ b/packages/coding-agent/src/system-prompt.ts @@ -8,6 +8,7 @@ import { $env, getGpuCachePath, getProjectDir, hasFsCode, isEnoent, logger, prom import { $ } from "bun"; import { contextFileCapability } from "./capability/context-file"; import { systemPromptCapability } from "./capability/system-prompt"; +import { findConfigFile } from "./config"; import type { SkillsSettings } from "./config/settings"; import { type ContextFile, loadCapability, type SystemPrompt as SystemPromptFile } from "./discovery"; import { expandAtImports } from "./discovery/at-imports"; @@ -208,6 +209,19 @@ async function getEnvironmentInfo(): Promise !!e.value); } +/** Discover TITLE_SYSTEM.md file for automatic session-title prompt overrides */ +export function discoverTitleSystemPromptFile(cwd?: string): string | undefined { + const projectPath = findConfigFile("TITLE_SYSTEM.md", { user: false, cwd }); + if (projectPath) { + return projectPath; + } + const globalPath = findConfigFile("TITLE_SYSTEM.md", { user: true, cwd }); + if (globalPath) { + return globalPath; + } + return undefined; +} + /** Resolve input as file path or literal string */ export async function resolvePromptInput(input: string | undefined, description: string): Promise { if (!input) { diff --git a/packages/coding-agent/test/main-interactive-input.test.ts b/packages/coding-agent/test/main-interactive-input.test.ts index ef328deb7..7f32d7eab 100644 --- a/packages/coding-agent/test/main-interactive-input.test.ts +++ b/packages/coding-agent/test/main-interactive-input.test.ts @@ -2,8 +2,9 @@ import { afterEach, describe, expect, it, vi } from "bun:test"; import * as fs from "node:fs/promises"; import * as os from "node:os"; import * as path from "node:path"; -import { discoverTitleSystemPromptFile, submitInteractiveInput } from "@oh-my-pi/pi-coding-agent/main"; +import { submitInteractiveInput } from "@oh-my-pi/pi-coding-agent/main"; import type { SubmittedUserInput } from "@oh-my-pi/pi-coding-agent/modes/types"; +import { discoverTitleSystemPromptFile } from "@oh-my-pi/pi-coding-agent/system-prompt"; const cleanupDirs: string[] = [];