Metadata-Version: 2.4
Name: spyder-ai-chat
Version: 1.0.7
Summary: OpenAI-compatible AI chat pane + FIM completion for Spyder 6
Author: Maciej Piecko
License-Expression: MIT
Project-URL: Homepage, https://sourceforge.net/projects/spyder-ai-chat-plugin/
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: spyder>=6.1
Dynamic: license-file

# Spyder IDE AI Chat Plugin

An OpenAI-compatible AI chat panel for **Spyder 6.1+**.
Connect to **12 providers** — OpenAI, Groq, Mistral, DeepSeek, Together AI, Fireworks AI, OpenRouter, Azure OpenAI, Ollama, LM Studio, vLLM, or any custom OpenAI-compatible endpoint — all from inside your IDE, without switching windows.

© 2026 Maciej Piecko — MIT License

---

## What's new in 1.0.7
- **Switchable tool-call signatures** - Agentic settings now support Compatibility, XML-only, and legacy Markdown-only tool syntax modes. Compatibility mode is the default and teaches the new XML-style tool format while still accepting existing Markdown tool fences.
- **Markdown minimal tool prompt** - The tool-call syntax selector now uses shorter labels (`Compatible`, `XML`, `XML minimal`, `Markdown`, `Markdown minimal`) and adds a compact Markdown prompt for micro/small models that handle Markdown fences better than XML.
- **XML tool parser and prompt support** - All agentic tools now have XML tag metadata, XML examples in the injected tool-use prompt, and parser normalization into the existing execution pipeline, including streaming placeholders and malformed unclosed-body guards.
- **XML minimal tool prompt** - A new **XML minimal** syntax mode keeps the injected tool-use prompt short and example-focused for weaker local models while still using the XML tool parser.
- **Tool-syntax-aware rendering** - Live rendering, collapsed agentic summaries, and action detection now respect the selected tool-call syntax so XML-only mode does not treat legacy Markdown fences as executable tools.
- **Safer Markdown tool fences** - Legacy Markdown tool mode now supports four-backtick `file:` and `patch:` fences so generated Markdown code blocks inside file content do not close the tool call early; live rendering also avoids transient empty code blocks while long tool openers stream in.
- **Per-chat confirmation suppression** - Same-tool confirmation dialogs now offer an **Always run ...** action that runs the selected actions and suppresses future confirmation dialogs for that tool type in the current chat session; mixed-tool batches remain guarded and suppressions reset after Spyder restarts.
- **Clearer standard XML and Compatible prompts** - detailed XML prompts now organize enabled tools under Markdown-formatted inspection and modifying/application groups, keep sequencing guidance beside the relevant group, and remove repeated batching, syntax, and supported-tool rules.
- **Tool-syntax-aware patch recovery** - failed patches now return recovery instructions matching the selected XML or Markdown prompt; standard modes can request numbered reads, minimal modes use only their advertised base read form, and disabled read/file tools are omitted from the advice.
- **Corrected minimal tool definitions** - XML/Markdown minimal prompts now distinguish body-based calls, Markdown `copy:`, `rename:`, and `rename_dir:` examples place the destination in the tool body, disabled-action warnings list the unavailable functions, and file creation notes that parent directories are created automatically.
- **Opaque Run Python streaming** - unfinished `run:python` and `<tool:run>` bodies now use the compact generating spinner and live character counter instead of exposing long scripts line by line; the completed tool renders normally after its closing marker arrives.
- **Independent chat-history deletion countdowns** - arming deletion on multiple chat rows now keeps every countdown active; each chat is deleted and removed independently when its own timer expires instead of the first deletion cancelling the remaining rows.

## What's new in 1.0.6
- **Paged-chat Regenerate placement fix** — Regenerate is now shown only on the latest assistant/error message in the full chat history, not merely the latest assistant visible on the current page.
- **Faster long-stream rendering** — hidden in-progress `file:`/`patch:` tool bodies now drain from the provider queue in adaptive batches, helping the UI keep up with very fast local models while preserving normal character-level Markdown rendering.
- **Settings startup blink fix** — the Context tab token-limit table no longer creates transient unparented Qt widgets while opening Settings, removing the brief top-level window flash.
- **Compaction-aware regenerate safety** — regeneration continues to use the same compacted active context as normal sends, avoiding full-history payloads after compaction.

## What's new in 1.0.5
- **First-run context-limit refresh fix** — model-specific token limits added immediately after first provider configuration now update the chat token estimator without requiring a Spyder restart.
- **Per-model inference parameter templates** — the inference-parameters popup can now save, update, delete, and manually load settings per provider/model; new chats automatically start with the saved template while existing chats keep their own saved params unless the user loads the template.
- **Inference parameter default display fix** — unset float parameters with negative ranges, such as presence and frequency penalties, now show `default` instead of misleading `0,00`; explicit zero values are still supported when the user sets them.
- **Settings provider/model handoff fix** — the Connection tab's **Test & Load Models** button now loads fetched model names into the open Settings session, so the Context tab can add per-model token limits for a newly configured provider before closing and reopening Settings; the success message now clarifies that OK is still required to save.
- **FIM model-load error reporting** — the Auto-complete settings panel no longer reports stale saved FIM models as freshly loaded when the provider server is unavailable; failed loads keep the visible error state.
- **Stop-button lifecycle fix** — clicking Stop just after a provider stream has already ended no longer crashes when Qt has deleted the worker thread before the panel cleared its reference.
- **Malformed long tool-call safety guard** — Stop now force-closes the active streaming response, late chunks are ignored, unclosed `file:`/`patch:` tool bodies are capped by a configurable Agentic setting (default 50k chars), and an error-only render failure can no longer overwrite an existing real chat history file.
- **Unclosed file/patch stream limit enforcement** — the live generating counter for open `file:` and `patch:` tool calls now enforces the configured max unclosed stream size directly, so malformed never-ending file bodies are stopped and recorded as assistant errors instead of continuing to drain buffered text silently.
- **Stopped tool-call context notice** — stopped partial assistant responses persist with `agentic_discarded: true`, reload as disabled tool blocks, and now add a user-side client notice to the next LLM request that the partial tool calls were discarded and not executed.
- **OpenRouter preset support** — OpenRouter connection settings now include a `Preset identifier` field, saved in plugin state and sent as the root `preset` value in chat-completion requests when configured.

- **Agentic tool prompt clarity** — the injected tool-use prompt now starts with clearer “real-world actions” wording, explicitly separates enabled inspection tools from modifying/application tools, integrates patch line-number inspection guidance into the file/patch rules, and keeps final formatting guardrails for non-inline tool calls.
- **Grouped inspection readability** — grouped inspect actions now show the specific tool icon and label for each entry (`Read`, `List`, `Search`, or `Lint`) so mixed inspection batches are easier to scan.
- **Grouped inspection output collapse fix** — agentic output rows linked to grouped inspection actions now also respect the top-level agentic summary collapse state, so collapsing the parent group hides the output consistently like modifying-tool groups.
- **Contiguous inspection grouping** — inspection actions are now grouped only when they are adjacent in the assistant message; explanatory text or modifying/application actions split the group so the rendered order matches the actual tool execution order.
- **Git diff popup newborn-repo fix** — the local diff popup now works after `git init` before the first commit exists, avoiding `HEAD`-based diff failures, previewing untracked files as additions, and disabling branch-comparison scopes until an initial commit is available.
- **Regenerate after compaction guard** — Regenerate buttons are hidden for assistant responses that sit before the latest compaction request or summary boundary, preventing regenerated content from being inserted into already-compacted history segments.

## What's new in 1.0.4

- **Live tool generation stability** — open streamed tool calls now show a compact text-only generating label in the existing assistant stream instead of creating a transient Qt widget, preventing small top-level window flashes during file/read/list generation.
- **Generating label polish** — the live tool-call progress text is smaller and aligned with rendered action titles, uses a normalized timer-driven spinner, shows only the tool name/target and character count, and no longer leaks the current raw streamed line.
- **Generating-state contrast** — the live tool-call spinner and generating text now use a theme-aware light-orange colour so they remain distinct from the action title and target.
- **Lazy agentic-output previews** — agentic output hover popups are created only when hovered, reducing unnecessary widget creation in long agentic chats.
- **Agentic output visual alignment** — auto-sent tool-result messages now use the same blue left accent as user-side content, with tighter indentation so the “Agentic output” label aligns with nearby lightweight tool-action titles.
- **Batched agentic-output visibility fix** — agentic output rows linked to batched tool calls now inspect the collapse state of every action in the batch, including mixed batches separated by explanatory text, so expanding any participating action reveals the shared output and collapsing all of them hides it.
- **On-demand file and patch previews** — collapsed `file:` and `patch:` action blocks now defer editor creation, syntax/diff formatting, and content population until their first expansion, reducing live-rendering overhead and accelerating long chat-history loads.
- **Safer action status parsing** — successful actions whose paths contain words like `error`, `failed`, `cannot`, or `running` no longer appear as failed/running in the action header; status detection now relies on explicit status prefixes and stored action state.
- **Strict patch validation** — malformed patch calls without unified-diff hunks and patches that produce no actual file changes are now rejected and reported to the LLM with patch-recovery guidance instead of being marked as successfully applied.
- **Read/list error persistence** — failed `read:` and `ls:` actions no longer fall through to the success recorder; they remain Error in both live and history rendering, with the failure reason shown consistently in the expanded detail line and agentic output.
- **Stable nested-list rendering** — Markdown lists now use explicit Qt marker/content rows instead of native ordered-list markers, preventing malformed numbering and wrapped nested entries from overlapping following items at different chat-pane widths while preserving readable row spacing and compact indentation.
- **Semi-mode compaction fallback fix** — selecting LLM Summary while Agentic mode is Semi now consistently uses the effective Cut-off strategy in request building, context estimates, automatic triggering, and HTTP output budgeting. Cut-off removes complete old exchanges at real user-request boundaries while preserving the newest exchange, and internal compaction request/summary records are excluded from the active conversation window.
- **Prompt-aware compaction budget** — Cut-off and first-summary history trimming now reserve threshold space for the active system prompt, generated agentic tool prompt, project-root note, and existing compaction summary instead of granting message history the entire threshold budget and adding fixed prompt content afterward.

## What's new in 1.0.3

- **Local graphical git diff popup** — clicking the git bar branch/stat text opens a local-only diff viewer for uncommitted changes on the current branch, without sending anything to the LLM.
- **Git diff scope selector** — the popup can switch between `Working tree vs HEAD`, committed `Branch vs main/master`, and committed `Branch vs upstream` views, with branch scopes loaded asynchronously and uncommitted changes reported separately.
- **Patch-style git diff rendering** — changed, staged, unstaged, deleted, and untracked text files are shown in per-file cards using the existing coloured patch diff view, with binary/large-file safeguards.
- **Git diff summary polish** — the popup now keeps only the compact overall summary at the top and moves per-file insertion/deletion stats into the corresponding file diff cards.
- **Git diff popup responsiveness and polish** — the diff window now opens immediately with a loading state, uses a single button-like git status pill in the git bar, and removes extra borders from file diff previews.
- **Chat user-message polish** — normal user messages now appear as right-aligned themed blocks with improved spacing, while agentic output and error blocks keep their existing rendering.
- **Stop-before-first-token handling** — stopping an LLM request before any visible response now creates a visible assistant-side stopped/error record, preserving valid chat history and enabling Regenerate.
- **Agentic inspect grouping stability** — grouped read/list/grep/lint action widgets now receive the proper chat parent before insertion to avoid transient top-level widget flashes during auto execution.
- **Agentic settings tabs** — the Agentic settings page is split into `Agentic settings`, `Action's properties`, and `Tools system prompt` tabs for easier navigation.
- **Tool prompt preview polish** — the tool system prompt tab now uses the full page, removes the old collapse control, and includes a short note explaining the plugin's Markdown DSL tool-calling scheme.

## What's new in 1.0.2

- **Agentic web search tool** — added `web_search:<query>` for structured public web-search results through Jina AI or Tavily, with Jina shown first in settings.
- **Secure web-search tokens** — Jina AI and Tavily access tokens are configured separately in Agentic → Action properties and stored with the existing OS keyring fallback flow.
- **Web-search confirmation flow** — web search is treated as a confirmation-required modifying tool, runs asynchronously, persists Done/Cancelled/Error state, and auto-sends structured title/URL/description/date results to the LLM.
- **Web-search onboarding notice** — enabling the tool without a selected provider token shows an inline Agentic settings notice with links to the provider token pages.

## What's new in 1.0.1

- **Streaming renderer stability** — live streamed responses from chunked providers now drain through a small character queue, making Markdown lists and code blocks render consistently while keeping the final saved history unchanged.
- **Live code-block duplication guard** — completed code blocks are no longer duplicated or mixed while streaming providers send larger text chunks.
- **Lightweight tool block polish** — collapsed tool blocks now keep action titles readable, align expand markers after the title, collapse successful status/output details with the action content, and use tighter spacing for grouped actions.
- **Live agentic action placeholders** — incomplete streamed tool calls now show only a generating action title, spinner, and character count until the closing fence arrives, so raw file or patch bodies no longer scroll through the chat.
- **Model selector layout fix** — the model filter field and empty-results row now stay aligned to the top of the popup, so “No matching models” no longer appears in the middle of the dropdown.
- **System prompt popup** — system prompt controls moved into an `SP` popup in the prompt toolbar, with panel-clamped positioning, hover-highlighted toolbar styling, dark/light theme styling, and an agentic prompt injection note.

## What's new in 1.0.0

- **Manual agentic mode removed** — Agentic mode now supports only **Semi** and **Full**. Existing saved Manual/`off` configurations migrate to **Semi**, preserving confirmation review while simplifying the execution model.
- **Inline action execution removed** — chat-rendered tool blocks no longer expose execute or re-run buttons; actions execute only through the normal Semi/Full response-processing flow and historical blocks are passive status records.
- **Cancelled action state** — cancelling a confirmation dialog marks requested tools as **Cancelled by user** in chat/history. Full-dialog cancel stops the chain without an immediate LLM call; the next real user request includes a client notice. Partial approval auto-sends executed results plus a concise cancelled-action notice.
- **Lightweight tool block rendering** — chat-rendered tool blocks now use plain clickable text headers, collapsed content by default, subtle content backgrounds, plain text status rows, and an always-on 10-line expanded-content cap with scrollbars; the old file/patch height-limit setting was removed.
- **Prompt and Settings cleanup** — the injected tool-use prompt, Agentic settings controls, and behaviour matrix now describe only Semi and Full workflows.

## What's new in 0.9.6

- **Safer Full autonomous default** — fresh installs now start in Full autonomous mode with modifying-action confirmation enabled, so routine inspection can run smoothly while file/environment-changing actions still require review.
- **Silent Full-mode warning refinement** — the Full autonomous warning appears only when modifying-action confirmation is disabled and now recommends keeping confirmation enabled unless the user trusts the LLM not to damage the application or system.
- **No-project safety guard** — an amber in-pane warning now asks users to open or create a Spyder project for the full agentic experience; without a project, all modifying actions are blocked for safety.
- **Project-required tool restrictions** — `run:python`, `install:pip`, `run:git`, and `lint:` now join file-changing tools in requiring a trusted project root, preventing console, environment, git, or lint-report side effects when no project is open.
- **Blocked async tool output forwarding fix** — security-blocked async-capable tools such as `run:python` now forward their restriction error into the collected agentic output, so the LLM receives the same feedback as it does for blocked file actions.
- **LLM connection-error context** — provider failures that happen before any assistant text is streamed are saved as `assistant_error` chat entries and converted into user-side client notices in the next API payload, preserving failed prompts and error details without sending invalid message roles.
- **User-boundary delete cleanup** — chat delete controls now appear only on real user messages; deleting a user request removes the full user-started exchange, including any following agentic outputs and assistant continuations up to the next real user request.
- **Manual mode guardrail polish** — Manual mode uses model-facing “Tool-use rule violation” messages, lists skipped tools, disables skipped action buttons across reloads, forwards inline modifying-action results, and collects `run:python`/`sleep:` batch output into the same agentic result.
- **Agentic collapse readability polish** — collapsed agentic groups now keep the assistant text before the first tool call visible above the collapse summary, so the model's plan or intro remains readable; summary typography is tuned for both title-row and inline placements.
- **Thinking block auto-collapse setting** — Settings → Dialogs now includes a default-on option to auto-collapse `<think>` blocks, applying to live streamed thinking sections and chats loaded from history.
- **Model selector filtering** — the top model dropdown now includes a live filter field, making large provider lists such as OpenRouter easier to search by partial or multi-term model names.
- **Chat collection move fix** — moving the currently open chat from Manage Chat Collections now updates the active save target immediately, preventing autosave from recreating the chat in its old collection.
- **Agentic prompt cleanup** — prompt text no longer exposes internal “manual mode” terminology to the model; inspection rules are merged and only list inspection tools currently enabled in Settings.
- **Compaction summary update prompt** — follow-up LLM-summary compactions now ask for an updated replacement summary that merges the previous compacted summary with newer messages and tool/action results instead of repeating the old summary.
- **Compaction no-tool guard** — compaction summary requests now forbid tool calls and list only currently enabled tool-call markers as forbidden examples, avoiding disabled-tool advertising.
- **Agentic tool registry refactor** — settings keys, parser prefixes, supported-tool formats, labels, project-root requirements, and compaction no-tool markers now share one registry.
- **Git output decoding fix** — Git bar actions and `run:git` now tolerate non-locale bytes in diffs on Windows by decoding output as UTF-8 with replacement.
- **Context estimate popup layout polish** — the token tooltip now groups current context, full history, current-context message counts, and LLM speed in a clearer order with aligned section dividers.
- **Inference parameters popup cleanup** — provider connection notes no longer appear in the compact per-chat inference parameters popup.
- **Reliable `install:pip` execution and reporting** — package installs now run through `sys.executable -m pip install ...` in a background subprocess, return captured pip output/exit code, and participate in the semi/full auto batch collector instead of using Spyder's unreliable `%pip` magic or console scraping.
- **Semi/full batch output fix** — normal semi/full autonomous tool execution now routes `install:pip` through the same batch collector as other tools, while direct action-block clicks keep the manual-style forwarded-output behavior.
- **HTTP tool User-Agent fallback** — public `http:` requests now receive a random browser-like `User-Agent` when the LLM did not provide one, while local/private traffic and explicit headers stay unchanged.
- **HTTP text-mode response sizing** — the default HTTP returned-content limit increased from 20k to 100k characters, and `http:...:text` now applies that cap after HTML is stripped.
- **HTTP context safety gate** — `http:` result size is now capped before the request worker starts using a protected recent-chain budget, preserving the triggering request and assistant tool call.
- **Git bar startup recovery** — the git status bar now re-checks Spyder's live project root on every refresh and resets retry state when the detected working directory changes.
- **Settings text polish** — Agentic Manual mode now clarifies that only inspection-tool results are not auto-sent, and the LLM Project Context section matches the `📁 Proj. Context ○ / ●` toggle label.
- **Lint report hint clarity** — `lint:` results now explicitly call `.ai_chat/lint/` a directory and include created report-file paths so models can read specific JSON reports.
- **Indented list rendering fix** — Markdown lists that start indented after headings or paragraphs now render correctly, with a parser guard for malformed block-looking lines.

## What's new in 0.9.5

- **Agentic tools terminology** — the agentic prompt and Settings → Agentic UI now describe model actions as tool use instead of "agentic fences", which is easier for small tool-trained models to follow.
- **Clearer tool-call prompt** — the prompt now includes an **Available tools** section, a generic triple-backtick tool-call format, and a final supported-tool list telling the model that no other tool names are available.
- **Better file/patch instructions** — `file:` and `patch:` are grouped together, paths are described as project-relative or absolute, examples are clearly placeholders, multiple file creations in one response are allowed, and `read:` is recommended after patches when enabled.
- **Numbered read output for patch repair** — `read:` supports `:lines` (`read:app/main.py:lines` and `read:app/main.py:100-150:lines`) to return file content with line numbers at the beginning of every line.
- **Shorter patch recovery guidance** — failed patch blocks now point the LLM to `read:<file>:lines`, one corrected `patch:` call, and full-file `file:` recreation only if patching still fails.
- **Body-based grep tool** — `grep:` now uses the opening marker as an optional file/directory scope and the block body as the Python regex, so colons inside patterns are safe; old inline `grep:pattern[:scope]` parsing was removed.
- **Manual mode guardrail** — Manual mode is marked deprecated, mixed inspection + modifying/tool responses skip inspection tools with disabled buttons plus an auto-sent warning, and inspection-only responses are limited to the first inspection tool; later inspection tools are skipped and the first result panel includes the warning before the user can forward it.
- **Better batching behavior** — autonomous/semi modes now encourage independent tools to be called together in one response instead of creating files one at a time when no inspection result is needed first.
- **Console bypass guard** — when `run:python` is available, the prompt tells the LLM not to use it as a workaround for disabled tools such as install, delete/rename, or HTTP.
- **Markdown code-block rendering fix** — indented normal Markdown code blocks inside lists, such as SQL or bash instructions, now render as code blocks.
- **Compaction summary formatting fix** — LLM summary compaction blocks preserve basic Markdown formatting while keeping a distinct summary background; accidental tool-looking blocks inside summaries are inert, and full-summary outer `markdown`/`md` code fences are unwrapped so nested SQL/code blocks render correctly.
- **Create vs overwrite history fix** — `file:` blocks now remember whether the target existed before execution, so created files stay labeled **Create File** after full-auto execution and history reload.
- **Duplicate write-target confirmation fix** — the batch confirmation dialog now warns only about repeated same-tool writes to the same path, allowing normal `file:` then `patch:` repair sequences while still protecting against duplicate `file:` creates.
- **Response speed and TTFT stats** — the context-token popup now shows estimated tokens-per-second and TTFT (time to first token) for the last LLM response, plus volatile last-5-response averages for the currently opened chat.
- **LLM-summary compaction chain fix** — automatic summary compaction now fires after long full-auto agentic tool chains that jump past the hard context limit, and the summary request preserves the newest exchange instead of trimming the payload down to no conversation.
- **Light-theme rendering polish** — improved light-theme colors for compaction summaries, grouped inspection-tool blocks, warmup delete buttons, and the context-size button; also removed stylesheet warnings from those updated widgets.
- **Agentic confirmation stylesheet cleanup** — action confirmation rows no longer use Qt-incompatible alpha hex colors in QFrame styles, removing stylesheet parse warnings seen when create/patch rows were shown.
- **Chat collection cleanup** — Manage Chat Collections now includes **Delete selected** for multi-selected chats in the current collection.
- **Tool wording cleanup** — user-facing warnings and helper prompts now consistently say tools/tool calls instead of fences.

## What's new in 0.9.4

- **First-run provider onboarding** — fresh installs now show a clear "No provider configured" state with an Open Settings callout instead of old default model names.
- **Default prompt restoration fixes** — new empty chats created by `+ New Chat`, history deletion, Delete All, or restart now consistently restore the configured default system prompt.
- **Agentic prompt compaction** — the injected agentic instructions are much shorter while preserving key safety rules: only enabled fences are advertised, closing backticks must be on their own line, example paths are placeholders, and `run:python` cannot bypass disabled fences.
- **Small-model fence robustness** — safe bodyless one-line action fences are normalized, and indented regular Markdown code blocks such as SQL snippets inside numbered instructions render correctly.
- **Duplicate action target warning** — batch confirmation warns about repeated write targets and unchecks earlier duplicate `file:` creates by default.
- **Stopped-response agentic safety** — pressing Stop during a streaming LLM response now suppresses pending action confirmations, disables action buttons in partial agentic fences, saves the assistant message with `agentic_discarded`, and shows a warning note so incomplete file contents or commands cannot be executed after reload.
- **Batch `run:python` output forwarding fix** — console output from `run:python` now joins the same batch result payload as file/git/http/lint/sleep actions, so the LLM receives one complete agentic-output message for the whole batch.
- **Regenerate keeps agentic collapse controls** — clicking Regenerate no longer removes collapse headers from earlier assistant/action-output pairs.
- **Agentic system prompt clarity for small models** — the dynamic prompt now explicitly requires action fences to start on a new line, matches manual/full-autonomous wording to actual execution behavior, avoids conflicting inspection-fence instructions, and adds a conditional patch-recovery rule for falling back to full-file `file:` recreation after corrected `patch:` attempts fail.
- **Patch retry guidance tightened** — the prompt and patch failure hint now tell the LLM to use only one `patch:` action per file in a response, wait for the result, and send a corrected patch in the next response instead of repeating patches inline.
- **Agentic chat rendering setting** — Settings → Agentic → Action properties now has a **Chat rendering settings** option to keep newly rendered agentic responses expanded instead of collapsed.
- **Patch fuzzy-apply improvement** — failed hunks with stale LLM context can now recover by replacing a uniquely matched contiguous removed-line block; one-line removals still require nearby context to avoid ambiguous edits.
- **Patch preview gutter sizing fix** — long `@@` hunk headers no longer stretch the old/new line-number columns in patch previews.
- **Agentic collapse summary cleanup** — collapsed headers show the first two action types plus `+N more`, keep the full action list in a tooltip, and summarize action fences from the assistant response so failed attempts are included without being marked as successful.
- **Action-fence parser crash fix** — nested triple-backtick parsing is now limited to `file:` fences, so one-line fences such as `lint:`, `read:`, `ls:`, and `grep:` close correctly when text follows them during streaming.
- **Streaming render safety guard** — parser/render errors during streaming now stop generation and show an in-pane assistant error; oversized unclosed small-action bodies are aborted while large `file:` and `patch:` responses remain unrestricted.
- **Model context estimate refresh fix** — switching models from the top selector, including after reloading the model list, now immediately updates the estimated context usage button with the configured per-model token limit.
- **Provider-specific secure key storage refinements** — chat and FIM keys are per-provider, migrate from legacy single-key fields on Settings save, and show a themed key indicator for keyring/plaintext/unsaved state.
- **FIM provider key switching fix** — switching FIM providers restores that provider's saved key or clears the field when no key exists.
- **Settings and composer UI polish** — centered inference/token popups, clearer inference popup borders, aligned inference spinbox arrows, compact icon-only delete controls, and safer themed storage tooltips.
- **Agentic `run:python` manual capture fix** — manual-mode console execution returns captured output as soon as it is available instead of waiting for the timeout when the process already finished.

## What's new in 0.9.3

- **Image attachments in user messages** — attach images to any message via the **+ Image** composer button or by pasting a screenshot from the clipboard (Ctrl+V); supported formats: JPEG, PNG, WebP, GIF:
  - **+ Image button** — opens a file browser filtered to image formats; appears in the composer action row; greyed out with a tooltip for non-vision providers
  - **Clipboard paste** — pasting a screenshot or browser-copied image into the input field adds it as a chip without inserting text; ordinary text paste is unaffected; blocked for non-vision providers with a status bar notice
  - **Context bar chips** — each image appears as a violet `🖼 filename.jpg` chip with a **×** remove button; hovering shows a 200 × 200 px thumbnail popup (same popup appears on badges in chat history)
  - **Vision providers** — OpenAI, Groq, Mistral, Together AI, Fireworks AI, OpenRouter, Azure OpenAI, Ollama, LM Studio, vLLM, Custom; DeepSeek excluded (text-only models)
  - **API payload** — with images + vision provider: `content` becomes an OpenAI-compatible array of `{"type": "text"}` + `{"type": "image_url", "image_url": {"url": "data:mime;base64,…"}}` blocks; with text-only providers: `content` is still a plain string (images excluded from payload but preserved in JSON history)
  - **Scaling** — images are scaled to the configured maximum dimension (default **1 280 px**, longest side) before encoding; JPEG quality is configurable (default **85**); PNG is always lossless; GIF/WebP are re-encoded to JPEG; 5 MB base64 cap with a clear error message
  - **Settings → Context → Image attachments** — two new spinners: **Max image dimension** (256–4096 px, step 128, default 1 280 px) and **JPEG/WebP quality** (1–95, step 5, default 85); settings are read live at attachment time
  - **Chat history** — images stored as base64 in the chat JSON; violet badges with thumbnail hover on reload; switching to a non-vision provider preserves the data and re-includes it when switching back
  - **Token estimate** — each pending image adds ~1 500 tokens to the context-size indicator and breakdown popup
- **LM Studio / local-model "No user query found" fix** — two guards prevent Jinja2 chat-template errors with strict-alternation models (Qwen3, Llama 3):
  - **Consecutive same-role merge** — adjacent user or assistant messages in the API payload are merged into one before dispatch, preventing errors when Stop is pressed before any tokens arrive (which leaves no assistant message in history, causing the next send to produce back-to-back user entries)
  - **Leading-assistant guard** — after history trimming, any assistant messages that appear as the first non-system entry in the payload are dropped; this fixes the case where two consecutive user messages in `_messages` are removed together by the 2-at-a-time trimming loop, exposing the following assistant message at the front
- **Composer action-row refresh** — the prompt area is now one bordered composer with a bottom action row: **+ Image**, compact inference params, compact context estimate, **> Send**, and **[] Stop**; the old right-side vertical button stack is gone
- **Send / Stop feedback polish** — Send and Stop now include text icons; Send shows a small Braille spinner animation while a request or regeneration is running, and resets when the response completes, errors, or Stop is clicked
- **Inference params and context estimate controls** — moved into the composer action row; both controls are bordered, centered, theme-aware, and width-limited so long active parameter summaries are elided instead of increasing panel height
- **Regenerate click feedback** — clicking Regenerate immediately greys out the button and changes it to `⠋ Regenerate` before the retry rebuild starts, removing the stale-looking pause
- **LLM summary compaction warning fix** — Settings → Context now uses the live autonomous-mode selection from the open dialog, so switching Full → Manual/Semi and then viewing LLM summary compaction shows the warning before saving
- **Provider-specific API keys** — each chat provider and FIM provider keeps its own API key, and switching providers in Settings restores the key saved for that provider instead of reusing one global key
- **API-key storage indicator** — Connection and FIM API-key fields show a key icon with the plugin's themed hover popup explaining whether the current key is stored in secure system storage, plaintext fallback, or not saved yet
- **Secure API-key storage** — chat and FIM API keys are saved to the OS keyring via Python `keyring` when available; `state.json` keeps storage metadata and blank secret fields after successful keyring saves; if keyring fails, provider-scoped plaintext fallback remains available with a warning

## What's new in 0.9.2

- **Top bar moved into Spyder's pane toolbar row** — the model selector, ⟳ reload, + New Chat, ⚙ Settings, and chat history buttons are no longer a separate row inside the panel; they now appear in Spyder's standard toolbar band (same row as the ≡ options button), saving one full row of vertical space in the chat area
- **Project-root security filter for all file-operation fences** — path validation extended to `file`, `patch`, `read`, `ls`, and `grep` fences (previously only `delete`/`rename`/`copy` were guarded); write operations are always blocked outside the project root and require an open project; read operations have a configurable toggle (on by default) in Settings → 🤖 Agentic → Action properties → Filesystem operations permissions, with an ℹ popup explaining the full behaviour matrix

## What's new in 0.9.1

- **`sleep:` agentic fence** — new fence that pauses execution for a specified number of milliseconds without blocking the Spyder UI:
  - **Syntax** — `sleep:5000` (waits 5 seconds); value is in the fence tag; default 5 000 ms, maximum 60 000 ms (60 s)
  - **Non-blocking** — runs in a background `QThread` so Spyder stays fully responsive during the wait; the button shows `⏳ Waiting…` with a live countdown label
  - **Use case** — pace between `http:` requests, or wait for an external application to start before probing it; LLM receives `Slept N ms` as confirmation
  - **Settings** — `Sleep / wait (sleep:ms)` checkbox in Settings → 🤖 Agentic → Application calls; **on by default**
- **`http:` fence — configurable request properties** — a new collapsible **Action properties** panel in Settings → 🤖 Agentic (between Allow actions and Default base path) exposes five per-request knobs:
  - **Follow redirects** checkbox — disable to block all HTTP redirects (default: on)
  - **Max redirects** spinner (0–20) — cap the number of redirects followed; auto-disabled when follow redirects is off (default: 2)
  - **Timeout (s)** spinner (1–300 s) — per-request network timeout; was hard-coded at 30 s (default: **5 s**)
  - **Max response body (chars)** spinner (1 000–200 000) — cap on response body returned to the LLM; was hard-coded at 10 000 (default: **20 000**)
  - **Include link URLs in text mode** checkbox — when `:text` modifier is active, append `(https://…)` next to each hyperlink's anchor text so the LLM sees the actual URLs (default: off)
  - All settings are persisted in `state.json` under the `agentic` key and applied every time an `http:` fence executes
- **`http:` fence — `:text` mode href extraction** — `_strip_html()` now optionally collects `href` attributes from `<a>` tags and appends them as `(url)` after the link text; controlled by the new "Include link URLs in text mode" setting
- **LLM summary compaction threshold fix** — the 80 % compaction threshold now fires correctly instead of only at ≈ 100 %:
  - Root cause: `_maybe_trigger_compaction()` summed only message-history tokens, ignoring system-prompt + agentic-prompt overhead (10–20 % of context), so effective trigger was `history ≥ 80 %` of limit but the UI displayed `(history + system) / limit %`
  - Fix: compaction trigger now delegates to `_compute_context_stats()` — the same calculation the context-size indicator uses — so the threshold fires at exactly the percentage shown in the UI
- **LLM summary compaction — first compaction window fix** — for chats that accumulated history in cutoff mode and then switched to LLM summary mode (no prior compaction summary), the compaction request was built from the full history (potentially hundreds of thousands of tokens) which would exceed the provider's context limit; fixed by applying the same cutoff trimming to threshold (80 %) when no prior summary exists, matching what `_send()` actually sends to the API and leaving headroom for system-prompt and compaction-prompt overhead
- **`chat_widget.py` split into focused modules (Phase 1 refactor)** — the 7 217-line monolith is reorganised into maintainable, single-responsibility files with zero behaviour change:
  - `widgets/chat_panel.py` (~3 775 lines) — `AIChatPanel` (the main QWidget), extracted from `chat_widget.py`
  - `widgets/_panel/` sub-package — 10 helper modules covering distinct concerns:
    - `utils.py` — theme helpers, style factories, `DEFAULT_MODELS`, chat-ref encode/decode
    - `small_widgets.py` — `_FlowLayout`, `_WarmupButton`, `_PageBar`, click/event helpers, agentic tooltip widgets
    - `context_size.py` — `_CtxSizeButton`, `_CtxTooltipPopup`, read-group frame helpers
    - `command_input.py` — `_CommandInput`, `_CommandDropdown`
    - `chat_history.py` — `_ChatHistory` (message rendering engine), `_build_llm_content`
    - `workers.py` — `_ChatWorker`, `_GitStatusWorker`, `_GitActionWorker`
    - `git_status_bar.py` — `_GitStatusBar`
    - `infer_popups.py` — `_InferParamsPopup`, `_ModelPopup`
    - `history_popup.py` — `_ChatHistoryPopup`
    - `project_dialog.py` — `_ProjectContextDialog`
  - `widgets/chat_widget.py` reduced to ~90 lines — only `AIChatWidget` (Spyder wrapper) plus two re-exports for backward compatibility; all existing import paths in `plugin.py` unchanged
- **`file:` fence — bare no-lang nested code block fix** — `file:` fences that contain nested plain ` ``` ` blocks (no language tag, e.g. an env-vars section or a project tree inside a README) were silently truncated at the first bare fence; fixed with a one-line lookahead that distinguishes a nested opener from the outer fence's closing delimiter; resolves a recurring issue where large README.md writes were cut in half
- **Batch confirmation dialog — LLM context label** — when the LLM writes an explanation immediately before an action fence and the agentic group is collapsed in chat, the user previously had no way to see that explanation in the batch confirmation dialog; it is now shown as an italic grey `💬 …` label above the action preview header whenever a preceding paragraph is present; text truncated at 200 chars; hidden for actions with no context
- **Agentic system prompt — wait-for-acknowledgment guidance** — the closing paragraph of the injected agentic system prompt now tells the LLM to send manual-step instructions (restart an app, provide credentials, etc.) as a plain message first and wait for the user's acknowledgment before sending the action fence
- **`http:` fence block — orange colour scheme** — header colour changed from dark red (`#b03030`) to warm orange (`#e09030`) in both the chat view and the batch confirmation dialog; background tint updated to match (dark: `#1e1200`, light: `#fff8ee`); the fence no longer looks like an error state
- **Stop button active during agentic execution** — clicking Stop while fences are running now cancels the in-progress batch; `_agentic_cancelled` flag checked at each `_batch_execute._next()` iteration; badge reset, auto-send suppressed, Send re-enabled on cancel
- **Autonomous mode — behaviour matrix popup updated** — all 16 fence types now listed; previously missing: `lint:` (Inspection row), `http:` and `sleep:` (new dedicated rows), `copy:`/`delete_dir:`/`rename_dir:` in the Modifying row
- **`lint:` fence — manual mode inspection panel fix** — lint results in Manual mode were silently discarded; missing `"lint"` in the condition that activates the Send/Dismiss inspection panel; one-line fix
- **`patch:` fence — silent failure detection** — `execute_patch_file` now raises `ValueError` when no hunks matched instead of silently reporting `"✓ Patched"`; the error message names the specific failing `@@ … @@` headers and instructs the LLM to re-read the file; partial failures (some hunks applied) also raise with a `"⚠ Partial patch: N/M hunks applied"` warning; original trailing newline is now preserved after `splitlines()`/`join()`
- **Agentic action errors always forwarded to LLM** — in Manual mode, fence execution errors (patch mismatch, security check failure, etc.) were shown in the status label but not sent to the LLM; `_run_action` now returns `"[Error: …]"` instead of `None` on exception, and `_on_execute` auto-sends error results to the LLM in all modes so it can self-correct
- **Project context warning bar — visual and logic fixes** — the amber bar shown when the Spyder project differs from the chat's pinned project root received several fixes: single external border with no spurious inner label border; startup false positive eliminated (bar no longer appears when roots already match at load time); `_proj_root` no longer overwritten when the Spyder project changes while project context is enabled; `on_project_loaded()` now explicitly hides the bar when the new project matches the chat's pinned root
- **Project context badge — hover info popup** — hovering the `📁 Project` badge now shows a popup with the full project root path, the number of files currently in context (or "pending first send"), the count of files changed since last send, and up to 5 included folder names
- **Git bar buttons — hover tooltips** — the **⎇ PR desc** and **? Changes** buttons now show descriptive hover popups explaining what each button collects and sends to the LLM
- **Context estimation popup — message counts** — the "Estimated context tokens usage" hover popup now includes a **Messages count** section with per-role message counts (user, agentic outputs, LLM responses) and a total, all in the same table as the token stats so columns align; when LLM summary compaction is active a **Full history** section (blue accent colour) shows the total token count and message count across the entire chat history including compacted portions, making it easy to see how much has been summarised away
- **Context estimation popup — title renamed** — heading changed from *"Used context estimation in tokens"* to *"Estimated context tokens usage"*

## What's new in 0.9.0

- **`copy:` agentic fence** — copies a file or directory to a destination path written in the fence body; files use `shutil.copy2` (metadata preserved), directories use `shutil.copytree` (destination must not exist); both source and destination are validated against the project root security guard; enabled by default in Settings → 🤖 Agentic → File operations
- **`http:` agentic fence** — makes an HTTP request using stdlib `urllib` and returns the response to the LLM:
  - **Syntax** — `http:GET https://api.example.com/data`; optional request headers and body in the fence body; JSON bodies auto-get `Content-Type: application/json`
  - **`:text` modifier** — `http:GET:text https://example.com` strips HTML tags, scripts, and styles using `html.parser`, returning readable plain text; useful for page scraping without token-heavy markup
  - **Response** — status line, up to 15 response headers, body capped at 10 000 chars; HTTP 4xx/5xx errors are returned as results (not failures) so the LLM sees the actual error body
  - **Non-blocking** — runs in a background `QThread` so Spyder's UI stays responsive during the 30-second timeout
  - **Agentic output block** — in full/semi autonomous mode the result appears as a proper "⚙ Agentic output" block (same batch-chain mechanism as git), not a standalone user message
  - **Settings** — `HTTP requests` checkbox in Settings → 🤖 Agentic → Application calls; **off by default** (network access)
- **`lint:` agentic fence** — new fence that runs pylint on a file, directory, or glob pattern and returns the analysis to the LLM:
  - **Syntax** — `lint:file.py`, `lint:src/` (recursive, up to 50 files), `lint:src/**/*.py`; optional pylint args in the fence body
  - **Progress indicator** — button shows `⏳ Running…` while pylint runs; no confirmation required in "confirm only modifying actions" mode (read-only fence)
  - **Source line injection** — each pylint message includes a `"source"` field with the exact code line at the reported location
  - **Compact inline summary** — all errors + first 5 warnings shown with file/line/symbol/source; convention and refactor counts as totals; score header prepended
  - **Per-file JSON reports** — full pylint JSON written to `.ai_chat/lint/<rel_path>.json`; navigable with `read:` / `ls:` fences
  - **Spyder Code Analysis panel** — triggers Spyder's own analysis (`start_code_analysis`) so score and results always populate correctly; single-file runs update immediately, multi-file runs are queued with 3-second gaps
  - **Settings** — `Run linter` checkbox in the new **Application calls** group in Settings → 🤖 Agentic (on by default)
- **Settings → 🤖 Agentic — Allow actions split into two groups** — the flat checkbox grid is replaced by two labelled group boxes: **File operations** (create, patch, read, list, search, delete, rename) and **Application calls** (run in console, install, git, lint)
- **Compaction command — plugin-style display** — the LLM summary compaction request is now displayed as a collapsed purple **"📦 Compaction request"** frame (click to expand) instead of a plain blue user message bubble, making it visually distinct from real user messages; the `plugin_command` field is persisted in the message dict so the style is preserved on history reload

## What's new in 0.8.8

- **Collapsible agentic action pairs** — completed assistant+agentic-output pairs are automatically collapsed into the assistant title row; the label shows **"Agentic: Read file, Git command ▶"** (dark-yellow); clicking expands both blocks; consecutive runs of 2+ pairs are grouped under one label with repeat counts (e.g. **"Agentic: Git command ×2 ▶"**); applies to both history loads and live streaming; delete buttons hidden while collapsed
- **Agentic collapse — live grouping shake fixed** — when a second consecutive agentic pair arrived during streaming the chat briefly shook (content flashed then re-collapsed) because the grouping logic removed and re-inserted the summary label on every update; replaced with surgical in-place extension: the existing collapse group grows by appending new widgets to the same list the toggle closure already holds, and the label text is updated via `setText()`; zero visual artifact
- **Fence parser — infinite loop on spaces in fence tag fixed** — any fence tag containing a space (e.g. `` ```grep:SHOW TABLES ``, `` ```file:path/with spaces.py ``) caused `parse_blocks()` to loop forever, making Spyder completely unresponsive; fixed by widening the fence-opening regex capture group from `\S*` to `(\S[^\n]*?|)` so the full tag including embedded spaces is accepted; a secondary defensive guard was also added to ensure any `` ``` ``-starting line that still fails the regex advances the parser rather than spinning in place
- **Blockquote rendering fix** — the `>` markdown blockquote no longer shows a doubled vertical accent line; fixed by replacing the `QFrame border-left` approach with a plain `QWidget` + a separate 3 px coloured child widget; nested fenced code blocks inside blockquotes now render as full syntax-highlighted code block widgets
- **Plugin logo in Settings dialog** — the plugin logo is now displayed at the bottom of the tab-bar column in the Settings dialog; embedded in the package under `spyder_ai_chat/resources/` and available after `pip install` without extra files; position is recomputed on resize
- **Git bar disabled by default** — the git status bar is now off by default for new installs; users enable it once they have confirmed git is on their system
- **Git availability check on enable** — ticking "Show Git status bar" in Settings → ⎇ Git bar immediately validates git via `shutil.which("git")` (no subprocess, no blocking, no console flash on Windows); a green **"✓ git found in PATH"** label appears if git is found; if not, a red warning is shown and the checkbox is automatically unchecked; the check also runs at dialog open time when the setting is already enabled

## What's new in 0.8.7

- **Settings — light theme support** — resolved multiple elements that showed a black box or were invisible in Spyder's light UI theme: Context tab warning boxes, Agentic tab full-autonomy warning, Commands tab built-in commands group, Connection tab title label, autonomous mode behaviour matrix popup, and the agentic system prompt preview textarea; all colours now adapt via a `_is_dialog_dark()` helper
- **Table rendering — height fix** — LLM table responses no longer stretch to the full chat window height when no vertical scrollbar is visible; root cause was `showEvent` firing before the viewport had a valid width, producing an enormous document height from `setTextWidth(0)`; fixed with a `w ≤ 0` guard and a `Preferred` vertical size policy
- **Manual mode — inspection output panel** — executing a `read:`/`ls:`/`grep:` fence via the batch dialog in Manual mode now shows the per-block output panel with **"📤 Send to LLM"** / **"✕ Dismiss"** buttons; previously the result was silently discarded
- **Manual mode — git output panel** — confirming a `run:git` fence in Manual mode now shows the git output panel with **"📤 Send to LLM"** / **"✕ Dismiss"** buttons; previously git output was auto-sent without user control in all modes
- **Manual mode — modifying action results auto-sent** — `file:`, `patch:`, `delete:`, `rename:`, and `install:` results confirmed in Manual mode are now forwarded to the LLM automatically; only `read:`/`ls:`/`grep:` and `run:git` results stay under user control via the output panel
- **"📤 Send to LLM" on git panel — sends immediately** — the button now calls `auto_send_fn` (adds tag + fires `_send()`); previously it only added an attachment tag without triggering a send
- **Autonomous mode matrix — git row** — git has its own row: Manual = "panel → user decides"; Semi/Full = "auto-sent ✓"; previously incorrectly grouped under Modifying with "auto-sent ✓" for Manual mode
- **Git output panel — text always visible** — changed from `NoWrap` to `WidgetWidth` wrap mode and added a 52 px minimum height floor; previously a long output line (e.g. LF→CRLF warning) caused the horizontal scrollbar to consume the full widget height, hiding all text
- **Editor keyboard shortcuts** — **Ctrl+Shift+A** adds the current file to the AI Chat context; **Ctrl+Shift+Q** adds the current text selection; both are scoped to the editor so they don't conflict with the rest of Spyder; shortcut hints also appear in the right-click AI Chat submenu

## What's new in 0.8.6

- **Dynamic agentic system prompt** — the system prompt injected into each chat is now assembled at send time from only the fence types enabled in Settings → 🤖 Agentic; the LLM is never told about fences it cannot use; a user who enables only `patch:` and `read:` receives a prompt describing only those two fences
- **Mode-aware prompt wording** — the injected prompt adapts to the selected autonomous mode: the preamble correctly describes confirmation behaviour, git output forwarding, delete/rename confirmation vs. silent execution, and the inspection-fence discipline paragraph, all based on the actual mode in use
- **Missing delete / rename fences in system prompt — fixed** — `delete:`, `delete_dir:`, `rename:`, and `rename_dir:` fences were implemented but never mentioned in the agentic system prompt so the LLM did not know they existed; they now appear as conditional sections whenever the respective fence is enabled
- **Settings: read-only agentic prompt preview** — the editable textarea in Settings → 🤖 Agentic is replaced by a collapsible read-only preview that shows the exact prompt that will be injected; the preview updates live as fence checkboxes or the autonomous mode radio button are toggled
- **Agentic action widget — no blank body for delete / rename fences** — `delete:`, `delete_dir:`, `rename:`, and `rename_dir:` action blocks no longer show an empty text area below the header; the target is already fully described in the header row
- **Chat history paging** — chats longer than 120 messages are now split into pages; a centered `<<` / `<` / numbered / `>` / `>>` navigation bar appears below the chat area; the current page button is highlighted in blue; opening a long saved chat lands on the last (newest) page with scroll anchored to the bottom; navigating to an earlier page scrolls to the top; page navigation uses the same batched-load pipeline with a "Page N loading… N%" progress overlay; the page bar stays hidden for chats with 120 or fewer messages (no behavioural change)
- **Incremental chat history loading** — history now loads in batches of 12 messages with an event-loop yield between each batch, keeping the application interactive (scrollable, closable, resizable) while a large chat loads; a "Loading chat… N%" progress overlay tracks progress; before this change the UI froze completely for the entire load duration
- **Chat scroll height — long-chat sizeHint fix** — blank space that appeared below the last message after loading a chat with 100+ messages is now gone; paging caps rendered widgets to 120 per page, keeping Qt's internal sizeHint cache reliable
- **Patch diff line numbers** — `patch:` action blocks in the chat, the single-action confirm dialog, and the batch confirm dialog now show line numbers on the left border of the diff view; two gutter columns display old-file (left) and new-file (right) line numbers, parsed from `@@` hunk headers to show real file positions; `@@` hunk rows now display the full `@@ -N,M +P,Q @@` header text instead of the former `──────────────` placeholder; gutter width auto-sizes to the widest line number in the diff
- **Patch application correctness** — `_apply_unified_diff` now verifies that file content at the computed position matches the expected hunk context before applying; stale LLM-generated line numbers no longer silently corrupt unrelated lines; falls back to content-based fuzzy search when verification fails and recalibrates the running line-number offset for all subsequent hunks
- **Python indentation preservation in patches** — when the fuzzy search path is used, context lines (unchanged lines surrounding the edit) are taken from the FILE's original content verbatim rather than from the diff; prevents the LLM's slightly-wrong context indentation from overwriting correct Python indentation in the patched file — Python code is particularly sensitive since indentation is semantic
- **Chat scroll height — bug fix** — fixed ~950 px of blank space at the bottom of the chat area appearing after a streaming response finished; root cause was `QScrollArea` processing `updateGeometry()` asynchronously; fixed by synchronously resizing the content widget immediately after removing the streaming label

## What's new in 0.8.5

- **Context History Compaction** — new feature in Settings → 📁 Context to limit how much chat history is forwarded to the LLM without deleting messages locally: **Cut-off** mode silently drops the oldest pairs when the estimated token count exceeds a configurable threshold; **LLM summary** mode (Full autonomous only) auto-sends a summary request and saves the result as a collapsible 📦 compaction block — subsequent sends include only messages after that block
- **Built-in commands** — new plugin-defined command category (not user-editable) shown with ⚡ prefix and blue-purple colour in a separate "── Built-in ──" section of the slash-command picker; displayed read-only in the Commands settings tab; built-in names are protected from user collision
- **`/compact` built-in command** — manually triggers LLM summary compaction; visible in the dropdown only when all four conditions are met (Compaction enabled + LLM Summary strategy + Full autonomous mode + Project Context off); ignores the token threshold but re-validates all other guards; fires silently without adding a user message to the chat
- **Context size estimate in params bar** — always-visible `~X.Xk / Yk (Z%)` button on the right side of the inference params bar; colour-coded: gray (normal), amber (near threshold), red (over limit); hover shows a dark floating popup with a progress bar and per-category token breakdown (history, system prompt, context files, compaction buffer, total, free space); refreshes on every send, LLM response, and chat switch
- **Inspection fence output panel** — executing a `read:`/`ls:`/`grep:` fence with auto-send OFF now shows a scrollable output panel with **"📤 Send to LLM"** / **"✕ Dismiss"** buttons instead of silently discarding the result
- **Confirm dialog for inspection fences** — proper icon, label, and detail block (file / directory / pattern + scope) for `read:`/`ls:`/`grep:` confirm dialogs; previously showed "? read" with an empty body
- **Project root in system prompt** — the active Spyder project root is automatically injected into the system prompt so the LLM uses it as the base directory for all file operations even when Project Context is disabled
- **Agentic output blue border** — the collapsed "⚙ Agentic output" frame now has a straight blue left border matching user message bubbles
- **Attachment content tooltip** — hover any locked attachment badge in a sent message to preview the first 25 lines of its content
- **Regenerate bug fix** — fixed two root causes of agentic action output being lost when regenerating after a service error: fence re-registration during history rebuild, and `read:`/`ls:`/`grep:` results using the wrong `source` type
- **Context size estimate refresh on chat switch — bug fix** — the token counter now correctly recalculates after loading a saved chat; previously it always showed the empty-history value until the next LLM call
- **Settings: ⎇ Git bar tab** — git status bar settings moved to a dedicated tab; Settings minimum height raised to 770 px
- **Agentic warning colour** — the "Full autonomous mode" warning box in Settings → 🤖 Agentic now uses amber styling (matching the Project Context warning) instead of red
- **Compaction table UX** — Provider column is now a dropdown of all known providers; Model column is an editable combo pre-populated with the live model list when provider matches the active one; "− Remove row" button width fixed
- **`/clear` built-in command** — clears all messages while keeping every setting (model, system prompt, inference parameters, project context, collection); always saves to history before wiping regardless of the autosave setting; always visible in the slash-command picker; replaces the former toolbar 🗑 button
- **Read fence batch grouping** — 2+ consecutive `read:`/`ls:`/`grep:` blocks from the same response are collapsed into one collapsible summary block (▶/▼ toggle, path list, ✓ Done badge in the header); applies to both live responses and history reloads
- **Read fence auto-batching in off mode** — in Off autonomous mode all `read:`/`ls:`/`grep:` fences are now auto-batched into a single execution, matching Semi/Full mode behaviour
- **Agentic output hover popup** — "⚙ Agentic output" label shows a custom dark-blue scrollable floating popup (max 420 px, 200 ms grace) instead of a plain system tooltip
- **Context size refresh on delete** — the token counter updates immediately after deleting any exchange
- **`/clear` history save fix** — clear always saves to history unconditionally; previously the save was gated on the `save_on_new` setting, which could leave a stale autosaved file reloadable from the history popup
- **"Off" autonomous mode renamed to "Manual"** — now shows a batch confirmation dialog for ALL action types (reads and modifying alike), same as Semi; the key difference from Semi is that results are never auto-sent to the LLM; internal value `"off"` unchanged for backward compatibility
- **Autonomous mode behaviour matrix popup** — ℹ button next to the "Autonomous Mode:" label opens a colour-coded table showing confirmation style and auto-send behaviour across all four mode variants
- **Removed "Auto-send individual Execute results" checkbox** — redundant option removed (Manual + auto-send = Semi; no longer a meaningful distinction)
- **Agentic mode and compaction enabled by default** — new installs start with agentic mode on and context history compaction on (Cut-off strategy)
- **Stop-before-first-token Regenerate fix** — Regenerate now works correctly when a response was stopped before any tokens arrived
- **Console output shown as Agentic output block** — auto-sent console execution results now render as the collapsed blue ⚙ Agentic output frame instead of a plain "You:" user bubble
- **Batch confirm dialog patch preview fix** — fixed `TypeError: _diff_to_html() got an unexpected keyword argument 'context_lines'` when opening the batch dialog with a patch action
- **Settings version label fix** — version string in the settings dialog bottom-left was clipped to "Ch"; now displays the full version correctly

## What's new in 0.8.4

- **Full autonomous mode** — new third execution mode (Off / Semi / Full) in *Settings → 🤖 Agentic*; in Full mode the LLM's requested actions execute immediately without any confirmation dialog; sub-option "Confirm only modifying actions" (default ON) still shows the batch dialog for file/patch/run/install/git while silently auto-executing read-only fences
- **On-demand file inspection** — three inspection tools let the LLM explore the project without requiring full project context upload: `read:path/to/file.py` (full, line-range, or `:lines` numbered read), `ls:some/dir/`, and `grep:path/or/dir` with the Python regex in the block body; results are auto-sent back in autonomous modes
- **Inspection error forwarding** — `read:`/`ls:`/`grep:` errors are now sent to the LLM instead of being silently swallowed, preventing hallucination when a file is not found
- **Git bar improvements** — untracked (new) files now counted in the diff stats; refresh interval configurable in Settings (default 10 s, range 5–300 s)
- **Batch git output fix** — all git commands in a batch now reach the LLM; previously only the first command's output was forwarded due to an empty-target bug and duplicate-tag silencing
- **Settings UI** — tab bar moved to left side with horizontal labels and compact height; Context tab split into two group boxes; version label in bottom-left corner

## What's new in 0.8.3

- **Batch confirmation dialog** — all action blocks from a single LLM response are grouped into one scrollable dialog; each row shows a friendly verb + target with an include/exclude checkbox; **Run selected** executes only the checked items in order; **Cancel** leaves all Execute buttons available as before
- **Auto-show confirmation** (semi-autonomous mode) — when enabled the batch dialog appears automatically after each LLM response containing action blocks, without requiring the user to click individual Execute buttons; enable via *Settings → 🤖 Agentic → Semi-autonomous mode*
- **Auto-send execution results** — after actions complete, results are injected as context tags and a follow-up is automatically sent to the LLM so it can confirm success or react to errors; always on when auto-show confirmation is on; also available independently for manual Execute clicks
- **Collapsible agentic output messages** — user messages generated by the plugin (git bar prompts, auto-sent results) are shown as a collapsed **⚙ Agentic output** frame in the chat; click to expand; stored in JSON as `"agentic_response": true`
- **Sequential git execution** — multiple `run:git` commands in a batch (e.g. `git add -A` then `git commit`) run in order, each waiting for the previous to finish
- **Auto-dismiss git output panel** — when auto-send is enabled the inline output panel after a git command is suppressed and ✓ Done shown instead; the output travels to the LLM automatically; panel still appears in manual mode
- **Settings enforcement** — enabling "Auto-show batch confirmation" forces "Auto-send execution results" on and grays it out; the two can be toggled freely only when auto-show confirmation is off
- **No console popups on Windows** — git subprocess calls use `CREATE_NO_WINDOW` so no terminal window flickers during git operations

## What's new in 0.8.2

- **Git Status Bar** — compact bar below the context tag bar showing current branch (`⎇ branch`), diff stats (`+N −N in N files`), and three action buttons: **Commit** (suggests commit message + `run:git commit` fence), **PR desc** (generates PR description from current diff), **Changes** (summarises uncommitted changes); bar hides automatically when no git repo is active
- **Auto-refresh on branch/index changes** — bar updates non-blocking via QThread when `.git/HEAD` or `.git/index` changes; branch switches trigger a context update so the LLM always knows the current branch
- **Git info in project context** — when the git bar is enabled, `Branch:` and `Uncommitted:` are injected into the project context header; configurable via *"Show git status bar"* in Settings → 📁 Context

## What's new in 0.8.1

- **`run:git` agentic fence** — the LLM can run git commands via `` ```run:git `` fences; orange action block; non-blocking QThread execution with ⏳ spinner; inline output panel with **📎 Add to chat** / **✕ Dismiss**; git availability checked with a friendly error if git is not on PATH
- **Diff syntax highlighting** — `patch:` blocks render with coloured unified-diff highlighting in the chat and confirm dialog; internal patch text is always preserved unchanged
- **Robust patch application** — fuzzy line-search fallback when LLM omits `@@` line numbers, preventing silent no-op patches
- **Agentic system prompt** — hash-based auto-upgrade removed; replaced with an amber upgrade notice in Settings; **Reset to default** button always visible above the collapsible prompt textarea; built-in prompt now enforces `patch:` for edits, `file:` only for new files
- **Full absolute paths in file attachments** — manually attached files and project context blocks store and display full absolute paths so the LLM can use them directly in fences
- **Wrapping context bar** — tag bar wraps to the next row instead of expanding the plugin window; project context toggle stays in a fixed right column
- **New-chat project context** — starting a new chat always disables project context (configurable in Settings → 📁 Context); enabling project context clears any manually attached files
- **Live project root for agentic actions** — base directory resolved lazily at click time using the live Spyder project root, even if project context is off; home directory is last-resort only
- **`.git` metadata files in project context** — `HEAD`, `config`, `COMMIT_EDITMSG` etc. are now correctly collected when project context is active
- **Version shown in Settings** — plugin version displayed in Settings → Connection tab

## What's new in 0.8.0

- **Named chat collections** — organise saved chats into user-defined collections (folders inside `~/.spyder_ai_chat/chats/`); fully backward-compatible with existing chat files in the Default collection
- **Collection selector in history popup** — "Collection:" dropdown lets you browse one collection at a time or switch to **⊕ All Collections** to search across all collections simultaneously
- **Collection Manager dialog** — ⚙ gear button opens a side-by-side manager: create, rename, delete collections; move chats between them individually or in bulk; delete dialog lets you choose to delete chats or move them to another collection first
- **Right-click "Move to →"** — context menu on any chat row lets you move it to another collection; moving the currently open chat updates the panel's active reference live
- **Collection badge in All-Collections view** — chat rows show a `[CollectionName]` badge so the source is always visible when browsing all collections
- **Auto-complete settings fix** — "Context before cursor" field no longer resets to 100 when clicking OK (Qt intermediate-validation bug with minimum=100 was the root cause; lowered to 1)
- **Button icon fixes** — gear icon in the toolbar now renders in monochrome on Windows instead of coloured emoji

## What's new in 0.7.1

- **Project Explorer context menu** — right-click file(s) in the Project Explorer to add them to the AI Chat context; multi-select supported; disabled automatically when project context is ON
- **Editor context menu fix (Spyder 6.1.4)** — *AI Chat* submenu restored after Spyder 6.1.4 changed the editor menu API; backwards-compatible with Spyder ≤ 6.1.3
- **Agentic fixes** — overwrite header updates live after file creation; patch reloads the open editor buffer; startup chat action blocks (run/overwrite detection) work correctly on first click without requiring a chat switch
- **Agentic: Apply patch colour** — changed from purple to lime green for better contrast
- **Settings: Agentic tab** — compact 2-column layout; prompt template collapsible to save vertical space

## What's new in 0.7.0

- **Agentic mode** — enable in Settings → 🤖 Agentic; the LLM can take direct actions via special code fences, each confirmed with a single click:
  - `` ```file:path `` — create or overwrite a file; new files open automatically in the Spyder editor
  - `` ```run:python `` — send Python code to the active IPython console
  - `` ```install:pip `` — install packages via the console
  - `` ```patch:path `` — apply a unified diff patch to an existing file
- **Agentic settings tab**: master switch, per-action allow flags, default base path, customisable prompt template with Reset button
- **Overwrite detection** — action button shows blue "✓ Create file" or amber "⚠ Overwrite file" depending on whether the target exists
- **Done badge** — executed actions show **✓ Done**; hover reveals **↺ Re-run**; execution state persisted across chat reloads
- **Regenerate fix** — 🔄 Regenerate now correctly injects the agentic system prompt
- **Streaming flash fix** — eliminated the brief floating widget appearing during action block rendering

## What's new in 0.6.0

- **Project-wide context** — enable the **📁 Proj. Context** toggle in the chat bar to attach your entire Spyder project to the conversation:
  - Folder-selection dialog with live token estimate lets you choose which top-level folders to include
  - First message sends all selected files in full; subsequent messages send only changed files as a delta (token-efficient)
  - Open files with unsaved edits use the live editor buffer — the LLM always sees what you are currently working on
  - New unsaved files (not yet on disk) are auto-included from the editor buffer
  - File watcher monitors the project directory; the badge shows a changed-file count before each send
  - Re-opening a saved chat restores project context; files are silently re-expanded if hashes match, otherwise a stale badge is shown
  - Whole-file attachments are blocked while project context is ON (editor selections and console attachments remain available)
  - New **📁 Context** tab in Settings: max file size, max file count, extra exclusion glob patterns (on top of built-in exclusions and `.gitignore`)

## What's new in 0.5.1

- **Chat history search** — live search field in the history popup filters by title preview and full message content simultaneously as you type
- **Table `<br>` tag fix** — line breaks inside table cells are now rendered correctly instead of appearing as literal `<br>` text
- **Table scroll fix** — mouse wheel over a table now scrolls the chat window instead of scrolling the table widget independently

## What's new in 0.5.0

- **IPython console context menu** — right-click anywhere in the IPython console to access the **AI Chat** submenu: *Add console content to context* attaches the full console output (ANSI codes stripped); *Add selection to context* attaches the highlighted text
- **Console attachment colour distinction** — console context tags use a teal-green badge colour to distinguish them from the blue editor/file tags at a glance
- **Think block show/hide scroll fix** — toggling the thinking block no longer causes the chat pane to jump to the bottom; scroll position is preserved
- **Live code block rendering** — the code block widget appears at the first ` ``` ` line and grows in real time; finalised when the closing fence arrives
- **Code block height fixes** — accurate height from `fontMetrics().lineSpacing()`; horizontal scrollbar space reserved; single-line blocks no longer clipped

## What's new in 0.4.1

- **Default system prompt for new chat** — pick a saved prompt as the default in Settings → System Prompts; it is applied automatically every time a new chat is started
- **Think block streaming fix** — `<think>` blocks render as the collapsible Thinking widget immediately after `</think>` arrives, not only at stream end
- **Nested list streaming fix** — nested list items now have correct line breaks during progressive rendering
- **Code-only message fix** — a response that is a single code block no longer produces an empty code widget; it renders correctly when the closing fence arrives
- **`build_code_block` crash fix** — `UnboundLocalError` when loading saved chats with code blocks is resolved

## What's new in 0.4.0

- **Processing spinner** — braille spinner shown while waiting for the first LLM token; disappears the moment streaming starts
- **Incremental markdown rendering** — response formatted in real time as it streams; completed blocks become rendered widgets instantly; only the trailing incomplete block is shown as plain text
- **HTTP error display** — API errors shown in a dark-red styled box with an "⚠ Response error" header; no empty assistant block created on error
- **Delete on error blocks** — delete button on error response blocks now works correctly
- **Regenerate on error** — Regenerate button now appears on error response blocks for an immediate retry

## What's new in 0.3.2

- **Plugin entry-point renamed** to `ai_chat_plugin` (`spyder.plugins`) and `ai_fim_provider` (`spyder.completions`) for clarity
- **`NAME` / `CONF_SECTION`** in `AIChatPlugin` updated to `"ai_chat_plugin"`; `COMPLETION_PROVIDER_NAME` / `CONF_SECTION` in `AiFimProvider` updated to `"ai_fim_provider"` / `"ai_chat_plugin"`

## What's new in 0.3.1

- **Settings → ⚡ Auto-complete tab** redesigned as a step-by-step wizard: enable → set provider/URL → **Load Models** → pick model + backend; backend probe validates response body to avoid false-positive matches
- **Model list and backend list persist** after save and reopen — no need to re-run Load Models every time
- **Test Connection button** in the Connection tab — probes `GET /models` with an OpenAI-SDK-style `User-Agent` (fixes Cloudflare 403 / error 1010 on Groq and similar providers)
- **System Prompts tab**: Edit button removed; selecting a prompt immediately opens it for editing; Save activates only when content changes
- **Commands tab**: Edit button removed; selecting a command immediately opens it for editing; Save activates only when content changes
- **Settings window** wider (+10%); tabs stretch edge-to-edge; "🖊 Editor" tab renamed to "🖊 Dialogs"
- **FIM cursor-offset bug fixed**: completions are now correct for files with `\r\n` line endings

## What's new in 0.3.0

- **AI auto-complete (FIM)** — fill-in-middle ghost-text completions in the code editor
- **Tab** to accept, **Escape** to dismiss, **Alt+\\** for manual trigger
- Supports Ollama, LM Studio, vLLM, DeepSeek, Codestral/Mistral, OpenRouter, custom endpoints
- Trigger modes: auto (debounce), after new line, manual

---

## Features

| | Feature | Details |
|---|---|---|
| 🗨️ | Chat panel | Scrollable conversation with colour-coded user / assistant messages |
| ⚡ | Streaming | Token-by-token streaming with live incremental markdown rendering — blocks are formatted as they arrive |
| 🔁 | Model selector | Dropdown populated live from the API — switch models instantly |
| 🔧 | 12 providers | OpenAI, Groq, Mistral, DeepSeek, Together, Fireworks, OpenRouter, Azure, Ollama, LM Studio, vLLM, Custom |
| ⚙ | Inference params | Per-chat hyperparameters popup — provider-aware, resets on New Chat |
| 🔑 | Optional API key | Leave blank for local models that need no authentication |
| 🧠 | System prompt | Custom prompt field, or select from a saved prompts library |
| 💬 | Saved system prompts | Define reusable prompts; manage via Settings → System Prompts tab |
| ⏹ | Stop | Cancel a streaming reply at any time |
| 🗑 | New Chat | Start a fresh conversation; current one saved automatically |
| 📋 | Chat history | Browse, load, and delete saved chats; live search by title or content; active chat highlighted in green |
| 📄 | Chat history paging | Chats longer than 120 messages split into pages; centered `<<` / `<` / numbered / `>` / `>>` bar below the chat area; current page highlighted; hidden for shorter chats |
| 🗂 | Chat collections | Organise chats into named collections; ⚙ manager to create / rename / delete; right-click to move chats; search within one or across all |
| 📎 | File context | Attach whole files or selected text from the editor, or IPython console output — colour-coded tags (blue = editor, teal = console) |
| 🖊️ | Markdown rendering | Headings, bold, italic, tables, code blocks, blockquotes, links, strikethrough |
| 🗂 | Nested lists | Arbitrarily deep bullet & numbered lists, mixed types at any level |
| 🧠 | Thinking blocks | `<think>` tags rendered as a collapsible scrollable box (DeepSeek-R1, QwQ, …) |
| 📋 | Copy to editor | Insert any code block or full response at the cursor in the active file |
| 🗑 | Delete exchange | Remove any exchange with a 3-second undo window |
| 🔄 | Regenerate | Re-run the last assistant response with one click; button greys out immediately while retry is prepared |
| ↔ | Horizontal scroll | Wide code blocks scroll horizontally instead of clipping |
| ⚙ | Settings | Tabbed dialog: provider + Test Connection, dialog font sizes, history, system prompts, commands, auto-complete |
| / | Commands | Slash-command aliases with picker dropdown; expand to full prompts before sending |
| ⚡ | Built-in commands | Plugin-defined commands (⚡ prefix, blue-purple) in a separate dropdown section — not user-editable; `/compact` (manual LLM summary compaction) and `/clear` (wipe conversation, keep all settings) |
| ▶ | Composer controls | Bottom composer row with **+ Image**, inference params, context estimate, **> Send**, and **[] Stop**; Send animates while the LLM is generating |
| 📊 | Context size estimate | Always-visible `~X.Xk / Yk (Z%)` token counter in the composer action row — colour-coded; hover for per-category breakdown popup |
| ✍️ | AI auto-complete | FIM ghost-text completions in the editor — Tab to accept, Escape to dismiss |
| 🤖 | Agentic mode | LLM uses configured tools for file operations, project inspection, console code, git, lint, HTTP, and waits — actions execute through the Semi/Full response-processing flow |
| 🤖 | Autonomous modes | **Semi** — batch dialog + all results auto-sent · **Full** — silent or confirm-modifying execution, results always auto-sent; ℹ behaviour-matrix popup in settings |

---

## Requirements

- Python ≥ 3.9
- Spyder ≥ 6.1
- No additional Python packages — HTTP via `urllib` (stdlib), UI via Qt (bundled with Spyder)

---

## Installation

### From PyPI

```bash
pip install spyder-ai-chat
```

### From source / development build

Clone the source code from the repository:

```
https://sourceforge.net/p/spyder-ai-chat-plugin/code/ci/master/tree/
```

Then install in editable mode:

```bash
cd spyder_ai_chat
pip install -e .
```

> **Important:** install into the **same Python environment that Spyder uses**.

After installation, **restart Spyder**. The panel appears automatically.
If not visible: **Window → Panes → AI Chat**.

---

## Quick start

1. Open **Settings** (⚙ button in the panel toolbar).
2. On the **Connection** tab, select your **Provider** from the dropdown.
3. Fill in the API URL and key as needed (pre-filled for known providers).
4. Click **Test Connection** to verify credentials, then click **OK**.
5. Click **⟳** to load the model list and pick a model.
6. Type a message and press **Ctrl+Enter** or click **Send**.

**To enable AI auto-complete in the editor:**

1. Open **Settings → ⚡ Auto-complete**.
2. Check **Enable AI auto-completion in the editor**.
3. Select a provider and API URL, then click **Load Models**.
4. Choose a model and backend type, adjust parameters if needed, and click **OK**.

---

## License

MIT — see the `LICENSE` file included in the package.
