deploy: current vibn theia state
Some checks failed
Playwright Tests / Playwright Tests (ubuntu-22.04, Node.js 22.x) (push) Has been cancelled
3PP License Check / 3PP License Check (11, 22.x, ubuntu-22.04) (push) Has been cancelled
Publish packages to NPM / Perform Publishing (push) Has been cancelled

Made-with: Cursor
This commit is contained in:
2026-02-27 12:01:08 -08:00
commit 8bb5110148
3782 changed files with 640947 additions and 0 deletions

View File

@@ -0,0 +1,214 @@
// *****************************************************************************
// Copyright (C) 2025 EclipseSource GmbH.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
import * as React from '@theia/core/shared/react';
import { MessageService, nls } from '@theia/core';
import { TokenUsageFrontendService, ModelTokenUsageData } from '@theia/ai-core/lib/browser/token-usage-frontend-service';
import { formatDistanceToNow } from 'date-fns';
import { AITableConfigurationWidget, TableColumn } from './base/ai-table-configuration-widget';
@injectable()
export class AITokenUsageConfigurationWidget extends AITableConfigurationWidget<ModelTokenUsageData> {
static readonly ID = 'ai-token-usage-configuration-container-widget';
static readonly LABEL = nls.localize('theia/ai/tokenUsage/label', 'Token Usage');
@inject(MessageService)
protected readonly messageService: MessageService;
@inject(TokenUsageFrontendService)
protected readonly tokenUsageService: TokenUsageFrontendService;
@postConstruct()
protected init(): void {
this.id = AITokenUsageConfigurationWidget.ID;
this.title.label = AITokenUsageConfigurationWidget.LABEL;
this.title.closable = false;
this.addClass('ai-configuration-widget');
this.loadItems().then(() => this.update());
this.toDispose.push(
this.tokenUsageService.onTokenUsageUpdated(data => {
this.items = data;
this.update();
})
);
}
protected async loadItems(): Promise<void> {
try {
this.items = await this.tokenUsageService.getTokenUsageData();
} catch (error) {
this.messageService.error(nls.localize('theia/ai/tokenUsage/failedToGetTokenUsageData', 'Failed to fetch token usage data: {0}', error));
}
}
protected getItemId(item: ModelTokenUsageData): string {
return item.modelId;
}
protected formatNumber(num: number): string {
return num.toLocaleString();
}
protected formatDate(date?: Date): string {
if (!date) {
return nls.localizeByDefault('Never');
}
return formatDistanceToNow(date, { addSuffix: true });
}
protected hasCacheData(): boolean {
return this.items.some(model =>
model.cachedInputTokens !== undefined ||
model.readCachedInputTokens !== undefined
);
}
protected getColumns(): TableColumn<ModelTokenUsageData>[] {
const showCacheColumns = this.hasCacheData();
const columns: TableColumn<ModelTokenUsageData>[] = [
{
id: 'model',
label: nls.localize('theia/ai/tokenUsage/model', 'Model'),
className: 'token-usage-model-column',
renderCell: item => <span>{item.modelId}</span>
},
{
id: 'input-tokens',
label: nls.localize('theia/ai/tokenUsage/inputTokens', 'Input Tokens'),
className: 'token-usage-column',
renderCell: item => <span>{this.formatNumber(item.inputTokens)}</span>
}
];
if (showCacheColumns) {
columns.push(
{
id: 'cached-input-tokens',
label: nls.localize('theia/ai/tokenUsage/cachedInputTokens', 'Input Tokens Written to Cache'),
className: 'token-usage-column',
renderCell: item => (
<span title={nls.localize(
'theia/ai/tokenUsage/cachedInputTokensTooltip',
"Tracked additionally to 'Input Tokens'. Usually more expensive than non-cached tokens."
)}>
{item.cachedInputTokens !== undefined ? this.formatNumber(item.cachedInputTokens) : '-'}
</span>
)
},
{
id: 'read-cached-input-tokens',
label: nls.localize('theia/ai/tokenUsage/readCachedInputTokens', 'Input Tokens Read From Cache'),
className: 'token-usage-column',
renderCell: item => (
<span title={nls.localize(
'theia/ai/tokenUsage/readCachedInputTokensTooltip',
"Tracked additionally to 'Input Token'. Usually much less expensive than not cached. Usually does not count to rate limits."
)}>
{item.readCachedInputTokens !== undefined ? this.formatNumber(item.readCachedInputTokens) : '-'}
</span>
)
}
);
}
columns.push(
{
id: 'output-tokens',
label: nls.localize('theia/ai/tokenUsage/outputTokens', 'Output Tokens'),
className: 'token-usage-column',
renderCell: item => <span>{this.formatNumber(item.outputTokens)}</span>
},
{
id: 'total-tokens',
label: nls.localize('theia/ai/tokenUsage/totalTokens', 'Total Tokens'),
className: 'token-usage-column',
renderCell: item => {
const totalTokens = item.inputTokens + item.outputTokens + (item.cachedInputTokens ?? 0);
return (
<span title={nls.localize('theia/ai/tokenUsage/totalTokensTooltip', "'Input Tokens' + 'Output Tokens'")}>
{this.formatNumber(totalTokens)}
</span>
);
}
},
{
id: 'last-used',
label: nls.localize('theia/ai/tokenUsage/lastUsed', 'Last Used'),
className: 'token-usage-column',
renderCell: item => {
const lastUsedDate = item.lastUsed ? new Date(item.lastUsed) : undefined;
const exactDateString = lastUsedDate ? lastUsedDate.toLocaleString() : '';
return <span title={exactDateString}>{this.formatDate(lastUsedDate)}</span>;
}
}
);
return columns;
}
protected override renderHeader(): React.ReactNode {
return undefined;
}
protected override renderFooter(): React.ReactNode {
if (this.items.length === 0) {
return (
<div className="ai-empty-state-content">
<p>{nls.localize('theia/ai/tokenUsage/noData', 'No token usage data available yet.')}</p>
</div>
);
}
const showCacheColumns = this.hasCacheData();
const totalInputTokens = this.items.reduce((sum, model) => sum + model.inputTokens, 0);
const totalOutputTokens = this.items.reduce((sum, model) => sum + model.outputTokens, 0);
const totalCachedInputTokens = this.items.reduce((sum, model) => sum + (model.cachedInputTokens || 0), 0);
const totalReadCachedInputTokens = this.items.reduce((sum, model) => sum + (model.readCachedInputTokens || 0), 0);
const totalTokens = totalInputTokens + totalCachedInputTokens + totalOutputTokens;
return (
<div className="ai-configuration-footer-total">
<table className="ai-configuration-table">
<tfoot>
<tr className="ai-configuration-footer-total-row">
<td className="token-usage-model-column">{nls.localize('theia/ai/tokenUsage/total', 'Total')}</td>
<td className="token-usage-column">{this.formatNumber(totalInputTokens)}</td>
{showCacheColumns && (
<>
<td className="token-usage-column">{this.formatNumber(totalCachedInputTokens)}</td>
<td className="token-usage-column">{this.formatNumber(totalReadCachedInputTokens)}</td>
</>
)}
<td className="token-usage-column">{this.formatNumber(totalOutputTokens)}</td>
<td className="token-usage-column">{this.formatNumber(totalTokens)}</td>
<td className="token-usage-column"></td>
</tr>
</tfoot>
</table>
<div className="ai-configuration-info-box">
<p className="ai-configuration-info-text">
<i className="codicon codicon-info ai-configuration-info-icon"></i>
{nls.localize('theia/ai/tokenUsage/note', 'Token usage is tracked since the start of the application and is not persisted.')}
</p>
</div>
</div>
);
}
}