From ae747a44702fedd2aba68441c695cf20e0c30704 Mon Sep 17 00:00:00 2001 From: Florian Egger Date: Wed, 20 May 2026 23:25:07 +0200 Subject: [PATCH] Update README with new features and fix streaming state cleanup Expand documentation for agent modes, workflows, auto-organizer, structured memory, tool telemetry, and enhanced context sources. Set `isThinking` to false when finalizing assistant messages to ensure UI state resets correctly. --- README.md | 140 +++++++++++++++++++++++++++++++++++++++++++---- src/chat-view.ts | 15 +++++ 2 files changed, 145 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 4aacec2..132a217 100755 --- a/README.md +++ b/README.md @@ -4,13 +4,18 @@ A plugin that integrates [Ollama](https://ollama.ai) with Obsidian, allowing you ## Features -- Chat with Ollama models directly in Obsidian -- Vault context search — the assistant can reference your notes +- **Chat with Ollama models** directly in Obsidian with streaming responses +- **Vault context search** — the assistant can reference your notes via semantic (RAG) or keyword search +- **Agent Modes** — selectable chat modes (Ask, Edit, Organize, Research, Workflow) that change available tools, system prompts, and preview behaviour +- **Tool integration** — create, read, search, append, edit, rename, move, delete notes, and insert wiki-links +- **Structured Memory** — persist conversation summaries, user preferences, and learned facts across sessions +- **Tool Telemetry** — track which tools were called, which notes were searched, and LLM token usage - **Semantic/RAG vault indexing** — automatically index your vault into a vector database for intelligent retrieval -- Tool integration — create files based on chat responses -- Streaming responses -- Semantic response cache — repeated or similar queries are answered instantly without hitting the model (requires ChromaDB) -- Customisable model, URL, and cache settings +- **Semantic response cache** — repeated or similar queries are answered instantly without hitting the model +- **Workflow Engine** — execute multi-step AI workflows via `/workflow` commands +- **Auto-Organizer** — AI-powered auto-tagging and auto-linking with dry-run preview and folder scoping +- **Obsidian MetadataCache integration** — frontmatter, tags, links, and headings are read via Obsidian's built-in cache instead of raw regex parsing +- Customisable model, URL, cache, and memory settings ## Prerequisites @@ -106,6 +111,7 @@ Open **Settings → Ollama Settings** to configure the plugin. |---------|---------|-------------| | Ollama URL | `http://localhost:11434` | Base URL of your Ollama instance | | Model | `llama3` | Model used for chat responses | +| **Default Agent Mode** | `Ask` | Default chat mode (Ask, Edit, Organize, Research, Workflow) | | Vault Search Limit | `5` | Maximum number of vault entries to include in context | | Max Context Length | `8000` | Maximum characters of vault content sent to the AI per message | | Max Message History | `50` | Maximum number of messages kept in conversation history | @@ -118,8 +124,24 @@ Open **Settings → Ollama Settings** to configure the plugin. | Enable Semantic Cache | Off | Cache responses for fast repeated queries | | ChromaDB URL | `http://localhost:8000` | URL of your running ChromaDB instance | | Cache Embedding Model | `nomic-embed-text` | Ollama model used to generate cache embeddings | -| Cache Similarity Threshold | `0.85` | Minimum cosine similarity (0–1) for a cache hit — higher values require closer matches | -| Clear Semantic Cache | — | Button to wipe all cached responses from ChromaDB | +| Cache Similarity Threshold | `0.85` | Minimum cosine similarity (0–1) for a cache hit | +| Clear Semantic Cache | — | Button to wipe all cached responses | +| **Enable Auto-Tagging** | Off | Automatically suggest and apply tags to untagged notes | +| Max Tags Per Note | `5` | Maximum tags to generate per note | +| Normalize Tags | On | Normalize generated tags against existing vault vocabulary | +| Target Folder (Auto-Tag) | — | Restrict auto-tagging to a specific folder | +| **Enable Auto-Linking** | Off | Add "Related Notes" sections based on semantic similarity | +| Max Links Per Note | `3` | Maximum related note links to insert | +| Target Folder (Auto-Link) | — | Restrict auto-linking to a specific folder | +| Dry Run Mode (Auto-Link) | Off | Preview proposed links without applying them | +| **Enable Structured Memory** | On | Inject remembered context from past sessions into prompts | +| Max Conversation Summaries | `10` | Maximum past conversation summaries to retain | +| Max User Preferences | `20` | Maximum user preferences to retain | +| Max Learned Facts | `50` | Maximum learned facts to retain | +| Clear Structured Memory | — | Button to delete all stored memory | +| **Enable Tool Telemetry** | On | Record tool calls, searches, and LLM token counts | +| Max Telemetry Entries | `100` | Maximum telemetry events to retain | +| Clear Tool Telemetry | — | Button to delete all recorded telemetry | ## Usage @@ -129,6 +151,52 @@ Open **Settings → Ollama Settings** to configure the plugin. 4. Press **Shift+Enter** to insert a line break 5. Click **New Chat** to start a fresh conversation +### Agent Modes + +The chat view includes a mode selector dropdown. Each mode changes the assistant's behaviour: + +| Mode | Tools Available | Preview Required | Use Case | +|------|----------------|------------------|----------| +| **Ask** | Read, Search | No | Answer questions using vault context | +| **Edit** | All tools | Yes | Create, modify, and manage notes | +| **Organize** | Read, Search, Frontmatter, Rename, Move, Link | Yes | Tag, rename, move, and link notes | +| **Research** | Read, Search | No | Deep vault search and synthesis | +| **Workflow** | None (uses `/workflow`) | No | Execute multi-step AI workflows | + +When a mode requires preview (Edit, Organize), write operations like `create_note` or `delete_note` show a card with a before/after diff and **Apply** / **Cancel** buttons. Ask and Research modes execute write tools immediately without preview. + +### Workflows + +Type `/workflow` followed by a description to trigger the workflow engine. The AI will generate a multi-step workflow plan, then execute it step-by-step. Example: + +``` +/workflow Find all notes tagged "meeting", summarise them, and create a "Meeting Summary" note +``` + +### Auto-Organizer + +Use the command palette to trigger: +- **Auto-Tag Untagged Notes** — AI generates tags for notes missing tags +- **Auto-Link Related Notes** — AI inserts "Related Notes" sections with wiki-links + +Both features support: +- **Dry-run mode** — preview proposed changes without modifying the vault +- **Target folder** — restrict processing to a specific folder and its subfolders +- **Tag normalisation** — match generated tags against existing vault vocabulary + +### Commands + +| Command | Description | +|---------|-------------| +| Open Ollama Chat | Open the chat sidebar | +| Clear Semantic Cache | Delete all cached responses | +| Clear Vault Index | Delete all indexed vault notes | +| Rebuild Vault Index | Rebuild the vault semantic index from scratch | +| Auto-Tag Untagged Notes | Run the auto-tagger | +| Auto-Link Related Notes | Run the auto-linker | +| Clear Structured Memory | Delete all conversation summaries, preferences, and facts | +| Clear Tool Telemetry | Delete all recorded telemetry events | + ## Semantic Cache Behaviour - The cache is **bypassed** when tool calls are involved (e.g. file creation), since those requests have side effects. @@ -146,11 +214,57 @@ When you send a message, the plugin searches your vault for relevant notes and i - **First paragraph** — 1.5x weight - **General content** — 1x weight +The plugin also pulls in: +- **Explicit mentions** — notes referenced via `[[...]]` wikilinks in the message +- **Open note** — the currently active note +- **Selected text** — text selected in the active editor +- **Backlinks / Outlinks** — notes that link to / from the open note +- **Related notes** — semantically similar notes (requires vault semantic index) + The plugin automatically watches your vault for changes (create, modify, delete, rename) and updates the semantic index in real time when enabled. +Frontmatter, tags, links, and headings are resolved using Obsidian's built-in `metadataCache` API for accuracy and performance. + ## Tools -The plugin exposes a `create_file` tool that allows the AI to create new markdown files in your vault. Paths are validated for safety (no `.obsidian`/`.git` access, no path traversal). +The assistant has access to a suite of tools that interact with your vault. Available tools depend on the current **Agent Mode**: + +| Tool | Description | Mode | +|------|-------------|------| +| `create_note` / `create_file` | Create a new markdown file | Edit | +| `read_vault_file` | Read the contents of a note | All | +| `search_vault_files` | Keyword-search vault files by path | All | +| `append_to_note` | Append text to the end of a note | Edit | +| `replace_note_section` | Replace content under a specific heading | Edit | +| `update_frontmatter` | Add, update, or remove frontmatter fields | Edit, Organize | +| `rename_note` | Rename a note file | Edit, Organize | +| `move_note` | Move a note to a different folder | Edit, Organize | +| `delete_note` | Delete a note | Edit | +| `insert_link` | Insert a `[[wiki-link]]` into a note | Edit, Organize | + +Paths are validated for safety: no `.obsidian`/`.git` access, no path traversal (`..`), no absolute paths, and a 200-character limit. + +## Structured Memory + +When **Enable Structured Memory** is on, the plugin remembers context across sessions by storing three kinds of data in Obsidian's plugin data JSON: + +- **Conversation Summaries** — After each assistant reply, a brief summary (topic + key points) is saved +- **User Preferences** — Statements like "I prefer dark mode" or "My favourite colour is blue" are extracted and stored +- **Learned Facts** — Simple facts mentioned in conversation (e.g., "Obsidian is a note-taking app") and vault folder paths are remembered + +These are injected as a system message at the start of every LLM call, so the assistant "remembers" context from previous sessions. Limits and clear controls are available in settings. + +## Tool Telemetry + +When **Enable Tool Telemetry** is on, the plugin records: + +- **Tool calls** — which tool, arguments, success/failure, result summary, and duration +- **LLM calls** — model, estimated prompt/completion/total tokens, and duration +- **Vault searches** — query, number of results, and matched note paths + +Telemetry is stored locally in Obsidian's plugin data. The settings tab shows a **Recent Activity** summary of the last 10 events. Use **Clear Tool Telemetry** to wipe the history. + +> **Note:** Token counts are exact when Ollama provides `prompt_eval_count` and `eval_count` in its response; otherwise they are estimated from character count (÷4 approximation). ## Supported Models @@ -167,9 +281,12 @@ Any Ollama-supported model works. Popular choices: ```bash npm install npm run build -npm test +npm test # 520+ unit tests across 21 test suites +npm run lint # ESLint check ``` +The project uses TypeScript, Jest, and esbuild. Obsidian APIs are mocked in `__mocks__/obsidian.ts` for testing. + ## Troubleshooting | Symptom | Likely cause | Fix | @@ -177,10 +294,13 @@ npm test | Plugin doesn't appear in Obsidian | Install script was not run or failed | Run `./install.sh /path/to/vault` and reload Obsidian | | Cannot connect to Ollama | Ollama is not running | Run `ollama serve` | | Model not found | Model not pulled | Run `ollama pull ` | +| "Invalid response format" error | Ollama returned a non-JSON response (e.g., proxy error page) | Check that Ollama is healthy at the configured URL | | Semantic cache unavailable (notice shown) | ChromaDB is not running, or the ChromaDB URL is wrong | Start ChromaDB (`chroma run`) and verify the URL in settings | | Cache always misses | Similarity threshold is too high, or the embedding model was changed | Lower the threshold or click **Clear Semantic Cache** and let the cache rebuild | | Slow first response after enabling cache | Embedding model not yet pulled | Run `ollama pull nomic-embed-text` (or the model you configured) | | Permission issues | Vault write permissions | Check that your Obsidian vault has proper write permissions | +| Structured memory not showing up | Memory was just cleared or is empty | Have a few conversations — summaries are generated after each assistant reply | +| Tool telemetry not recording | Telemetry is disabled or max entries is 0 | Enable **Tool Telemetry** in settings and set **Max Telemetry Entries** > 0 | ## Security diff --git a/src/chat-view.ts b/src/chat-view.ts index 02c2792..1eae351 100755 --- a/src/chat-view.ts +++ b/src/chat-view.ts @@ -701,6 +701,7 @@ export class ChatView extends ItemView { this.updateMessageById(assistantMessageId, { content: `${fullResponse}\n\n*Proposed actions:*\n${writePreviews.map((a) => `- ${a.description}`).join('\n')}`, isStreaming: false, + isThinking: false, }); this.render(); @@ -749,6 +750,7 @@ export class ChatView extends ItemView { this.updateMessageById(assistantMessageId, { content: finalResponse, isStreaming: false, + isThinking: false, }); // Record follow-up LLM call telemetry @@ -761,6 +763,13 @@ export class ChatView extends ItemView { ), durationMs: followUpDurationMs, }); + } else { + // No tool results to follow up on — all tools failed or produced no output + this.updateMessageById(assistantMessageId, { + content: fullResponse || 'No tool results to report.', + isStreaming: false, + isThinking: false, + }); } } @@ -809,6 +818,7 @@ export class ChatView extends ItemView { this.updateMessageById(assistantMessageId, { content: finalResponse, isStreaming: false, + isThinking: false, }); // Record follow-up LLM call telemetry @@ -825,6 +835,7 @@ export class ChatView extends ItemView { this.updateMessageById(assistantMessageId, { content: 'Actions applied successfully.', isStreaming: false, + isThinking: false, }); } @@ -842,6 +853,7 @@ export class ChatView extends ItemView { this.updateMessageById(context.assistantMessageId, { content: 'Actions cancelled. No changes were made.', isStreaming: false, + isThinking: false, }); } @@ -959,6 +971,7 @@ export class ChatView extends ItemView { this.updateMessageById(assistantMessageId, { content: '🔄 Generating workflow plan...', isStreaming: false, + isThinking: false, }); const result = await this.workflowEngine.executeWorkflowFromQuery(query, this.getTools()); @@ -979,6 +992,7 @@ export class ChatView extends ItemView { this.updateMessageById(assistantMessageId, { content: formatted, isStreaming: false, + isThinking: false, }); this.conversationStateManager.updateShortTermContext({ @@ -1140,6 +1154,7 @@ export class ChatView extends ItemView { this.updateMessageById(assistantMessageId, { content: fullResponse, isStreaming: false, + isThinking: false, }); }