Skip to content
Open
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
4 changes: 3 additions & 1 deletion src/utils/widget-manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ export const WIDGET_MANIFEST: WidgetManifestEntry[] = [
{ type: 'context-bar', create: () => new widgets.ContextBarWidget() },
{ type: 'skills', create: () => new widgets.SkillsWidget() },
{ type: 'thinking-effort', create: () => new widgets.ThinkingEffortWidget() },
{ type: 'vim-mode', create: () => new widgets.VimModeWidget() }
{ type: 'vim-mode', create: () => new widgets.VimModeWidget() },
{ type: 'model-intelligence', create: () => new widgets.ModelIntelligenceWidget() },
{ type: 'context-window-size', create: () => new widgets.ContextWindowSizeWidget() }
];

export const LAYOUT_WIDGET_MANIFEST: LayoutWidgetManifestEntry[] = [
Expand Down
44 changes: 44 additions & 0 deletions src/widgets/ContextWindowSize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import type { RenderContext } from '../types/RenderContext';
import type { Settings } from '../types/Settings';
import type {
Widget,
WidgetEditorDisplay,
WidgetItem
} from '../types/Widget';
import { getContextWindowMetrics } from '../utils/context-window';
import {
getContextConfig,
getModelContextIdentifier
} from '../utils/model-context';
import { formatTokens } from '../utils/renderer';

import { formatRawOrLabeledValue } from './shared/raw-or-labeled';

export class ContextWindowSizeWidget implements Widget {
getDefaultColor(): string { return 'brightBlack'; }
getDescription(): string { return 'Shows the total context window size (e.g. 200k, 1.0M)'; }
getDisplayName(): string { return 'Context Window'; }
getCategory(): string { return 'Context'; }
getEditorDisplay(item: WidgetItem): WidgetEditorDisplay {
return { displayText: this.getDisplayName() };
}

render(item: WidgetItem, context: RenderContext, settings: Settings): string | null {
if (context.isPreview) {
return formatRawOrLabeledValue(item, 'Win: ', '200.0k');
}

const metrics = getContextWindowMetrics(context.data);

if (metrics.windowSize !== null) {
return formatRawOrLabeledValue(item, 'Win: ', formatTokens(metrics.windowSize));
}

const modelIdentifier = getModelContextIdentifier(context.data?.model);
const contextConfig = getContextConfig(modelIdentifier, null);
return formatRawOrLabeledValue(item, 'Win: ', formatTokens(contextConfig.maxTokens));
}

supportsRawValue(): boolean { return true; }
supportsColors(item: WidgetItem): boolean { return true; }
}
84 changes: 84 additions & 0 deletions src/widgets/ModelIntelligence.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import type { RenderContext } from '../types/RenderContext';
import type { Settings } from '../types/Settings';
import type {
Widget,
WidgetEditorDisplay,
WidgetItem
} from '../types/Widget';
import { getContextWindowMetrics } from '../utils/context-window';
import {
getContextConfig,
getModelContextIdentifier
} from '../utils/model-context';

import { formatRawOrLabeledValue } from './shared/raw-or-labeled';

function getModelBeta(modelIdentifier?: string): number {
if (!modelIdentifier) {
return 1.5;
}

const lower = modelIdentifier.toLowerCase();

if (lower.includes('opus')) {
return 1.8;
}

if (lower.includes('haiku')) {
return 1.2;
}

return 1.5;
}

function calculateMI(usageRatio: number, beta: number): number {
const clamped = Math.max(0, Math.min(1, usageRatio));
return Math.max(0, 1 - clamped ** beta);
}

function getUsageRatio(context: RenderContext): number | null {
const metrics = getContextWindowMetrics(context.data);

if (metrics.usedPercentage !== null) {
return metrics.usedPercentage / 100;
}

if (context.tokenMetrics) {
const modelIdentifier = getModelContextIdentifier(context.data?.model);
const contextConfig = getContextConfig(modelIdentifier, metrics.windowSize);
return Math.min(1, context.tokenMetrics.contextLength / contextConfig.maxTokens);
}

return null;
}

export class ModelIntelligenceWidget implements Widget {
getDefaultColor(): string { return 'cyan'; }
getDescription(): string { return 'Model Intelligence score based on context fill level'; }
getDisplayName(): string { return 'Model Intelligence'; }
getCategory(): string { return 'Context'; }
getEditorDisplay(item: WidgetItem): WidgetEditorDisplay {
return { displayText: this.getDisplayName() };
}

render(item: WidgetItem, context: RenderContext, settings: Settings): string | null {
const modelIdentifier = getModelContextIdentifier(context.data?.model);
const beta = getModelBeta(modelIdentifier);

if (context.isPreview) {
const previewMI = calculateMI(0.093, beta);
return formatRawOrLabeledValue(item, 'MI: ', previewMI.toFixed(3));
}

const usageRatio = getUsageRatio(context);
if (usageRatio === null) {
return null;
}

const mi = calculateMI(usageRatio, beta);
return formatRawOrLabeledValue(item, 'MI: ', mi.toFixed(3));
}

supportsRawValue(): boolean { return true; }
supportsColors(item: WidgetItem): boolean { return true; }
}
4 changes: 3 additions & 1 deletion src/widgets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,6 @@ export { ContextBarWidget } from './ContextBar';
export { LinkWidget } from './Link';
export { SkillsWidget } from './Skills';
export { ThinkingEffortWidget } from './ThinkingEffort';
export { VimModeWidget } from './VimMode';
export { VimModeWidget } from './VimMode';
export { ModelIntelligenceWidget } from './ModelIntelligence';
export { ContextWindowSizeWidget } from './ContextWindowSize';