@jupyterlite/ai 0.14.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/lib/agent.d.ts +33 -115
  2. package/lib/agent.js +192 -106
  3. package/lib/chat-model-handler.d.ts +9 -11
  4. package/lib/chat-model-handler.js +9 -4
  5. package/lib/chat-model.d.ts +84 -13
  6. package/lib/chat-model.js +214 -136
  7. package/lib/completion/completion-provider.d.ts +2 -3
  8. package/lib/components/completion-status.d.ts +2 -2
  9. package/lib/components/index.d.ts +1 -1
  10. package/lib/components/index.js +1 -1
  11. package/lib/components/model-select.d.ts +3 -3
  12. package/lib/components/save-button.d.ts +31 -0
  13. package/lib/components/save-button.js +41 -0
  14. package/lib/components/tool-select.d.ts +3 -4
  15. package/lib/components/{token-usage-display.d.ts → usage-display.d.ts} +13 -14
  16. package/lib/components/usage-display.js +109 -0
  17. package/lib/diff-manager.d.ts +2 -3
  18. package/lib/index.d.ts +2 -4
  19. package/lib/index.js +186 -28
  20. package/lib/models/settings-model.d.ts +11 -53
  21. package/lib/models/settings-model.js +38 -22
  22. package/lib/providers/built-in-providers.js +22 -36
  23. package/lib/providers/generated-context-windows.d.ts +8 -0
  24. package/lib/providers/generated-context-windows.js +96 -0
  25. package/lib/providers/model-info.d.ts +3 -0
  26. package/lib/providers/model-info.js +58 -0
  27. package/lib/tokens.d.ts +361 -36
  28. package/lib/tokens.js +18 -13
  29. package/lib/tools/commands.d.ts +2 -3
  30. package/lib/widgets/ai-settings.d.ts +3 -5
  31. package/lib/widgets/ai-settings.js +12 -0
  32. package/lib/widgets/main-area-chat.d.ts +2 -3
  33. package/lib/widgets/main-area-chat.js +12 -12
  34. package/lib/widgets/provider-config-dialog.d.ts +1 -2
  35. package/lib/widgets/provider-config-dialog.js +34 -34
  36. package/package.json +17 -10
  37. package/schema/settings-model.json +18 -1
  38. package/src/agent.ts +275 -248
  39. package/src/chat-model-handler.ts +25 -21
  40. package/src/chat-model.ts +307 -196
  41. package/src/completion/completion-provider.ts +7 -4
  42. package/src/components/completion-status.tsx +3 -3
  43. package/src/components/index.ts +1 -1
  44. package/src/components/model-select.tsx +4 -3
  45. package/src/components/save-button.tsx +84 -0
  46. package/src/components/tool-select.tsx +10 -4
  47. package/src/components/usage-display.tsx +208 -0
  48. package/src/diff-manager.ts +4 -4
  49. package/src/index.ts +250 -58
  50. package/src/models/settings-model.ts +46 -88
  51. package/src/providers/built-in-providers.ts +22 -36
  52. package/src/providers/generated-context-windows.ts +102 -0
  53. package/src/providers/model-info.ts +88 -0
  54. package/src/tokens.ts +438 -58
  55. package/src/tools/commands.ts +2 -3
  56. package/src/widgets/ai-settings.tsx +69 -15
  57. package/src/widgets/main-area-chat.ts +18 -15
  58. package/src/widgets/provider-config-dialog.tsx +96 -61
  59. package/style/base.css +17 -195
  60. package/lib/approval-buttons.d.ts +0 -49
  61. package/lib/approval-buttons.js +0 -79
  62. package/lib/components/token-usage-display.js +0 -72
  63. package/src/approval-buttons.ts +0 -115
  64. package/src/components/token-usage-display.tsx +0 -138
package/style/base.css CHANGED
@@ -88,164 +88,6 @@
88
88
  border-bottom: none;
89
89
  }
90
90
 
91
- /* Modern Tool Call Card Styling */
92
- .jp-ai-tool-call {
93
- margin: 8px 0;
94
- border: 1px solid var(--jp-border-color1);
95
- border-radius: 6px;
96
- background: var(--jp-layout-color0);
97
- box-shadow: var(--jp-elevation-z2);
98
- transition: all 0.2s ease;
99
- overflow: hidden;
100
- }
101
-
102
- .jp-ai-tool-call:hover {
103
- border-color: var(--jp-border-color2);
104
- box-shadow: var(--jp-elevation-z4);
105
- }
106
-
107
- /* Tool Header - clickable summary */
108
- .jp-ai-tool-header {
109
- display: flex;
110
- align-items: center;
111
- padding: 4px 8px;
112
- background: var(--jp-layout-color1);
113
- cursor: pointer;
114
- user-select: none;
115
- gap: 8px;
116
- transition: background-color 0.2s ease;
117
- }
118
-
119
- .jp-ai-tool-header:hover {
120
- background: var(--jp-layout-color2);
121
- }
122
-
123
- .jp-ai-tool-header::marker {
124
- content: '';
125
- }
126
-
127
- .jp-ai-tool-header::before {
128
- content: '';
129
- width: 0;
130
- height: 0;
131
- border-left: 5px solid var(--jp-ui-font-color2);
132
- border-top: 3px solid transparent;
133
- border-bottom: 3px solid transparent;
134
- transition: transform 0.2s ease;
135
- }
136
-
137
- .jp-ai-tool-call[open] .jp-ai-tool-header::before {
138
- transform: rotate(90deg);
139
- }
140
-
141
- .jp-ai-tool-icon {
142
- font-size: 14px;
143
- opacity: 0.8;
144
- }
145
-
146
- .jp-ai-tool-title {
147
- font-family: var(--jp-ui-font-family);
148
- font-size: var(--jp-ui-font-size1);
149
- font-weight: 500;
150
- color: var(--jp-ui-font-color1);
151
- flex: 1;
152
- }
153
-
154
- .jp-ai-tool-summary {
155
- font-weight: 400;
156
- opacity: 0.7;
157
- font-size: var(--jp-ui-font-size0);
158
- }
159
-
160
- .jp-ai-tool-summary::before {
161
- content: ' ';
162
- white-space: pre;
163
- }
164
-
165
- .jp-ai-tool-status {
166
- font-size: var(--jp-ui-font-size0);
167
- font-weight: 500;
168
- padding: 2px 6px;
169
- border-radius: 3px;
170
- }
171
-
172
- .jp-ai-tool-status-pending {
173
- background: rgb(var(--jp-warn-color1-rgb) / 15%);
174
- color: var(--jp-warn-color1);
175
- }
176
-
177
- .jp-ai-tool-status-completed {
178
- background: rgb(var(--jp-success-color1-rgb) / 15%);
179
- color: var(--jp-success-color1);
180
- }
181
-
182
- .jp-ai-tool-status-error {
183
- background: rgb(var(--jp-error-color1-rgb) / 15%);
184
- color: var(--jp-error-color1);
185
- }
186
-
187
- .jp-ai-tool-status-approval {
188
- background: rgb(var(--jp-warn-color1-rgb) / 15%);
189
- color: var(--jp-warn-color1);
190
- }
191
-
192
- /* Tool Body */
193
- .jp-ai-tool-body {
194
- padding: 8px 12px 12px;
195
- }
196
-
197
- .jp-ai-tool-section {
198
- margin-bottom: 8px;
199
- }
200
-
201
- .jp-ai-tool-section:last-child {
202
- margin-bottom: 0;
203
- }
204
-
205
- .jp-ai-tool-label {
206
- font-family: var(--jp-ui-font-family);
207
- font-size: var(--jp-ui-font-size0);
208
- font-weight: 600;
209
- color: var(--jp-ui-font-color2);
210
- margin-bottom: 4px;
211
- text-transform: uppercase;
212
- letter-spacing: 0.5px;
213
- }
214
-
215
- .jp-ai-tool-code {
216
- background: var(--jp-layout-color2);
217
- border: 1px solid var(--jp-border-color1);
218
- border-radius: 4px;
219
- padding: 8px;
220
- margin: 0;
221
- font-family: var(--jp-code-font-family);
222
- font-size: var(--jp-code-font-size);
223
- line-height: 1.4;
224
- overflow: auto auto;
225
- max-height: 200px;
226
- }
227
-
228
- .jp-ai-tool-code code {
229
- background: none;
230
- padding: 0;
231
- border: none;
232
- font-family: inherit;
233
- font-size: inherit;
234
- }
235
-
236
- /* State-specific styling */
237
- .jp-ai-tool-pending {
238
- border-left: 4px solid var(--jp-warn-color1);
239
- }
240
-
241
- .jp-ai-tool-completed {
242
- border-left: 4px solid var(--jp-success-color1);
243
- }
244
-
245
- .jp-ai-tool-error {
246
- border-left: 4px solid var(--jp-error-color1);
247
- }
248
-
249
91
  .jp-AIChatToolbar {
250
92
  display: flex;
251
93
  flex-shrink: 0;
@@ -267,53 +109,33 @@
267
109
  padding: 0 0.4em;
268
110
  }
269
111
 
270
- /* Tool Approval Button Styles */
271
- .jp-ai-tool-approval-buttons,
272
- .jp-ai-group-approval-buttons {
112
+ /* Save button */
113
+ .jp-ai-SaveButton {
273
114
  display: flex;
274
- gap: 8px;
275
- margin-top: 12px;
276
- justify-content: flex-end;
277
- }
278
-
279
- .jp-ai-approval-btn {
280
- padding: 6px 12px;
281
- border: none;
115
+ align-items: center;
116
+ background-color: var(--jp-layout-color1);
117
+ border: 1px solid var(--jp-border-color1);
282
118
  border-radius: 4px;
283
- font-family: var(--jp-ui-font-family);
284
- font-size: var(--jp-ui-font-size0);
285
- font-weight: 500;
286
- cursor: pointer;
287
- transition: all 0.2s ease;
288
- min-width: 70px;
289
- display: inline-block;
290
- }
291
-
292
- .jp-ai-approval-approve {
293
- background: var(--jp-success-color1);
294
- color: var(--jp-ui-inverse-font-color1);
119
+ padding: 4px;
295
120
  }
296
121
 
297
- .jp-ai-approval-approve:hover:not(:disabled) {
298
- background: var(--jp-success-color0);
299
- transform: translateY(-1px);
300
- box-shadow: var(--jp-elevation-z4);
122
+ .jp-ai-SaveButton.lm-mod-toggled {
123
+ box-shadow: inset 0 0 2px 2px var(--neutral-fill-strong-active);
301
124
  }
302
125
 
303
- .jp-ai-approval-reject {
304
- background: var(--jp-error-color1);
305
- color: var(--jp-ui-inverse-font-color1);
126
+ .jp-ai-SaveButton .jp-ToolbarButtonComponent {
127
+ margin: unset;
128
+ height: 18px;
306
129
  }
307
130
 
308
- .jp-ai-approval-reject:hover:not(:disabled) {
309
- background: var(--jp-error-color0);
310
- transform: translateY(-1px);
311
- box-shadow: var(--jp-elevation-z4);
131
+ .jp-ai-SaveButton .jp-ai-AutoSaveButton {
132
+ min-width: unset;
133
+ width: 18px;
312
134
  }
313
135
 
314
- .jp-ai-approval-btn:disabled {
315
- cursor: not-allowed;
316
- opacity: 0.5;
136
+ .jp-ai-SaveButton .jp-ai-AutoSaveButton svg {
137
+ width: 12px;
138
+ height: 12px;
317
139
  }
318
140
 
319
141
  .jp-MainAreaWidget
@@ -1,49 +0,0 @@
1
- import { ChatWidget } from '@jupyter/chat';
2
- import { IDisposable } from '@lumino/disposable';
3
- import type { AgentManager } from './agent';
4
- /**
5
- * Handles click events for approval buttons in the chat panel.
6
- */
7
- export declare class ApprovalButtons implements IDisposable {
8
- constructor(options: ApprovalButtons.IOptions);
9
- get isDisposed(): boolean;
10
- /**
11
- * Dispose of the resources held by the object.
12
- */
13
- dispose(): void;
14
- /**
15
- * Handles click events using event delegation.
16
- * Detects clicks on approval buttons and calls the appropriate handler.
17
- */
18
- private _handleClick;
19
- /**
20
- * Handles approval/rejection of a tool call.
21
- */
22
- private _handleApproval;
23
- /**
24
- * Extracts the approval ID from an element's class list.
25
- * The ID is encoded in a class name like "jp-ai-approval-id--{id}".
26
- */
27
- private _extractApprovalId;
28
- private _chatPanel;
29
- private _isDisposed;
30
- private _agentManager;
31
- }
32
- /**
33
- * Namespace for ApprovalButtons statics.
34
- */
35
- export declare namespace ApprovalButtons {
36
- /**
37
- * The options for the constructor of the approval buttons.
38
- */
39
- interface IOptions {
40
- /**
41
- * The chat panel widget to wrap.
42
- */
43
- chatPanel: ChatWidget;
44
- /**
45
- * The agent manager for handling approvals.
46
- */
47
- agentManager: AgentManager;
48
- }
49
- }
@@ -1,79 +0,0 @@
1
- /**
2
- * Handles click events for approval buttons in the chat panel.
3
- */
4
- export class ApprovalButtons {
5
- constructor(options) {
6
- this._chatPanel = options.chatPanel;
7
- this._agentManager = options.agentManager;
8
- this._chatPanel.node.addEventListener('click', this._handleClick);
9
- }
10
- get isDisposed() {
11
- return this._isDisposed;
12
- }
13
- /**
14
- * Dispose of the resources held by the object.
15
- */
16
- dispose() {
17
- if (this._isDisposed) {
18
- return;
19
- }
20
- this._isDisposed = true;
21
- this._chatPanel.node.removeEventListener('click', this._handleClick);
22
- this._chatPanel = null;
23
- }
24
- /**
25
- * Handles click events using event delegation.
26
- * Detects clicks on approval buttons and calls the appropriate handler.
27
- */
28
- _handleClick = (event) => {
29
- const target = event.target;
30
- // Check if the click target is an approval button
31
- if (!target.classList.contains('jp-ai-approval-btn')) {
32
- return;
33
- }
34
- event.preventDefault();
35
- event.stopPropagation();
36
- const isApprove = target.classList.contains('jp-ai-approval-approve');
37
- this._handleApproval(target, isApprove);
38
- };
39
- /**
40
- * Handles approval/rejection of a tool call.
41
- */
42
- _handleApproval(target, isApprove) {
43
- const container = target.closest('.jp-ai-tool-approval-buttons');
44
- if (!container) {
45
- return;
46
- }
47
- // Extract approval ID from class name (encoded as jp-ai-approval-id--{id})
48
- const approvalId = this._extractApprovalId(container);
49
- if (!approvalId) {
50
- console.warn('No approval ID found for button');
51
- return;
52
- }
53
- // Disable buttons to prevent double-clicks
54
- const buttons = container.querySelectorAll('button');
55
- buttons.forEach(btn => btn.setAttribute('disabled', 'true'));
56
- if (isApprove) {
57
- this._agentManager.approveToolCall(approvalId);
58
- }
59
- else {
60
- this._agentManager.rejectToolCall(approvalId);
61
- }
62
- }
63
- /**
64
- * Extracts the approval ID from an element's class list.
65
- * The ID is encoded in a class name like "jp-ai-approval-id--{id}".
66
- */
67
- _extractApprovalId(element) {
68
- const prefix = 'jp-ai-approval-id--';
69
- for (const className of element.classList) {
70
- if (className.startsWith(prefix)) {
71
- return className.slice(prefix.length);
72
- }
73
- }
74
- return null;
75
- }
76
- _chatPanel;
77
- _isDisposed = false;
78
- _agentManager;
79
- }
@@ -1,72 +0,0 @@
1
- import { ReactWidget, UseSignal } from '@jupyterlab/ui-components';
2
- import React from 'react';
3
- /**
4
- * React component that displays token usage information.
5
- * Shows input/output token counts with up/down arrows.
6
- * Only renders when token usage display is enabled in settings.
7
- */
8
- export const TokenUsageDisplay = ({ tokenUsageChanged, settingsModel, initialTokenUsage, translator: trans }) => {
9
- return (React.createElement(UseSignal, { signal: settingsModel.stateChanged, initialArgs: undefined }, () => {
10
- const config = settingsModel.config;
11
- if (!config.showTokenUsage) {
12
- return null;
13
- }
14
- return (React.createElement(UseSignal, { signal: tokenUsageChanged, initialArgs: initialTokenUsage }, (_, tokenUsage) => {
15
- if (!tokenUsage) {
16
- return null;
17
- }
18
- const total = tokenUsage.inputTokens + tokenUsage.outputTokens;
19
- if (total === 0) {
20
- return null;
21
- }
22
- return (React.createElement("div", { style: {
23
- display: 'flex',
24
- alignItems: 'center',
25
- gap: '6px',
26
- fontSize: '12px',
27
- color: 'var(--jp-ui-font-color2)',
28
- padding: '4px 8px',
29
- backgroundColor: 'var(--jp-layout-color1)',
30
- border: '1px solid var(--jp-border-color1)',
31
- borderRadius: '4px',
32
- whiteSpace: 'nowrap'
33
- }, title: trans.__('Token Usage - Sent: %1, Received: %2, Total: %3', tokenUsage.inputTokens.toLocaleString(), tokenUsage.outputTokens.toLocaleString(), total.toLocaleString()) },
34
- React.createElement("span", { style: {
35
- display: 'flex',
36
- alignItems: 'center',
37
- gap: '2px'
38
- } },
39
- React.createElement("span", null, "\u2191"),
40
- React.createElement("span", null, tokenUsage.inputTokens.toLocaleString())),
41
- React.createElement("span", { style: {
42
- display: 'flex',
43
- alignItems: 'center',
44
- gap: '2px'
45
- } },
46
- React.createElement("span", null, "\u2193"),
47
- React.createElement("span", null, tokenUsage.outputTokens.toLocaleString()))));
48
- }));
49
- }));
50
- };
51
- /**
52
- * JupyterLab widget wrapper for the TokenUsageDisplay component.
53
- * Extends ReactWidget to integrate with the JupyterLab widget system.
54
- */
55
- export class TokenUsageWidget extends ReactWidget {
56
- /**
57
- * Creates a new TokenUsageWidget instance.
58
- * @param options - Configuration options containing required models
59
- */
60
- constructor(options) {
61
- super();
62
- this._options = options;
63
- }
64
- /**
65
- * Renders the React component within the widget.
66
- * @returns The TokenUsageDisplay React element
67
- */
68
- render() {
69
- return React.createElement(TokenUsageDisplay, { ...this._options });
70
- }
71
- _options;
72
- }
@@ -1,115 +0,0 @@
1
- import { ChatWidget } from '@jupyter/chat';
2
- import { IDisposable } from '@lumino/disposable';
3
- import type { AgentManager } from './agent';
4
-
5
- /**
6
- * Handles click events for approval buttons in the chat panel.
7
- */
8
- export class ApprovalButtons implements IDisposable {
9
- constructor(options: ApprovalButtons.IOptions) {
10
- this._chatPanel = options.chatPanel;
11
- this._agentManager = options.agentManager;
12
-
13
- this._chatPanel.node.addEventListener('click', this._handleClick);
14
- }
15
-
16
- get isDisposed(): boolean {
17
- return this._isDisposed;
18
- }
19
-
20
- /**
21
- * Dispose of the resources held by the object.
22
- */
23
- dispose(): void {
24
- if (this._isDisposed) {
25
- return;
26
- }
27
- this._isDisposed = true;
28
-
29
- this._chatPanel.node.removeEventListener('click', this._handleClick);
30
- this._chatPanel = null!;
31
- }
32
-
33
- /**
34
- * Handles click events using event delegation.
35
- * Detects clicks on approval buttons and calls the appropriate handler.
36
- */
37
- private _handleClick = (event: Event): void => {
38
- const target = event.target as HTMLElement;
39
-
40
- // Check if the click target is an approval button
41
- if (!target.classList.contains('jp-ai-approval-btn')) {
42
- return;
43
- }
44
-
45
- event.preventDefault();
46
- event.stopPropagation();
47
-
48
- const isApprove = target.classList.contains('jp-ai-approval-approve');
49
- this._handleApproval(target, isApprove);
50
- };
51
-
52
- /**
53
- * Handles approval/rejection of a tool call.
54
- */
55
- private _handleApproval(target: HTMLElement, isApprove: boolean): void {
56
- const container = target.closest('.jp-ai-tool-approval-buttons');
57
- if (!container) {
58
- return;
59
- }
60
-
61
- // Extract approval ID from class name (encoded as jp-ai-approval-id--{id})
62
- const approvalId = this._extractApprovalId(container);
63
- if (!approvalId) {
64
- console.warn('No approval ID found for button');
65
- return;
66
- }
67
-
68
- // Disable buttons to prevent double-clicks
69
- const buttons = container.querySelectorAll('button');
70
- buttons.forEach(btn => btn.setAttribute('disabled', 'true'));
71
-
72
- if (isApprove) {
73
- this._agentManager.approveToolCall(approvalId);
74
- } else {
75
- this._agentManager.rejectToolCall(approvalId);
76
- }
77
- }
78
-
79
- /**
80
- * Extracts the approval ID from an element's class list.
81
- * The ID is encoded in a class name like "jp-ai-approval-id--{id}".
82
- */
83
- private _extractApprovalId(element: Element): string | null {
84
- const prefix = 'jp-ai-approval-id--';
85
- for (const className of element.classList) {
86
- if (className.startsWith(prefix)) {
87
- return className.slice(prefix.length);
88
- }
89
- }
90
- return null;
91
- }
92
-
93
- private _chatPanel: ChatWidget;
94
- private _isDisposed: boolean = false;
95
- private _agentManager: AgentManager;
96
- }
97
-
98
- /**
99
- * Namespace for ApprovalButtons statics.
100
- */
101
- export namespace ApprovalButtons {
102
- /**
103
- * The options for the constructor of the approval buttons.
104
- */
105
- export interface IOptions {
106
- /**
107
- * The chat panel widget to wrap.
108
- */
109
- chatPanel: ChatWidget;
110
- /**
111
- * The agent manager for handling approvals.
112
- */
113
- agentManager: AgentManager;
114
- }
115
- }
@@ -1,138 +0,0 @@
1
- import { ReactWidget, UseSignal } from '@jupyterlab/ui-components';
2
- import type { TranslationBundle } from '@jupyterlab/translation';
3
- import React from 'react';
4
- import { ISignal } from '@lumino/signaling';
5
- import { AISettingsModel } from '../models/settings-model';
6
- import { ITokenUsage } from '../tokens';
7
-
8
- /**
9
- * Props for the TokenUsageDisplay component.
10
- */
11
- export interface ITokenUsageDisplayProps {
12
- /**
13
- * The token usage changed signal
14
- */
15
- tokenUsageChanged: ISignal<any, ITokenUsage>;
16
-
17
- /**
18
- * The settings model instance for configuration options
19
- */
20
- settingsModel: AISettingsModel;
21
-
22
- /**
23
- * Initial token usage.
24
- */
25
- initialTokenUsage?: ITokenUsage;
26
-
27
- /**
28
- * The application language translator.
29
- */
30
- translator: TranslationBundle;
31
- }
32
-
33
- /**
34
- * React component that displays token usage information.
35
- * Shows input/output token counts with up/down arrows.
36
- * Only renders when token usage display is enabled in settings.
37
- */
38
- export const TokenUsageDisplay: React.FC<ITokenUsageDisplayProps> = ({
39
- tokenUsageChanged,
40
- settingsModel,
41
- initialTokenUsage,
42
- translator: trans
43
- }) => {
44
- return (
45
- <UseSignal signal={settingsModel.stateChanged} initialArgs={undefined}>
46
- {() => {
47
- const config = settingsModel.config;
48
- if (!config.showTokenUsage) {
49
- return null;
50
- }
51
-
52
- return (
53
- <UseSignal signal={tokenUsageChanged} initialArgs={initialTokenUsage}>
54
- {(_, tokenUsage: ITokenUsage | null | undefined) => {
55
- if (!tokenUsage) {
56
- return null;
57
- }
58
-
59
- const total = tokenUsage.inputTokens + tokenUsage.outputTokens;
60
- if (total === 0) {
61
- return null;
62
- }
63
-
64
- return (
65
- <div
66
- style={{
67
- display: 'flex',
68
- alignItems: 'center',
69
- gap: '6px',
70
- fontSize: '12px',
71
- color: 'var(--jp-ui-font-color2)',
72
- padding: '4px 8px',
73
- backgroundColor: 'var(--jp-layout-color1)',
74
- border: '1px solid var(--jp-border-color1)',
75
- borderRadius: '4px',
76
- whiteSpace: 'nowrap'
77
- }}
78
- title={trans.__(
79
- 'Token Usage - Sent: %1, Received: %2, Total: %3',
80
- tokenUsage.inputTokens.toLocaleString(),
81
- tokenUsage.outputTokens.toLocaleString(),
82
- total.toLocaleString()
83
- )}
84
- >
85
- <span
86
- style={{
87
- display: 'flex',
88
- alignItems: 'center',
89
- gap: '2px'
90
- }}
91
- >
92
- <span>↑</span>
93
- <span>{tokenUsage.inputTokens.toLocaleString()}</span>
94
- </span>
95
- <span
96
- style={{
97
- display: 'flex',
98
- alignItems: 'center',
99
- gap: '2px'
100
- }}
101
- >
102
- <span>↓</span>
103
- <span>{tokenUsage.outputTokens.toLocaleString()}</span>
104
- </span>
105
- </div>
106
- );
107
- }}
108
- </UseSignal>
109
- );
110
- }}
111
- </UseSignal>
112
- );
113
- };
114
-
115
- /**
116
- * JupyterLab widget wrapper for the TokenUsageDisplay component.
117
- * Extends ReactWidget to integrate with the JupyterLab widget system.
118
- */
119
- export class TokenUsageWidget extends ReactWidget {
120
- /**
121
- * Creates a new TokenUsageWidget instance.
122
- * @param options - Configuration options containing required models
123
- */
124
- constructor(options: ITokenUsageDisplayProps) {
125
- super();
126
- this._options = options;
127
- }
128
-
129
- /**
130
- * Renders the React component within the widget.
131
- * @returns The TokenUsageDisplay React element
132
- */
133
- protected render(): React.ReactElement {
134
- return <TokenUsageDisplay {...this._options} />;
135
- }
136
-
137
- private _options: ITokenUsageDisplayProps;
138
- }