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.
This commit is contained in:
2026-05-20 23:25:07 +02:00
parent 3d3b996839
commit ae747a4470
2 changed files with 145 additions and 10 deletions
+130 -10
View File
@@ -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 integrationcreate 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 (01) 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 (01) 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 <model>` |
| "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
+15
View File
@@ -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,
});
}