diff --git a/CHANGELOG.md b/CHANGELOG.md index 99cf728e..b892ce27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to **omp-web** (`@kahme247/ompweb`) are documented in this f ### Added - Choose **Classifier** or **Vendor default** in Settings → AI Model Defaults → **Auto Thinking Source** when Reasoning is `auto`. The choice is saved in omp's native config for newly started or restarted agents. Vendor mode prefers the publisher's effort, then omp's per-model default, then normal Auto fallback. Requires an omp release containing [can1357/oh-my-pi#14114](https://github.com/can1357/oh-my-pi/pull/14114). +- Show conflicting skill names and deduplicated installations when an OMP session starts, with resolution details, a **×** button that dismisses the notice for the session until the diagnostic report changes, and a persisted **Turn off** action that disables startup notices. Inspect a running session manually in **Settings → Extensions & Tools → Skills**, even when notices are off; inspection never resumes a stopped session. Requires an OMP runtime with the skill-diagnostics RPC commands; older runtimes report live diagnostics as unavailable. - Ask a side question with `/btw `: omp answers from the current conversation in a panel above the composer, even while the agent is working, and the question never enters the chat. Cancel a running answer, copy it, or ask follow-ups in the same topic. `/btw` on its own lists the session's past side questions, including ones asked in the terminal, each expandable to all its turns with **Copy** and **Follow up**. Side questions are text-only: with an attachment in the composer, `/btw` is refused and the draft is kept. An answer that omp lost (for example after its process restarted) shows as **Interrupted** instead of spinning. Requires an omp with the `btw` RPC commands; older omp shows "/btw requires a newer omp" instead of sending the text to the model. - Show omp's Claude usage-limit badge in the composer toolbar, matching the terminal status line during the wrap-up allowance or once `/slow` low priority takes over. Reset times use the browser's locale and timezone. Requires an omp version whose `get_state` reports structured `usageLimit` state. - Add a **Slow** toggle next to **Fast** in the composer toolbar, the equivalent of omp's `/slow`. On Claude models it turns low priority on or off in your omp settings, so it applies to every session and terminal; on OpenAI and Google models it switches this session to the provider's flex tier. Once the session's omp process runs, the toggle follows omp's `get_state` (`slowModeSupported`); before that, including in a new session, it follows the selected model's provider (`anthropic`, `openai`, `openai-codex`, `google`, `google-vertex`) and, on Claude, the `providers.anthropic.slowMode` setting. Clicking it there starts the session's omp process. diff --git a/README.md b/README.md index 0e5a7884..74223bc3 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,20 @@ Queue **Delete** and **Edit** additionally require `remove_queued_message`. Dele The queue panel shows omp's own queue (`queuedMessages` in `get_state` and `queue_update` events, omp 18.4.4 or later), so every device viewing a session sees the same queued messages. **Stop** moves the text of messages still waiting in the queue back into the composer instead of letting the agent run them; a steer the model already picked up through live steering still runs. Older omp runtimes show no queue panel, and Stop cannot take queued messages back. +Skill startup notices require an OMP runtime with `get_skill_diagnostics`, +`set_skill_startup_diagnostics`, and `skill_diagnostics_update`. Conflicts and +redundant installations appear above the composer when its OMP session starts; +an empty new-chat page does not start OMP just for diagnostics. **Details** shows +the resolved default, variants, identical copies, backing paths, sources, and +selection reason. The **×** button dismisses the notice for that session until +the diagnostic report changes. **Turn off** and **Settings → +Interface & Behavior → Skill startup notices** use OMP's persisted +`skills.showStartupDiagnostics` preference, not a separate browser setting. +**Settings → Extensions & Tools → Skills → View skill diagnostics** remains +available for a selected running session when notices are off. Inspection does +not resume stopped sessions. Missing support or no running session is unavailable, +not a clean result. + ## Quick Start **Run directly without installing:** diff --git a/app/api/agent/[id]/route.ts b/app/api/agent/[id]/route.ts index f4eb1ba9..d6b39454 100644 --- a/app/api/agent/[id]/route.ts +++ b/app/api/agent/[id]/route.ts @@ -18,6 +18,13 @@ const NO_SPAWN_REPLIES: Record = { btw_cancel: { cancelled: false }, }; +// Live diagnostics of a skill-resolving omp. A saved or exited session has none, +// and resuming a full child (MCP, LSP) just to answer a read-only inspection or +// flip one setting is not what the click asked for: with no live wrapper these +// answer 409 instead of starting omp, and a live idle child is never replaced +// because the advisor flag differs. +const LIVE_SESSION_ONLY = new Set(["get_skill_diagnostics", "set_skill_startup_diagnostics"]); + /** omp-web's own failures carry a stable code the client can localize; omp's * errors stay opaque English text. */ function commandErrorResponse(error: unknown) { @@ -60,14 +67,21 @@ export async function POST( // running and pick the flag up at the next natural respawn. const existing = getRpcSession(id); const noSpawn = Object.hasOwn(NO_SPAWN_REPLIES, body.type); + const liveOnly = LIVE_SESSION_ONLY.has(body.type); if (existing?.isAlive()) { - if (noSpawn || existing.advisorSpawned === advisor || existing.isRunning()) { + if (noSpawn || liveOnly || existing.advisorSpawned === advisor || existing.isRunning()) { const result = await existing.send(body); return NextResponse.json({ success: true, data: result }); } await existing.destroyAndWait(); } if (noSpawn) return NextResponse.json({ success: true, data: NO_SPAWN_REPLIES[body.type] }); + if (liveOnly) { + return NextResponse.json( + { error: "Skill diagnostics require a running session", code: "skill_diagnostics_unavailable" }, + { status: 409 }, + ); + } const resolved = await resolveSessionPathOr404(id); if ("response" in resolved) return resolved.response; diff --git a/components/ChatWindow.tsx b/components/ChatWindow.tsx index 6257d52d..30bb80ba 100644 --- a/components/ChatWindow.tsx +++ b/components/ChatWindow.tsx @@ -13,6 +13,7 @@ import { ExtensionDialog } from "./ExtensionDialog"; import { SubagentTranscriptDialog } from "./SubagentTranscriptDialog"; import { ChatMinimap, useMessageRefs } from "./ChatMinimap"; import { ComposerPanels } from "./ComposerPanels"; +import { SkillDiagnosticsNotice } from "./SkillDiagnostics"; import { BtwHistoryDialog, type BtwPanelProps } from "./BtwPanel"; import OmpWebLogo from "./OmpWebLogo"; import { CHAT_COLUMN_MAX_WIDTH, MINIMAP_WIDTH } from "@/lib/chat-layout"; @@ -532,6 +533,7 @@ export function ChatWindow({ session, newSessionCwd, newSessionWorkspace, toolCa isCompacting, compactResult, tokensPerSecond, displayModel: displayModelValue, sessionStats, slashCommands, slashCommandsLoading, queuedMessages, advisorActive, advisorEnabled, handleAdvisorChange, notices, dismissNotice, extensionDialog, extensionCustomUi, extensionStatuses, extensionWidgets, respondToExtensionUi, sendExtensionCustomInput, + skillDiagnostics, setSkillStartupDiagnostics, isAutoModelSelection, agentPhase, activeGoal, activePlan, liveToolResults, @@ -1232,6 +1234,7 @@ export function ChatWindow({ session, newSessionCwd, newSessionWorkspace, toolCa {newSessionWorkspace} + setSkillStartupDiagnostics(false)} /> {/* ChatInput insets itself by CHAT_COLUMN_PADDING; cancel this column's padding so the composer matches its in-session width. */} @@ -1447,6 +1450,7 @@ export function ChatWindow({ session, newSessionCwd, newSessionWorkspace, toolCa /> )} + setSkillStartupDiagnostics(false)} /> { if (currentTab === "system") { @@ -1140,6 +1142,9 @@ export function SettingsConfig({ activeTab, toolCallsDefaultCollapsed, onToolCal + + patchSection("skills", { showStartupDiagnostics: enabled })} /> +