Skip to content

Commit a450edf

Browse files
luoxuanzaoQoder-AI
andauthored
feat(context): announce the current note in the turn text (#80)
* feat(context): announce the current note in the turn text The chip above the composer showed which note was attached, but the note was sent only once per session, so the agent kept assuming a stale note after the user switched. Drop the chip and resolve the active note when a turn is built instead: append <linked_note> to the turn text only when it changed since the last announcement — first turn, note switch, reopening after close — and replay it once after a session switch, mirroring <external_context>. Excluded tags still keep a note out of context. * refactor(context): rename the note tag to current_note The tag carries the note the user is viewing and is sent when it changes, so current_note says what it is; linked_note stays understood as the legacy name and the system prompt now explains both. * docs(changelog): keep the current-note entries under Unreleased Rebasing onto main moved them into the released 1.0.12 section, since that is where their neighbouring context lines now live. Co-authored-by: QoderAI (Qwen 3.8 Max) <qoder_ai@qoder.com> * chore(chat): drop the dead file-chip styles and lookups left by the chip removal FileChipsView is gone, so nothing creates .qoderian-file-indicator or applies the .qoderian-file-chip base pill anymore: remove the container rule, the base pill with its hover/focus-visible rules, and the two queries that could only ever return null. The -icon/-name/-remove part classes stay because the selection indicators share them. Co-authored-by: QoderAI (Qwen 3.8 Max) <qoder_ai@qoder.com> --------- Co-authored-by: QoderAI (Qwen 3.8 Max) <qoder_ai@qoder.com>
1 parent ed423ae commit a450edf

29 files changed

Lines changed: 207 additions & 660 deletions

‎CHANGELOG.md‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@ version with its date and start a fresh empty `[Unreleased]` above it.
1616
- The context usage meter beside the composer is now a complete ring that fills
1717
clockwise from the top, replacing the 240° arc. The percentage, the hover
1818
tooltip, and the pale-red warning state above 80% are unchanged.
19+
- The agent now learns which note you are viewing from the message text: the
20+
turn you send after switching notes carries the new path as a
21+
`<current_note>` tag (older messages may still carry `<linked_note>`, which
22+
keeps working), and switching conversations reports it again, so the
23+
composer no longer needs a chip for it.
24+
25+
### Removed
26+
27+
- The current-note chip above the composer is gone. Use the "Excluded tags"
28+
setting to keep a note out of context.
1929

2030
## [1.0.16] - 2026-09-29
2131

‎src/features/chat/chat-view.ts‎

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -700,15 +700,6 @@ export class QoderianView extends ItemView {
700700
this.plugin.app.vault.on('modify', () => markCacheDirty(false))
701701
);
702702

703-
// File open event
704-
this.registerEvent(
705-
this.plugin.app.workspace.on('file-open', (file) => {
706-
if (file) {
707-
this.tabManager?.getActiveTab()?.ui.fileContextManager?.handleFileOpen(file);
708-
}
709-
})
710-
);
711-
712703
// Click outside to close mention dropdown
713704
this.registerDomEvent(activeDocument, 'click', (e) => {
714705
const activeTab = this.tabManager?.getActiveTab();

‎src/features/chat/controllers/context-row-visibility.ts‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,15 @@ export function updateContextRowHasContent(contextRowEl: HTMLElement): void {
22
const editorIndicator = contextRowEl.querySelector('.qoderian-selection-indicator');
33
const browserIndicator = contextRowEl.querySelector('.qoderian-browser-selection-indicator');
44
const canvasIndicator = contextRowEl.querySelector('.qoderian-canvas-indicator');
5-
const fileIndicator = contextRowEl.querySelector('.qoderian-file-indicator');
65
const imagePreview = contextRowEl.querySelector('.qoderian-image-preview');
76

87
const hasEditorSelection = !!editorIndicator && !editorIndicator.hasClass('qoderian-hidden');
98
const hasBrowserSelection = !!browserIndicator && !browserIndicator.hasClass('qoderian-hidden');
109
const hasCanvasSelection = !!canvasIndicator && !canvasIndicator.hasClass('qoderian-hidden');
11-
const hasFileChips = !!fileIndicator && fileIndicator.hasClass('qoderian-visible-flex');
1210
const hasImageChips = !!imagePreview && imagePreview.hasClass('qoderian-visible-flex');
1311

1412
contextRowEl.classList.toggle(
1513
'has-content',
16-
hasEditorSelection || hasBrowserSelection || hasCanvasSelection || hasFileChips || hasImageChips
14+
hasEditorSelection || hasBrowserSelection || hasCanvasSelection || hasImageChips
1715
);
1816
}

‎src/features/chat/controllers/conversation-controller.ts‎

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,6 @@ export class ConversationController {
165165

166166
const fileCtx = this.deps.getFileContextManager();
167167
fileCtx?.resetForNewConversation();
168-
fileCtx?.autoAttachActiveFile();
169168

170169
this.deps.getImageContextManager()?.clearImages();
171170
this.deps.getMcpServerSelector()?.clearEnabled();
@@ -211,7 +210,6 @@ export class ConversationController {
211210

212211
const fileCtx = this.deps.getFileContextManager();
213212
fileCtx?.resetForNewConversation();
214-
fileCtx?.autoAttachActiveFile();
215213

216214
// Initialize external contexts with persistent paths from settings
217215
this.deps.getExternalContextSelector()?.clearExternalContexts(
@@ -232,7 +230,7 @@ export class ConversationController {
232230
}
233231

234232
await this.deps.ensureServiceForConversation?.(conversation);
235-
this.restoreConversation(conversation, { autoAttachFile: true });
233+
this.restoreConversation(conversation);
236234
this.updateWelcomeVisibility();
237235

238236
this.callbacks.onConversationLoaded?.();
@@ -448,10 +446,7 @@ export class ConversationController {
448446
* Shared logic for restoring a conversation into the current tab.
449447
* Used by both loadActive() and switchTo() to avoid duplication.
450448
*/
451-
private restoreConversation(
452-
conversation: Conversation,
453-
options?: { autoAttachFile?: boolean }
454-
): void {
449+
private restoreConversation(conversation: Conversation): void {
455450
const { plugin, state, renderer } = this.deps;
456451

457452
state.currentConversationId = conversation.id;
@@ -471,13 +466,7 @@ export class ConversationController {
471466
this.getAgentService()?.syncConversationState(conversation, externalContextPaths);
472467

473468
const fileCtx = this.deps.getFileContextManager();
474-
fileCtx?.resetForLoadedConversation(hasMessages);
475-
476-
if (conversation.currentNote) {
477-
fileCtx?.setCurrentNote(conversation.currentNote);
478-
} else if (!hasMessages && options?.autoAttachFile) {
479-
fileCtx?.autoAttachActiveFile();
480-
}
469+
fileCtx?.resetForLoadedConversation();
481470

482471
this.restoreExternalContextPaths(conversation.externalContextPaths, !hasMessages);
483472

@@ -985,10 +974,7 @@ export class ConversationController {
985974
const welcomeEl = this.deps.getWelcomeEl();
986975
if (!welcomeEl) return;
987976

988-
// Initialize file context to auto-attach the currently focused note
989-
const fileCtx = this.deps.getFileContextManager();
990-
fileCtx?.resetForNewConversation();
991-
fileCtx?.autoAttachActiveFile();
977+
this.deps.getFileContextManager()?.resetForNewConversation();
992978

993979
// Only add greeting if not already present
994980
if (!welcomeEl.querySelector('.qoderian-welcome-greeting')) {

‎src/features/chat/controllers/input-controller.ts‎

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,6 @@ export class InputController {
197197

198198
const inputEl = this.deps.getInputEl();
199199
const imageContextManager = this.deps.getImageContextManager();
200-
const fileContextManager = this.deps.getFileContextManager();
201200

202201
const contentOverride = options?.content;
203202
const shouldUseInput = contentOverride === undefined;
@@ -266,8 +265,6 @@ export class InputController {
266265
welcomeEl.addClass('qoderian-hidden');
267266
}
268267

269-
fileContextManager?.startSession();
270-
271268
// Slash commands are passed directly to SDK for handling
272269
// SDK handles expansion, $ARGUMENTS, @file references, and frontmatter options
273270
const images = imageOverride ?? imageContextManager?.getAttachedImages() ?? [];
@@ -293,8 +290,6 @@ export class InputController {
293290
});
294291
const { displayContent, turnRequest } = turnSubmission;
295292

296-
fileContextManager?.markCurrentNoteSent();
297-
298293
const userMsg: ChatMessage = {
299294
id: this.deps.generateId(),
300295
role: 'user',
@@ -656,7 +651,6 @@ export class InputController {
656651
const externalContextSelector = this.deps.getExternalContextSelector();
657652

658653
const currentNotePath = fileContextManager?.getCurrentNotePath() || null;
659-
const shouldSendCurrentNote = fileContextManager?.shouldSendCurrentNote(currentNotePath) ?? false;
660654

661655
const editorContext = options.editorContextOverride !== undefined
662656
? options.editorContextOverride
@@ -680,7 +674,7 @@ export class InputController {
680674
turnRequest: {
681675
text: transformedText,
682676
images: options.images,
683-
currentNotePath: shouldSendCurrentNote && currentNotePath ? currentNotePath : undefined,
677+
currentNotePath: currentNotePath ?? undefined,
684678
editorSelection: editorContext,
685679
browserSelection: browserContext,
686680
canvasSelection: canvasContext,

‎src/features/chat/tabs/tab.ts‎

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -269,20 +269,13 @@ function initializeContextManagers(tab: TabData, plugin: QoderianPlugin): void {
269269
},
270270
});
271271

272-
// File context manager - chips in contextRowEl, dropdown in inputContainerEl
272+
// File context manager - dropdown in inputContainerEl
273273
tab.ui.fileContextManager = new FileContextManager(
274274
app,
275275
dom.contextRowEl,
276276
dom.inputEl,
277277
{
278278
getExcludedTags: () => plugin.settings.excludedTags,
279-
onChipsChanged: () => {
280-
tab.controllers.selectionController?.updateContextRowVisibility();
281-
tab.controllers.browserSelectionController?.updateContextRowVisibility();
282-
tab.controllers.canvasSelectionController?.updateContextRowVisibility();
283-
autoResizeTextarea(dom.inputEl);
284-
tab.renderer?.scrollToBottomIfNeeded();
285-
},
286279
onReferencesChanged: (references) => {
287280
tab.ui.composerBridge?.setReferences(references);
288281
},

‎src/features/chat/ui/file-context/file-chips-view.ts‎

Lines changed: 0 additions & 70 deletions
This file was deleted.

0 commit comments

Comments
 (0)