Skip to content

Commit 0870354

Browse files
committed
feat(ai): token usage chip strings and styles, write-first ask files
Strings and styles for the AI panel's usage chip: the chip in the input area's mode row, its drop-up with an All tab, a tab per model and a gear tab holding the two display options, the line under each answer, and the usage shown on history rows. The subscription note reads "With a Claude subscription, this cost is included in your plan. Pricing shown is for reference only." The empty chip dims its icon and text rather than itself, so the drop-up inside it stays opaque. The askInLivePreview description now says to write both UI files before calling the tool; the smaller models were calling it first.
1 parent 1a60893 commit 0870354

3 files changed

Lines changed: 227 additions & 1 deletion

File tree

‎src-node/mcp-editor-tools.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -778,7 +778,7 @@ function createEditorMcpServer(sdkModule, nodeConnector, clarificationAccessors)
778778
"minimize and close, a text field with Send for an answer in the user's own words, drag, resize and " +
779779
"placement. You write only the body: uiFile, an HTML fragment with its own <style>, and scriptFile, whose " +
780780
"text runs once it is rendered as function(root, phoenix, params) { <your file's text goes here> }, so " +
781-
"write only what goes between the braces. Write both with Write into the folder " +
781+
"write only what goes between the braces. Write both files first, then call this tool; Write them into the folder " +
782782
"getEditorState reports as askInLivePreviewUiDir (your own folder: no permission needed, not shown to the " +
783783
"user), edit and reuse them later; pass " +
784784
"per-ask data in params, which fills {{key}} placeholders in the markup (escaped) and reaches the script " +

‎src/nls/root/strings.js‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2794,6 +2794,22 @@ define({
27942794
"AI_CHAT_TOOL_PROBLEMS": "Problems",
27952795
"AI_CHAT_TOOL_NOTIFY": "Notification",
27962796
"AI_CHAT_TOOL_ASK": "Asking in live preview",
2797+
"AI_CHAT_USAGE_CHIP_TITLE": "Tokens and cost of this chat",
2798+
"AI_CHAT_USAGE_TOKENS": "{0} tok",
2799+
"AI_CHAT_USAGE_CALLS": "{0} calls",
2800+
"AI_CHAT_USAGE_TAB_ALL": "All",
2801+
"AI_CHAT_USAGE_OPTIONS": "Options",
2802+
"AI_CHAT_USAGE_INPUT": "Input tokens",
2803+
"AI_CHAT_USAGE_OUTPUT": "Output tokens",
2804+
"AI_CHAT_USAGE_CACHE_READ": "Cache read",
2805+
"AI_CHAT_USAGE_CACHE_WRITE": "Cache write",
2806+
"AI_CHAT_USAGE_TOTAL": "Total tokens",
2807+
"AI_CHAT_USAGE_TURNS_CALLS": "Turns \u00b7 API calls",
2808+
"AI_CHAT_USAGE_API_TIME": "Time in API",
2809+
"AI_CHAT_USAGE_COST": "Cost at list price",
2810+
"AI_CHAT_USAGE_NOTE": "With a Claude subscription, this cost is included in your plan. Pricing shown is for reference only.",
2811+
"AI_CHAT_USAGE_OPTION_TURNS": "Show usage after every turn",
2812+
"AI_CHAT_USAGE_OPTION_DOLLARS": "Show $ cost",
27972813
"AI_CHAT_TOOL_ASK_COMPOSING": "Asking a question in the live preview...",
27982814
"AI_CHAT_LABEL_YOU_IN_PREVIEW": "You, in the live preview",
27992815
"AI_CHAT_TOOL_ASK_WAITING": "Answer in the live preview, or",

‎src/styles/Extn-AIChatPanel.less‎

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,20 @@
717717
flex-shrink: 0;
718718
}
719719

720+
// The chat's tokens and cost, when it has had a turn.
721+
.ai-history-item-usage {
722+
font-size: @ai-text-meta;
723+
color: @project-panel-text-2;
724+
opacity: 0.6;
725+
flex-shrink: 0;
726+
white-space: nowrap;
727+
728+
&::before {
729+
content: "·";
730+
margin-right: 5px;
731+
}
732+
}
733+
720734
/* Claude's title for the session, revealed on hover: always-on it made
721735
a 50-entry list too dense to scan. It keeps its space in the row while
722736
hidden, so showing it shifts nothing. Empty when it would only repeat
@@ -4222,6 +4236,178 @@
42224236
to { opacity: 1; }
42234237
}
42244238

4239+
/* ── Usage chip: tokens and cost of the chat, with a drop-up for the split ───── */
4240+
.ai-chat-mode-row {
4241+
position: relative;
4242+
4243+
.ai-usage-chip {
4244+
position: relative;
4245+
margin-left: auto;
4246+
display: inline-flex;
4247+
align-items: center;
4248+
gap: 5px;
4249+
height: 22px;
4250+
padding: 0 6px;
4251+
border-radius: 4px;
4252+
font-size: @ai-text-meta;
4253+
color: @project-panel-text-2;
4254+
cursor: pointer;
4255+
user-select: none;
4256+
white-space: nowrap;
4257+
4258+
&:hover, &.ai-usage-open {
4259+
background: rgba(255, 255, 255, 0.04);
4260+
color: @project-panel-text-1;
4261+
}
4262+
4263+
> i {
4264+
width: 14px;
4265+
text-align: center;
4266+
font-size: 10px;
4267+
opacity: 0.75;
4268+
}
4269+
4270+
.ai-usage-caret {
4271+
width: auto;
4272+
font-size: 9px;
4273+
opacity: 0.6;
4274+
transition: transform 120ms ease;
4275+
}
4276+
4277+
&.ai-usage-open .ai-usage-caret {
4278+
transform: rotate(180deg);
4279+
}
4280+
4281+
// Dim the chip's own text and icon before any turn; never the chip itself, since an
4282+
// opacity on the container would fade the drop-up inside it as well.
4283+
&.ai-usage-empty > i,
4284+
&.ai-usage-empty > .ai-usage-chip-text {
4285+
opacity: 0.6;
4286+
}
4287+
}
4288+
4289+
// The info flash shares the right side: the chip stops claiming the space then.
4290+
.ai-info.ai-info-flash + .ai-usage-chip {
4291+
margin-left: 8px;
4292+
}
4293+
4294+
// The drop-up borrows the attach menu's surface.
4295+
.ai-usage-pop {
4296+
display: none;
4297+
position: absolute;
4298+
right: 0;
4299+
bottom: ~"calc(100% + 6px)";
4300+
min-width: 230px;
4301+
padding: 4px 0;
4302+
background: @bc-ai-input-bg;
4303+
border: 1px solid @bc-ai-input-border;
4304+
border-radius: 8px;
4305+
box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.3);
4306+
z-index: 100;
4307+
text-align: left;
4308+
font-size: @ai-text-meta;
4309+
color: @project-panel-text-1;
4310+
cursor: default;
4311+
white-space: nowrap;
4312+
}
4313+
4314+
.ai-usage-chip.ai-usage-open .ai-usage-pop {
4315+
display: block;
4316+
}
4317+
4318+
.ai-usage-tabs {
4319+
display: flex;
4320+
gap: 2px;
4321+
padding: 6px 8px 5px;
4322+
border-bottom: 1px solid @bc-ai-input-border;
4323+
margin-bottom: 2px;
4324+
}
4325+
4326+
.ai-usage-tab {
4327+
padding: 4px 9px;
4328+
border-radius: 4px;
4329+
font-size: @ai-text-secondary;
4330+
color: @project-panel-text-2;
4331+
cursor: pointer;
4332+
4333+
&:hover {
4334+
background: rgba(255, 255, 255, 0.04);
4335+
}
4336+
4337+
&.active {
4338+
background: rgba(255, 255, 255, 0.08);
4339+
color: @project-panel-text-1;
4340+
}
4341+
4342+
&.ai-usage-tab-options {
4343+
margin-left: auto;
4344+
4345+
i {
4346+
font-size: 11px;
4347+
}
4348+
}
4349+
}
4350+
4351+
.ai-usage-pane {
4352+
display: none;
4353+
flex-direction: column;
4354+
min-height: var(--ai-usage-pane-height);
4355+
4356+
&.active {
4357+
display: flex;
4358+
}
4359+
}
4360+
4361+
.ai-usage-row {
4362+
display: flex;
4363+
justify-content: space-between;
4364+
gap: 16px;
4365+
padding: 5px 12px;
4366+
4367+
span:last-child {
4368+
font-variant-numeric: tabular-nums;
4369+
}
4370+
4371+
&.ai-usage-total {
4372+
border-top: 1px solid @bc-ai-input-border;
4373+
margin-top: 2px;
4374+
padding-top: 6px;
4375+
}
4376+
}
4377+
4378+
.ai-usage-note {
4379+
margin-top: auto;
4380+
padding: 4px 12px 6px;
4381+
color: @project-panel-text-2;
4382+
white-space: normal;
4383+
max-width: 270px;
4384+
}
4385+
4386+
label.ai-usage-option {
4387+
display: flex;
4388+
align-items: center;
4389+
justify-content: space-between;
4390+
gap: 16px;
4391+
margin: 0;
4392+
padding: 7px 12px;
4393+
font-size: @ai-text-meta;
4394+
font-weight: normal;
4395+
line-height: 1.4;
4396+
color: inherit;
4397+
cursor: pointer;
4398+
4399+
&:hover {
4400+
background: rgba(255, 255, 255, 0.04);
4401+
}
4402+
4403+
input[type="checkbox"] {
4404+
margin: 0;
4405+
width: 13px;
4406+
height: 13px;
4407+
}
4408+
}
4409+
}
4410+
42254411
.ai-chat-context-bar {
42264412
display: none;
42274413
flex-wrap: wrap;
@@ -5885,3 +6071,27 @@
58856071
.ai-chat-panel .ai-ask-waiting { color: @project-panel-text-2; font-size: @ai-text-secondary; }
58866072
.ai-chat-panel .ai-ask-cancel { border: 1px solid @bc-ai-input-border; border-radius: 4px; background: transparent; color: inherit; font: inherit; font-size: @ai-text-secondary; padding: 2px 10px; cursor: pointer; }
58876073
.ai-chat-panel .ai-ask-cancel:hover { background: rgba(128, 128, 128, 0.2); }
6074+
6075+
/* ── Usage line under an answer: what that turn took ────────────────── */
6076+
.ai-chat-panel .ai-usage-turn {
6077+
display: flex;
6078+
align-items: center;
6079+
gap: 8px;
6080+
margin: -2px 0 10px 14px;
6081+
font-size: @ai-text-meta;
6082+
color: @project-panel-text-2;
6083+
white-space: nowrap;
6084+
6085+
i {
6086+
font-size: 10px;
6087+
opacity: 0.7;
6088+
}
6089+
6090+
.ai-usage-sep {
6091+
opacity: 0.5;
6092+
}
6093+
6094+
&.ai-usage-hidden {
6095+
display: none;
6096+
}
6097+
}

0 commit comments

Comments
 (0)