feat: add markdown formatting support to AI planning questions

Enhance user question display with markdown rendering for better readability.
Display formatted questions with emphasis, lists, and code snippets. Adjust
input display max-height based on platform (mobile: 15vh, desktop: 30vh).
This commit is contained in:
Andrew Beal 2026-01-04 23:59:07 +00:00
parent 817ab3d332
commit 4614ec5639
4 changed files with 11 additions and 5 deletions

View file

@ -18,7 +18,7 @@ Common use cases:
properties: {
question: {
type: "string",
description: "The question to ask the user. Should be clear, specific, and provide enough context for the user to give a meaningful answer. Example: 'I found 3 files matching your criteria. Should I update all of them or would you like to review them first?'"
description: "The question to ask the user. Should be clear, specific, and provide enough context for the user to give a meaningful answer. Use markdown formatting for emphasis, lists, code snippets, or file paths to make the question easier to read. Example: 'I found **3 files** matching your criteria:\n\n- `src/components/Header.tsx`\n- `src/components/Footer.tsx`\n- `src/components/Sidebar.tsx`\n\nShould I update all of them or would you like to review them first?'"
},
user_message: {
type: "string",

View file

@ -18,6 +18,8 @@
import type { Attachment } from "Conversations/Attachment";
import ChatPlanArea from "./ChatPlanArea.svelte";
import type { ExecutionPlanStore } from "Stores/ExecutionPlanStore";
import type { StreamingMarkdownService } from "Services/StreamingMarkdownService";
import { HTMLService } from "Services/HTMLService";
const plugin: VaultkeeperAIPlugin = Resolve<VaultkeeperAIPlugin>(Services.VaultkeeperAIPlugin);
const executionPlanStore: ExecutionPlanStore = Resolve<ExecutionPlanStore>(Services.ExecutionPlanStore);
@ -25,6 +27,8 @@
const chatService: ChatService = Resolve<ChatService>(Services.ChatService);
const workSpaceService: WorkSpaceService = Resolve<WorkSpaceService>(Services.WorkSpaceService);
const conversationService: ConversationFileSystemService = Resolve<ConversationFileSystemService>(Services.ConversationFileSystemService);
const streamingMarkdownService: StreamingMarkdownService = Resolve<StreamingMarkdownService>(Services.StreamingMarkdownService);
const htmlService: HTMLService = Resolve<HTMLService>(Services.HTMLService);
const abortService: AbortService = Resolve<AbortService>(Services.AbortService);
let chatContainer: HTMLDivElement;
@ -123,7 +127,10 @@
busyPlanning = false;
},
onPlanningQuestion: async (question) => {
chatInput.setDisplayItem(createEl("span", { text: question }));
const displayEl = createEl("div");
const formattedHtml = streamingMarkdownService.formatText(question);
htmlService.setHTMLContent(displayEl, formattedHtml);
chatInput.setDisplayItem(displayEl);
return new Promise<string>((resolve) => {
chatInput.enterQuestionMode(resolve);
});

View file

@ -1,4 +1,5 @@
<script lang="ts">
import { Platform } from "obsidian";
import { slide } from "svelte/transition";
export let editModeActive = false;
@ -22,7 +23,7 @@
{#if displayItem}
<div id="input-display-wrapper" transition:slide>
<div id="input-display-container" class:edit-mode={editModeActive} bind:this={contentDiv}>
<div id="input-display-container" class:edit-mode={editModeActive} style:max-height={Platform.isMobile ? "15vh" : "30vh"} bind:this={contentDiv}>
</div>
</div>
{/if}
@ -37,7 +38,6 @@
display: flex;
overflow-y: auto;
scroll-behavior: smooth;
max-height: 15vh;
justify-content: center;
align-items: flex-start;
margin: var(--size-4-2) 0;

View file

@ -1,6 +1,5 @@
<script lang="ts">
import { Copy } from "Enums/Copy";
import { Selector } from "Enums/Selector";
import type VaultkeeperAIPlugin from "main";
import { DropdownComponent, setIcon } from "obsidian";
import { Resolve } from "Services/DependencyService";