Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,29 @@ version with its date and start a fresh empty `[Unreleased]` above it.

### Added

- Click the context usage reading beside the message input to open a context
window panel: what fills the window (system prompt, tools, skills,
messages), how full it is, and a Compact context button.
- The agent now learns which external context directories are attached: the
message you send right after adding or removing one carries the current
list, so the agent can use those folders without you referencing every file.
- An update icon appears in the view header when GitHub has a newer stable
release; click it to open Qoderian's plugin page, where Obsidian's update
button lives.

### Changed

- The context usage meter is now a complete ring that fills from the top
instead of an arc with a gap at the bottom.
- The resize grip above the message input stays hidden until the pointer is
inside the input area or the composer has focus, so the input's top edge
reads as a plain border while you are reading or scrolling.

### Removed

- The hover tooltip on the message input's resize grip; the resize cursor and
the accent highlight while dragging already signal what the grip does.

## [1.0.11] - 2026-09-16

### Added
Expand Down
4 changes: 3 additions & 1 deletion src/core/runtime/chat-runtime.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ChatMessage, Conversation, SlashCommand, StreamChunk, ToolCallInfo } from '../types';
import type { ChatMessage, ContextUsageBreakdown, Conversation, SlashCommand, StreamChunk, ToolCallInfo } from '../types';
import type {
ApprovalCallback,
AskUserQuestionCallback,
Expand Down Expand Up @@ -41,6 +41,8 @@ export interface ChatRuntime {
getSessionId(): string | null;
consumeSessionInvalidation(): boolean;
isReady(): boolean;
/** Context breakdown for the toolbar panel; null when unavailable. */
requestContextUsage?(): Promise<ContextUsageBreakdown | null>;
getSupportedCommands(): Promise<SlashCommand[]>;
getAuxiliaryModel?(): string | null;
cleanup(): Promise<void>;
Expand Down
27 changes: 27 additions & 0 deletions src/core/types/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,30 @@ export interface UsageInfo {
contextTokens: number;
percentage: number;
}

/** Slots the CLI reports in its `/context` breakdown. */
export type ContextUsageCategoryType =
| 'system_prompt'
| 'system_tools'
| 'skills'
| 'messages'
| 'other'
| 'free_space'
| 'auto_compact';

export interface ContextUsageCategory {
type: ContextUsageCategoryType;
/** Share of the full context window, 0-100 and possibly fractional. */
percentage: number;
}

/** What currently fills the context window, as reported by the CLI. */
export interface ContextUsageBreakdown {
usedPercentage: number;
categories: ContextUsageCategory[];
skills: {
count: number;
/** Aggregate skill frontmatter as a percentage of the full context. */
percentageOfContext: number;
};
}
3 changes: 3 additions & 0 deletions src/core/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
export {
type ChatMessage,
type ContentBlock,
type ContextUsageBreakdown,
type ContextUsageCategory,
type ContextUsageCategoryType,
type Conversation,
type ConversationMeta,
type ErrorContentBlock,
Expand Down
3 changes: 0 additions & 3 deletions src/features/chat/chat-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -417,9 +417,6 @@ export class QoderianView extends ItemView {
);
}
this.creditsUsageButton?.refreshLocale();
for (const tab of this.tabManager?.getAllTabs() ?? []) {
tab.ui.composerResize?.refreshLocale();
}
this.updateTabBar();
}

Expand Down
17 changes: 17 additions & 0 deletions src/features/chat/tabs/tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { t } from '../../../i18n/i18n';
import type QoderianPlugin from '../../../main';
import { isHiddenCommand } from '../../../qoder/commands/command-visibility-policy';
import { getQoderSettings, updateQoderSettings } from '../../../qoder/config/settings';
import { fetchStoredSessionContextUsage } from '../../../qoder/services/context-usage';
import {
SlashCommandDropdown,
toSlashCommandDropdownEntries,
Expand Down Expand Up @@ -429,6 +430,22 @@ function initializeInputToolbar(
await plugin.qoderServices.agentCatalog.refresh();
},
loginService: plugin.qoderServices.loginService,
requestContextUsage: async () => {
const runtime = tab.service;
if (runtime?.requestContextUsage) {
return runtime.requestContextUsage();
}
// A restored tab keeps its runtime unstarted until the first send, so
// read the stored session directly through the idle probe instead.
const conversation = tab.conversationId
? await plugin.getConversationById(tab.conversationId)
: null;
const sessionId = conversation?.sessionId;
return sessionId ? fetchStoredSessionContextUsage(plugin, sessionId) : null;
},
onCompactContext: () => {
void tab.controllers.inputController?.sendMessage({ content: '/compact' });
},
onModelChange: async (model: string) => {
// Blank tabs keep their model choice until the first message binds them.
if (tab.lifecycleState === 'blank') {
Expand Down
10 changes: 0 additions & 10 deletions src/features/chat/ui/composer-resize.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import { t } from '../../../i18n/i18n';
import { setButtonTooltip } from '../../../shared/dom/tooltip';

export const COMPOSER_MIN_HEIGHT = 140;
export const COMPOSER_MAX_HEIGHT_PERCENT = 0.75;
export const COMPOSER_KEYBOARD_RESIZE_STEP = 24;

export interface ComposerResizeController {
destroy(): void;
refreshLocale(): void;
reset(): void;
}

Expand Down Expand Up @@ -113,15 +109,10 @@ export function attachComposerResize(
applyHeight(currentHeight() + delta);
};

const refreshLocale = (): void => {
setButtonTooltip(handleEl, t('composer.resize'));
};

handleEl.setAttribute('role', 'separator');
handleEl.setAttribute('aria-orientation', 'horizontal');
handleEl.setAttribute('tabindex', '0');
updateAriaBounds(currentHeight());
refreshLocale();
handleEl.addEventListener('pointerdown', handlePointerDown);
handleEl.addEventListener('dblclick', reset);
handleEl.addEventListener('keydown', handleKeydown);
Expand All @@ -148,7 +139,6 @@ export function attachComposerResize(
handleEl.removeEventListener('keydown', handleKeydown);
viewWindow?.removeEventListener('blur', stopDragging);
},
refreshLocale,
reset,
};
}
Loading
Loading