mirror of
https://github.com/andy-stack/vaultkeeper-ai.git
synced 2026-07-22 06:42:03 +00:00
feat: add free edit mode to bypass diff confirmations
Add toggle button in chat input to enable/disable free edit mode, which allows AI to make changes without showing diffs. Update ThoughtIndicator and StreamingIndicator with fade transitions and redesigned dot-based styling. Simplify ChatInput layout by removing dynamic stacked mode detection.
This commit is contained in:
parent
fa92e15b8c
commit
f57438dd54
7 changed files with 138 additions and 183 deletions
|
|
@ -213,7 +213,9 @@
|
|||
|
||||
<ThoughtIndicator thought={currentThought} bind:thoughtIndicatorElement={thoughtIndicatorElement}/>
|
||||
{#if isSubmitting}
|
||||
<StreamingIndicator bind:streamingIndicatorElement={streamingIndicatorElement}/>
|
||||
<div transition:fade={{ duration: 300 }}>
|
||||
<StreamingIndicator bind:streamingIndicatorElement={streamingIndicatorElement}/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div bind:this={chatAreaPaddingElement} style:user-select=none></div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { onDestroy, onMount, tick } from "svelte";
|
||||
import { Platform, setIcon, type EventRef } from "obsidian";
|
||||
import { Platform, setIcon, ToggleComponent, type EventRef } from "obsidian";
|
||||
import type { UserInputService } from "Services/UserInputService";
|
||||
import type { ISearchState, SearchStateStore } from "Stores/SearchStateStore";
|
||||
import { Resolve } from "Services/DependencyService";
|
||||
|
|
@ -55,14 +55,15 @@
|
|||
let submitButton: HTMLButtonElement;
|
||||
let attachmentButton: HTMLButtonElement;
|
||||
let chatModeButton: HTMLButtonElement;
|
||||
let freeEditButton: HTMLButtonElement;
|
||||
|
||||
let chatModeSelectionAreaActive: boolean = false;
|
||||
let userInstructionAreaActive: boolean = false;
|
||||
let userInstructionActive: boolean = true;
|
||||
let stacked: boolean = false;
|
||||
|
||||
let userRequest: string = "";
|
||||
|
||||
let freeEdit: boolean = settingsService.settings.freeEdit;
|
||||
let chatMode: ChatMode = settingsService.settings.chatMode;
|
||||
let inputMode: InputMode = InputMode.Normal;
|
||||
let questionResolver: ((answer: string) => void) | null = null;
|
||||
|
|
@ -73,7 +74,6 @@
|
|||
|
||||
let countdownIntervalId: ReturnType<typeof setInterval> | null = null;
|
||||
let countdownSecondsRemaining: number = 0;
|
||||
let inputInitialHeight: number = 0;
|
||||
|
||||
const diffOpenedRef: EventRef = eventService.on(Event.DiffOpened, () => { inputMode = InputMode.Diff; focusInput(); });
|
||||
const diffClosedRef: EventRef = eventService.on(Event.DiffClosed, () => { inputMode = InputMode.Normal; focusInput(); });
|
||||
|
|
@ -89,14 +89,27 @@
|
|||
setIcon(chatModeButton, iconForChatMode(chatMode));
|
||||
}
|
||||
}
|
||||
if (changed.includes("freeEdit")) {
|
||||
if (freeEditButton) {
|
||||
freeEdit = settingsService.settings.freeEdit;
|
||||
setIcon(freeEditButton, iconForFreeEdit(freeEdit));
|
||||
}
|
||||
}
|
||||
if (changed.includes("provider")) {
|
||||
webSearchUnavailable = settingsService.settings.provider === AIProvider.Local;
|
||||
}
|
||||
if (changed.includes("enableWebSearch")) {
|
||||
webSearchActive = settingsService.settings.enableWebSearch;
|
||||
}
|
||||
if (changed.includes("userInstruction")) {
|
||||
aiPrompt.userInstruction().then(instruction => {
|
||||
userInstructionActive = instruction.trim() !== "";
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
onMount(async () => {
|
||||
userInstructionActive = (await aiPrompt.userInstruction()).trim() !== "";
|
||||
inputInitialHeight = textareaElement.innerHeight;
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
|
|
@ -109,19 +122,6 @@
|
|||
stopCountdown();
|
||||
});
|
||||
|
||||
function checkStacked() {
|
||||
// Mobile already uses the 'stacked' layout
|
||||
if (Platform.isMobile || textareaElement.textContent.trim() === "") {
|
||||
stacked = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (textareaElement.innerHeight > inputInitialHeight) {
|
||||
stacked = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
export function focusInput(force: boolean = false) {
|
||||
// Generally don't focus on mobile, it's annoying
|
||||
if (force || !Platform.isMobile) {
|
||||
|
|
@ -237,6 +237,10 @@
|
|||
setIcon(chatModeButton, iconForChatMode(chatMode));
|
||||
}
|
||||
|
||||
$: if (freeEditButton) {
|
||||
setIcon(freeEditButton, iconForFreeEdit(freeEdit))
|
||||
}
|
||||
|
||||
$: inputPlaceholder = (() => {
|
||||
if (inputMode === InputMode.Question) return Copy.InputPlaceholderQuestion;
|
||||
if (inputMode === InputMode.Diff) return Copy.InputPlaceholderDiff;
|
||||
|
|
@ -264,6 +268,10 @@
|
|||
return isSubmitting ? Copy.ButtonCancel : Copy.ButtonSendMessage;
|
||||
})();
|
||||
|
||||
function iconForFreeEdit(freeEdit: boolean) {
|
||||
return freeEdit ? "file-pen" : "file-lock"
|
||||
}
|
||||
|
||||
function handleStop() {
|
||||
onStop();
|
||||
}
|
||||
|
|
@ -312,7 +320,6 @@
|
|||
|
||||
textareaElement.textContent = "";
|
||||
userRequest = "";
|
||||
checkStacked();
|
||||
|
||||
if (Platform.isMobile) {
|
||||
textareaElement.blur();
|
||||
|
|
@ -341,7 +348,13 @@
|
|||
|
||||
function toggleChatModeSelectionArea() {
|
||||
chatModeSelectionAreaActive = !chatModeSelectionAreaActive;
|
||||
}
|
||||
|
||||
function toggleFreeEdit() {
|
||||
const newState = !settingsService.settings.freeEdit;
|
||||
settingsService.updateSettings(settings => {
|
||||
settings.freeEdit = newState;
|
||||
});
|
||||
}
|
||||
|
||||
async function handleKeydown(e: KeyboardEvent) {
|
||||
|
|
@ -463,8 +476,6 @@
|
|||
if (userRequest.trim() === "") {
|
||||
textareaElement.textContent = "";
|
||||
}
|
||||
|
||||
checkStacked();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -567,7 +578,7 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<div id="input-container" class:stacked>
|
||||
<div id="input-container">
|
||||
<div id="input-display-container" style:padding-top={attachments.length > 0 ? "var(--size-4-2)" : 0}>
|
||||
<InputDisplay bind:this={inputDisplay}/>
|
||||
</div>
|
||||
|
|
@ -651,6 +662,15 @@
|
|||
aria-label={Copy.ButtonChangeChatMode}>
|
||||
</button>
|
||||
|
||||
<button
|
||||
id="free-edit-button"
|
||||
class:input-button-highlight={freeEdit}
|
||||
bind:this={freeEditButton}
|
||||
on:click={toggleFreeEdit}
|
||||
disabled={!editsAllowed}
|
||||
aria-label={editsAllowed ? Copy.ButtonFreeEdit : Copy.ButtonFreeEditDisabled }>
|
||||
</button>
|
||||
|
||||
<button
|
||||
id="submit-button"
|
||||
bind:this={submitButton}
|
||||
|
|
@ -675,8 +695,8 @@
|
|||
grid-row: 3;
|
||||
grid-column: 1;
|
||||
display: grid;
|
||||
grid-template-rows: auto auto auto auto auto var(--size-4-3) 1fr var(--size-4-3);
|
||||
grid-template-columns: var(--size-4-3) auto var(--size-4-2) auto var(--size-4-2) 1fr var(--size-4-2) auto var(--size-4-2) auto var(--size-4-2) auto var(--size-4-3);
|
||||
grid-template-rows: auto auto auto auto auto var(--size-4-3) 1fr var(--size-4-3) auto var(--size-4-3);
|
||||
grid-template-columns: var(--size-4-3) auto var(--size-4-2) auto 1fr auto var(--size-4-2) auto var(--size-4-2) auto var(--size-4-2) auto var(--size-4-3);
|
||||
border-radius: var(--radius-l);
|
||||
background-color: var(--background-primary);
|
||||
}
|
||||
|
|
@ -711,35 +731,9 @@
|
|||
grid-column: 2 / 13;
|
||||
}
|
||||
|
||||
#user-instruction-button {
|
||||
grid-row: 7;
|
||||
grid-column: 2;
|
||||
border-radius: var(--radius-xl);
|
||||
padding: var(--size-4-2);
|
||||
align-self: end;
|
||||
transition-duration: 0.5s;
|
||||
}
|
||||
|
||||
:global(.is-mobile) #user-instruction-button {
|
||||
max-height: 2rem;
|
||||
}
|
||||
|
||||
#web-search-button {
|
||||
grid-row: 7;
|
||||
grid-column: 4;
|
||||
border-radius: var(--radius-xl);
|
||||
padding: var(--size-4-2);
|
||||
align-self: end;
|
||||
transition-duration: 0.5s;
|
||||
}
|
||||
|
||||
:global(.is-mobile) #web-search-button {
|
||||
max-height: 2rem;
|
||||
}
|
||||
|
||||
#input-field {
|
||||
grid-row: 7;
|
||||
grid-column: 6;
|
||||
grid-column: 2 / 13;
|
||||
height: 100%;
|
||||
max-height: 30vh;
|
||||
border-radius: var(--radius-m);
|
||||
|
|
@ -792,9 +786,35 @@
|
|||
outline: none;
|
||||
}
|
||||
|
||||
#user-instruction-button {
|
||||
grid-row: 9;
|
||||
grid-column: 2;
|
||||
border-radius: var(--radius-xl);
|
||||
padding: var(--size-4-2);
|
||||
align-self: end;
|
||||
transition-duration: 0.5s;
|
||||
}
|
||||
|
||||
:global(.is-mobile) #user-instruction-button {
|
||||
max-height: 2rem;
|
||||
}
|
||||
|
||||
#web-search-button {
|
||||
grid-row: 9;
|
||||
grid-column: 4;
|
||||
border-radius: var(--radius-xl);
|
||||
padding: var(--size-4-2);
|
||||
align-self: end;
|
||||
transition-duration: 0.5s;
|
||||
}
|
||||
|
||||
:global(.is-mobile) #web-search-button {
|
||||
max-height: 2rem;
|
||||
}
|
||||
|
||||
#chat-attachment-button {
|
||||
grid-row: 7;
|
||||
grid-column: 8;
|
||||
grid-row: 9;
|
||||
grid-column: 6;
|
||||
border-radius: var(--radius-xl);
|
||||
padding: var(--size-4-2);
|
||||
align-self: end;
|
||||
|
|
@ -806,8 +826,8 @@
|
|||
}
|
||||
|
||||
#chat-mode-button {
|
||||
grid-row: 7;
|
||||
grid-column: 10;
|
||||
grid-row: 9;
|
||||
grid-column: 8;
|
||||
border-radius: var(--radius-xl);
|
||||
padding: var(--size-4-2);
|
||||
align-self: end;
|
||||
|
|
@ -822,8 +842,17 @@
|
|||
box-shadow: 0px 0px 2px 1px var(--color-accent);
|
||||
}
|
||||
|
||||
#free-edit-button {
|
||||
grid-row: 9;
|
||||
grid-column: 10;
|
||||
border-radius: var(--radius-xl);
|
||||
padding: var(--size-4-2);
|
||||
align-self: end;
|
||||
transition-duration: 0.5s;
|
||||
}
|
||||
|
||||
#submit-button {
|
||||
grid-row: 7;
|
||||
grid-row: 9;
|
||||
grid-column: 12;
|
||||
border-radius: var(--radius-xl);
|
||||
padding-left: var(--size-4-2);
|
||||
|
|
@ -841,78 +870,4 @@
|
|||
cursor: pointer;
|
||||
background-color: var(--interactive-accent-hover);
|
||||
}
|
||||
|
||||
/* Stacked layout: input above, buttons below (desktop only, when content wraps) */
|
||||
#input-container.stacked {
|
||||
grid-template-rows: auto auto auto auto auto var(--size-4-3) 1fr var(--size-4-2) auto var(--size-4-3);
|
||||
}
|
||||
|
||||
#input-container.stacked #input-field {
|
||||
grid-column: 2 / 13;
|
||||
}
|
||||
|
||||
#input-container.stacked #user-instruction-button {
|
||||
grid-row: 9;
|
||||
}
|
||||
|
||||
#input-container.stacked #web-search-button {
|
||||
grid-row: 9;
|
||||
}
|
||||
|
||||
#input-container.stacked #chat-attachment-button {
|
||||
grid-row: 9;
|
||||
}
|
||||
|
||||
#input-container.stacked #chat-mode-button {
|
||||
grid-row: 9;
|
||||
}
|
||||
|
||||
#input-container.stacked #submit-button {
|
||||
grid-row: 9;
|
||||
}
|
||||
|
||||
/* Narrow/mobile layout: input above, buttons below */
|
||||
:global(.is-mobile) #input-container {
|
||||
grid-template-rows: auto auto auto auto auto var(--size-4-3) 1fr var(--size-4-2) auto var(--size-4-3);
|
||||
grid-template-columns: var(--size-4-3) auto var(--size-4-2) auto 1fr auto var(--size-4-2) auto var(--size-4-2) auto var(--size-4-3);
|
||||
}
|
||||
|
||||
:global(.is-mobile) #input-display-container,
|
||||
:global(.is-mobile) #input-attachments-container,
|
||||
:global(.is-mobile) #diff-controls-container,
|
||||
:global(.is-mobile) #input-search-results-container,
|
||||
:global(.is-mobile) #user-instruction-container,
|
||||
:global(.is-mobile) #chat-mode-selector-container {
|
||||
grid-column: 2 / 11;
|
||||
}
|
||||
|
||||
:global(.is-mobile) #input-field {
|
||||
grid-row: 7;
|
||||
grid-column: 2 / 11;
|
||||
}
|
||||
|
||||
:global(.is-mobile) #user-instruction-button {
|
||||
grid-row: 9;
|
||||
grid-column: 2;
|
||||
}
|
||||
|
||||
:global(.is-mobile) #web-search-button {
|
||||
grid-row: 9;
|
||||
grid-column: 4;
|
||||
}
|
||||
|
||||
:global(.is-mobile) #chat-attachment-button {
|
||||
grid-row: 9;
|
||||
grid-column: 6;
|
||||
}
|
||||
|
||||
:global(.is-mobile) #chat-mode-button {
|
||||
grid-row: 9;
|
||||
grid-column: 8;
|
||||
}
|
||||
|
||||
:global(.is-mobile) #submit-button {
|
||||
grid-row: 9;
|
||||
grid-column: 10;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { fade } from "svelte/transition";
|
||||
import Spinner from "./Spinner.svelte";
|
||||
export let thought: string | null = null;
|
||||
export let thoughtIndicatorElement: HTMLElement | undefined = undefined;
|
||||
|
||||
|
|
@ -9,9 +8,10 @@
|
|||
</script>
|
||||
|
||||
{#if isVisible}
|
||||
<div class="ai-thought-container" in:fade={{ duration: 200 }} out:fade={{ duration: 200 }} bind:this={thoughtIndicatorElement}>
|
||||
<div class="ai-thought-bubble">
|
||||
<span><Spinner/> {thought}</span>
|
||||
<div class="ai-thought-container" bind:this={thoughtIndicatorElement} transition:fade={{ duration: 300 }}>
|
||||
<div class="ai-thought-line">
|
||||
<span class="ai-thought-dot"></span>
|
||||
<span class="ai-thought-text">{thought}</span>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
@ -22,59 +22,40 @@
|
|||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.ai-thought-bubble {
|
||||
--border-width: 1px;
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
border-radius: 10px;
|
||||
.ai-thought-line {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.5rem;
|
||||
padding-left: 0.125rem;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.ai-thought-bubble span {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
background: var(--background-primary);
|
||||
border-radius: 10px;
|
||||
padding: 0.55rem 0.7rem;
|
||||
.ai-thought-dot {
|
||||
flex-shrink: 0;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
margin-top: 5px;
|
||||
border-radius: 50%;
|
||||
background: var(--text-accent, #a78bfa);
|
||||
animation: breathe 1.6s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.ai-thought-text {
|
||||
font-size: var(--font-smallest);
|
||||
color: var(--text-muted);
|
||||
font-style: italic;
|
||||
line-height: 1.5;
|
||||
word-wrap: break-word;
|
||||
width: 100%;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.ai-thought-bubble::after {
|
||||
position: absolute;
|
||||
content: "";
|
||||
top: calc(-1 * var(--border-width));
|
||||
left: calc(-1 * var(--border-width));
|
||||
z-index: 0;
|
||||
width: calc(100% + var(--border-width) * 2);
|
||||
height: calc(100% + var(--border-width) * 2);
|
||||
background: linear-gradient(
|
||||
60deg,
|
||||
hsl(224, 85%, 66%),
|
||||
hsl(269, 85%, 66%),
|
||||
hsl(314, 85%, 66%),
|
||||
hsl(359, 85%, 66%),
|
||||
hsl(44, 85%, 66%),
|
||||
hsl(89, 85%, 66%),
|
||||
hsl(134, 85%, 66%),
|
||||
hsl(179, 85%, 66%)
|
||||
);
|
||||
background-size: 300% 300%;
|
||||
background-position: 0 50%;
|
||||
border-radius: 10px;
|
||||
animation: moveGradient 3s alternate infinite;
|
||||
}
|
||||
|
||||
@keyframes moveGradient {
|
||||
@keyframes breathe {
|
||||
0%, 100% {
|
||||
opacity: 0.35;
|
||||
transform: scale(0.85);
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -133,6 +133,8 @@ export enum Copy {
|
|||
ButtonMakeSuggestion = "Make Suggestion",
|
||||
ButtonSendMessage = "Send Message",
|
||||
ButtonChangeChatMode = "Change the Chat Mode",
|
||||
ButtonFreeEdit = "Allow changes without asking",
|
||||
ButtonFreeEditDisabled = "Read-only mode enabled",
|
||||
ButtonTurnOffPlanningMode = "Turn off Planning Mode",
|
||||
ButtonTurnOnPlanningMode = "Turn on Planning Mode",
|
||||
ButtonTurnOffWebSearch = "Turn off Web Search",
|
||||
|
|
|
|||
21
README.md
21
README.md
|
|
@ -18,7 +18,8 @@
|
|||
- 🔍 **Read-Only Mode**: AI can search, read, and list your notes safely
|
||||
- ✏️ **Edit Mode**: AI can create, edit, delete, and move notes and folders (when you need it)
|
||||
- 📋 **Planning Mode**: A three-agent workflow where a planning agent analyzes your vault and creates a step-by-step strategy before execution
|
||||
- **Interactive Diff Viewer** - Review and approve AI-proposed changes before they're applied with side-by-side diff view
|
||||
- **Interactive Diff Viewer** - Review and approve AI-proposed changes before they're applied with side-by-side diff view, or let the AI make changes without asking"
|
||||
- **Plan Approval Workflow** - In Planning Mode, review the AI's proposed plan and approve it, reject it, or suggest changes before execution begins
|
||||
- **Smart Reference System** - Mention tags (`#`), files (`@`), and folders (`/`) with autocomplete
|
||||
- **Custom System Instructions** - Create and switch between personalized AI behaviors
|
||||
- **Conversation Management** - Persistent chat history with automatic conversation naming
|
||||
|
|
@ -139,6 +140,10 @@ When the AI proposes changes to your files in Agent Mode, an interactive diff vi
|
|||
|
||||
The diff viewer ensures you're always in control of what changes are made to your vault, providing transparency and safety when working with AI-generated edits.
|
||||
|
||||
**Skipping Approval**
|
||||
|
||||
You can toggle the agents ability to make changes without asking when in edit and planning mode. While enabled, proposed changes are applied immediately without the diff viewer prompt. Turn it off anytime to go back to reviewing every change.
|
||||
|
||||
### Planning Mode
|
||||
|
||||
Planning Mode introduces a three-agent workflow that separates task planning, orchestration, and execution. When enabled, specialized agents collaborate to analyze your vault, create a detailed strategy, and execute changes with intelligent oversight between each step.
|
||||
|
|
@ -150,8 +155,9 @@ Planning Mode introduces a three-agent workflow that separates task planning, or
|
|||
3. **Planning Phase**: The planning agent analyzes your vault, exploring existing notes, organizational patterns, and relevant content
|
||||
4. **Clarifying Questions**: The planning agent may ask you questions to better understand your requirements
|
||||
5. **Plan Display**: A step-by-step plan appears above the chat showing what will be done
|
||||
6. **Execution Phase**: For each step, an execution agent performs the task while an orchestration agent monitors progress and decides whether to continue, adapt, or replan
|
||||
7. **Completion**: All steps are marked complete when finished
|
||||
6. **Plan Approval**: Review the plan and **Approve** it, **Reject** it, or suggest a change before execution begins (see [Plan Approval](#plan-approval) below)
|
||||
7. **Execution Phase**: For each step, an execution agent performs the task while an orchestration agent monitors progress and decides whether to continue, adapt, or replan
|
||||
8. **Completion**: All steps are marked complete when finished
|
||||
|
||||
**The Three Agents**
|
||||
|
||||
|
|
@ -166,6 +172,14 @@ Planning Mode introduces a three-agent workflow that separates task planning, or
|
|||
- The view auto-scrolls to keep the active step visible
|
||||
- Expand/collapse to see the full plan or a compact view
|
||||
|
||||
**Plan Approval**
|
||||
|
||||
Before execution begins, the proposed plan opens in a dedicated view for your review:
|
||||
|
||||
- **Approve** - Accept the plan as-is and move to the execution phase
|
||||
- **Reject** - Cancel the plan outright
|
||||
- **Suggest a change** - Type feedback describing what you'd like changed, and the planning agent replans with your feedback in mind rather than starting over from scratch
|
||||
|
||||
**When to Use Planning Mode**
|
||||
|
||||
Planning mode is especially useful for:
|
||||
|
|
@ -480,7 +494,6 @@ This plugin is built on the shoulders of many excellent projects:
|
|||
|
||||
**CSS**
|
||||
- [Loader](https://uiverse.io/Li-Deheng/bright-firefox-37) - Animated streaming indicator adapted from original by Li-Deheng
|
||||
- [Gradient Border](https://codepen.io/alphardex/pen/vYEYGzp) - Animated border adapted from original by alphardex
|
||||
- [Gradient Spinner](https://codepen.io/AlexWarnes/pen/jXYYKL) - Animated spinner adapted from original by AlexWarnes
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ export const DEFAULT_SETTINGS: IVaultkeeperAISettings = {
|
|||
firstTimeStart: true,
|
||||
|
||||
chatMode: ChatMode.ReadOnly,
|
||||
freeEdit: false,
|
||||
userInstruction: "",
|
||||
|
||||
provider: AIProvider.Local,
|
||||
|
|
@ -88,6 +89,7 @@ export interface IVaultkeeperAISettings {
|
|||
firstTimeStart: boolean;
|
||||
|
||||
chatMode: ChatMode;
|
||||
freeEdit: boolean;
|
||||
userInstruction: string;
|
||||
|
||||
provider: AIProvider;
|
||||
|
|
|
|||
|
|
@ -607,8 +607,8 @@ export class VaultService {
|
|||
private async proposeChange<T>(oldFileName: string, newFileName: string, oldContent: string, newContent: string,
|
||||
requiresConfirmation: boolean = true, performChange: () => Promise<T>): Promise<T | Error> {
|
||||
try {
|
||||
const result = requiresConfirmation ?
|
||||
await this.diffService.requestDiff(oldFileName, newFileName, oldContent, newContent) : { accepted: true };
|
||||
const result = this.settingsService.settings.freeEdit || !requiresConfirmation ? { accepted: true } :
|
||||
await this.diffService.requestDiff(oldFileName, newFileName, oldContent, newContent);
|
||||
|
||||
if (result.accepted) {
|
||||
return await performChange();
|
||||
|
|
|
|||
Loading…
Reference in a new issue