@jupyterlite/ai 0.12.0 → 0.13.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 (49) hide show
  1. package/lib/agent.d.ts +24 -2
  2. package/lib/agent.js +161 -24
  3. package/lib/{chat-model-registry.d.ts → chat-model-handler.d.ts} +12 -11
  4. package/lib/{chat-model-registry.js → chat-model-handler.js} +6 -40
  5. package/lib/chat-model.d.ts +8 -0
  6. package/lib/chat-model.js +156 -8
  7. package/lib/completion/completion-provider.d.ts +1 -1
  8. package/lib/completion/completion-provider.js +14 -2
  9. package/lib/components/model-select.js +4 -4
  10. package/lib/components/tool-select.d.ts +11 -2
  11. package/lib/components/tool-select.js +77 -18
  12. package/lib/index.d.ts +3 -3
  13. package/lib/index.js +128 -66
  14. package/lib/models/settings-model.d.ts +2 -0
  15. package/lib/models/settings-model.js +2 -0
  16. package/lib/providers/built-in-providers.js +7 -0
  17. package/lib/providers/provider-tools.d.ts +36 -0
  18. package/lib/providers/provider-tools.js +93 -0
  19. package/lib/rendered-message-outputarea.d.ts +24 -0
  20. package/lib/rendered-message-outputarea.js +48 -0
  21. package/lib/tokens.d.ts +44 -7
  22. package/lib/tokens.js +1 -1
  23. package/lib/tools/commands.js +4 -2
  24. package/lib/tools/web.d.ts +8 -0
  25. package/lib/tools/web.js +196 -0
  26. package/lib/widgets/ai-settings.d.ts +1 -1
  27. package/lib/widgets/ai-settings.js +125 -38
  28. package/lib/widgets/main-area-chat.d.ts +6 -0
  29. package/lib/widgets/main-area-chat.js +28 -0
  30. package/lib/widgets/provider-config-dialog.js +207 -4
  31. package/package.json +10 -4
  32. package/schema/settings-model.json +89 -1
  33. package/src/agent.ts +220 -42
  34. package/src/{chat-model-registry.ts → chat-model-handler.ts} +16 -51
  35. package/src/chat-model.ts +223 -14
  36. package/src/completion/completion-provider.ts +26 -12
  37. package/src/components/model-select.tsx +4 -5
  38. package/src/components/tool-select.tsx +110 -7
  39. package/src/index.ts +153 -82
  40. package/src/models/settings-model.ts +6 -0
  41. package/src/providers/built-in-providers.ts +7 -0
  42. package/src/providers/provider-tools.ts +179 -0
  43. package/src/rendered-message-outputarea.ts +62 -0
  44. package/src/tokens.ts +53 -9
  45. package/src/tools/commands.ts +4 -2
  46. package/src/tools/web.ts +238 -0
  47. package/src/widgets/ai-settings.tsx +282 -77
  48. package/src/widgets/main-area-chat.ts +34 -1
  49. package/src/widgets/provider-config-dialog.tsx +496 -3
package/lib/agent.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { ISignal } from '@lumino/signaling';
2
2
  import { type Tool } from 'ai';
3
3
  import { ISecretsManager } from 'jupyter-secrets-manager';
4
+ import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
4
5
  import { AISettingsModel } from './models/settings-model';
5
6
  import type { IProviderRegistry } from './tokens';
6
7
  import { ISkillRegistry, ITool, IToolRegistry, ITokenUsage } from './tokens';
@@ -22,7 +23,7 @@ export declare namespace AgentManagerFactory {
22
23
  /**
23
24
  * The token used to request the secrets manager.
24
25
  */
25
- token: symbol;
26
+ token: symbol | null;
26
27
  }
27
28
  }
28
29
  export declare class AgentManagerFactory {
@@ -92,7 +93,7 @@ export interface IAgentEventTypeMap {
92
93
  tool_call_complete: {
93
94
  callId: string;
94
95
  toolName: string;
95
- output: string;
96
+ outputData: unknown;
96
97
  isError: boolean;
97
98
  };
98
99
  tool_approval_request: {
@@ -148,6 +149,10 @@ export interface IAgentManagerOptions {
148
149
  * Initial token usage.
149
150
  */
150
151
  tokenUsage?: ITokenUsage;
152
+ /**
153
+ * JupyterLab render mime registry for discovering supported MIME types.
154
+ */
155
+ renderMimeRegistry?: IRenderMimeRegistry;
151
156
  }
152
157
  /**
153
158
  * Manages the AI agent lifecycle and execution loop.
@@ -245,6 +250,10 @@ export declare class AgentManager {
245
250
  * Prepare model, tools, and settings needed to (re)build the agent.
246
251
  */
247
252
  private _prepareAgentConfig;
253
+ /**
254
+ * Build the runtime tool map used by the agent.
255
+ */
256
+ private _buildRuntimeTools;
248
257
  /**
249
258
  * Rebuild the agent using cached resources and the current skills snapshot.
250
259
  */
@@ -264,6 +273,14 @@ export declare class AgentManager {
264
273
  * Handles tool-result stream parts.
265
274
  */
266
275
  private _handleToolResult;
276
+ /**
277
+ * Handles tool-error stream parts.
278
+ */
279
+ private _handleToolError;
280
+ /**
281
+ * Handles tool-output-denied stream parts.
282
+ */
283
+ private _handleToolOutputDenied;
267
284
  /**
268
285
  * Handles tool-approval-request stream parts.
269
286
  */
@@ -296,6 +313,10 @@ export declare class AgentManager {
296
313
  * @returns The enhanced system prompt with dynamic additions
297
314
  */
298
315
  private _getEnhancedSystemPrompt;
316
+ /**
317
+ * Build an instruction line describing MIME types supported by this session.
318
+ */
319
+ private _getSupportedMimeTypesInstruction;
299
320
  private _settingsModel;
300
321
  private _toolRegistry?;
301
322
  private _providerRegistry?;
@@ -312,6 +333,7 @@ export declare class AgentManager {
312
333
  private _activeProvider;
313
334
  private _activeProviderChanged;
314
335
  private _skills;
336
+ private _renderMimeRegistry?;
315
337
  private _initQueue;
316
338
  private _agentConfig;
317
339
  private _pendingApprovals;
package/lib/agent.js CHANGED
@@ -2,6 +2,7 @@ import { Signal } from '@lumino/signaling';
2
2
  import { ToolLoopAgent, stepCountIs } from 'ai';
3
3
  import { createMCPClient } from '@ai-sdk/mcp';
4
4
  import { createModel } from './providers/models';
5
+ import { createProviderTools } from './providers/provider-tools';
5
6
  import { SECRETS_NAMESPACE } from './tokens';
6
7
  export class AgentManagerFactory {
7
8
  constructor(options) {
@@ -20,6 +21,10 @@ export class AgentManagerFactory {
20
21
  this._initializeAgents().catch(error => console.warn('Failed to initialize agent in constructor:', error));
21
22
  // Listen for settings changes
22
23
  this._settingsModel.stateChanged.connect(this._onSettingsChanged, this);
24
+ // Disable the secrets manager if the token is empty.
25
+ if (!options.token) {
26
+ this._secretsManager = undefined;
27
+ }
23
28
  }
24
29
  createAgent(options) {
25
30
  const agentManager = new AgentManager({
@@ -180,6 +185,7 @@ export class AgentManager {
180
185
  this._tokenUsageChanged = new Signal(this);
181
186
  this._skills = [];
182
187
  this._agentConfig = null;
188
+ this._renderMimeRegistry = options.renderMimeRegistry;
183
189
  this.activeProvider =
184
190
  options.activeProvider ?? this._settingsModel.config.defaultProvider;
185
191
  // Initialize selected tools to all available tools by default
@@ -372,7 +378,7 @@ export class AgentManager {
372
378
  this._updateTokenUsage(await result.usage);
373
379
  // Add response messages to history
374
380
  if (responseMessages.messages?.length) {
375
- this._history.push(...responseMessages.messages);
381
+ this._history.push(...Private.sanitizeModelMessages(responseMessages.messages));
376
382
  }
377
383
  // Add approval response if processed
378
384
  if (streamResult.approvalResponse) {
@@ -454,18 +460,27 @@ export class AgentManager {
454
460
  this._mcpTools = mcpTools;
455
461
  }
456
462
  const model = await this._createModel();
457
- const shouldUseTools = !!(config.toolsEnabled &&
458
- this._selectedToolNames.length > 0 &&
459
- this._toolRegistry &&
460
- Object.keys(this._toolRegistry.tools).length > 0 &&
461
- this._supportsToolCalling());
462
- const tools = shouldUseTools
463
- ? { ...this.selectedAgentTools, ...this._mcpTools }
464
- : this._mcpTools;
463
+ const supportsToolCalling = this._supportsToolCalling();
464
+ const canUseTools = config.toolsEnabled && supportsToolCalling;
465
+ const hasFunctionToolRegistry = !!(this._toolRegistry && Object.keys(this._toolRegistry.tools).length > 0);
466
+ const selectedFunctionTools = canUseTools && hasFunctionToolRegistry ? this.selectedAgentTools : {};
467
+ const functionTools = canUseTools
468
+ ? { ...selectedFunctionTools, ...this._mcpTools }
469
+ : {};
465
470
  const activeProviderConfig = this._settingsModel.getProvider(this._activeProvider);
471
+ const activeProviderInfo = activeProviderConfig && this._providerRegistry
472
+ ? this._providerRegistry.getProviderInfo(activeProviderConfig.provider)
473
+ : null;
466
474
  const temperature = activeProviderConfig?.parameters?.temperature ?? DEFAULT_TEMPERATURE;
467
475
  const maxTokens = activeProviderConfig?.parameters?.maxOutputTokens;
468
476
  const maxTurns = activeProviderConfig?.parameters?.maxTurns ?? DEFAULT_MAX_TURNS;
477
+ const tools = this._buildRuntimeTools({
478
+ providerInfo: activeProviderInfo,
479
+ customSettings: activeProviderConfig?.customSettings,
480
+ functionTools,
481
+ includeProviderTools: canUseTools
482
+ });
483
+ const shouldUseTools = canUseTools && Object.keys(tools).length > 0;
469
484
  this._agentConfig = {
470
485
  model,
471
486
  tools,
@@ -476,6 +491,22 @@ export class AgentManager {
476
491
  shouldUseTools
477
492
  };
478
493
  }
494
+ /**
495
+ * Build the runtime tool map used by the agent.
496
+ */
497
+ _buildRuntimeTools(options) {
498
+ const providerTools = options.includeProviderTools
499
+ ? createProviderTools({
500
+ providerInfo: options.providerInfo,
501
+ customSettings: options.customSettings,
502
+ hasFunctionTools: Object.keys(options.functionTools).length > 0
503
+ })
504
+ : {};
505
+ return {
506
+ ...providerTools,
507
+ ...options.functionTools
508
+ };
509
+ }
479
510
  /**
480
511
  * Rebuild the agent using cached resources and the current skills snapshot.
481
512
  */
@@ -485,9 +516,21 @@ export class AgentManager {
485
516
  return;
486
517
  }
487
518
  const { model, tools, temperature, maxOutputTokens, maxTurns, baseSystemPrompt, shouldUseTools } = this._agentConfig;
488
- const instructions = shouldUseTools
489
- ? this._getEnhancedSystemPrompt(baseSystemPrompt)
519
+ const baseInstructions = shouldUseTools
520
+ ? this._getEnhancedSystemPrompt(baseSystemPrompt, tools)
490
521
  : baseSystemPrompt || 'You are a helpful assistant.';
522
+ const richOutputWorkflowInstruction = shouldUseTools
523
+ ? '- When the user asks for visual or rich outputs, prefer running code/commands that produce those outputs and describe that they will be rendered in chat.'
524
+ : '- When tools are unavailable, explain the limitation clearly and provide concrete steps the user can run to produce the desired rich outputs.';
525
+ const supportedMimeTypesInstruction = this._getSupportedMimeTypesInstruction();
526
+ const instructions = `${baseInstructions}
527
+
528
+ RICH OUTPUT RENDERING:
529
+ - The chat UI can render rich MIME outputs as separate assistant messages.
530
+ - ${supportedMimeTypesInstruction}
531
+ - Use only MIME types from the supported list when creating MIME bundles. Do not invent MIME keys.
532
+ - Do not claim that you cannot display maps, images, or rich outputs in chat.
533
+ ${richOutputWorkflowInstruction}`;
491
534
  this._agent = new ToolLoopAgent({
492
535
  model,
493
536
  instructions,
@@ -546,6 +589,12 @@ export class AgentManager {
546
589
  case 'tool-result':
547
590
  this._handleToolResult(part);
548
591
  break;
592
+ case 'tool-error':
593
+ this._handleToolError(part);
594
+ break;
595
+ case 'tool-output-denied':
596
+ this._handleToolOutputDenied(part);
597
+ break;
549
598
  case 'tool-approval-request':
550
599
  // Complete current message before approval
551
600
  if (currentMessageId && fullResponse) {
@@ -579,9 +628,6 @@ export class AgentManager {
579
628
  * Handles tool-result stream parts.
580
629
  */
581
630
  _handleToolResult(part) {
582
- const output = typeof part.output === 'string'
583
- ? part.output
584
- : JSON.stringify(part.output, null, 2);
585
631
  const isError = typeof part.output === 'object' &&
586
632
  part.output !== null &&
587
633
  'success' in part.output &&
@@ -591,11 +637,44 @@ export class AgentManager {
591
637
  data: {
592
638
  callId: part.toolCallId,
593
639
  toolName: part.toolName,
594
- output,
640
+ outputData: part.output,
595
641
  isError
596
642
  }
597
643
  });
598
644
  }
645
+ /**
646
+ * Handles tool-error stream parts.
647
+ */
648
+ _handleToolError(part) {
649
+ const output = typeof part.error === 'string'
650
+ ? part.error
651
+ : part.error instanceof Error
652
+ ? part.error.message
653
+ : JSON.stringify(part.error, null, 2);
654
+ this._agentEvent.emit({
655
+ type: 'tool_call_complete',
656
+ data: {
657
+ callId: part.toolCallId,
658
+ toolName: part.toolName,
659
+ outputData: output,
660
+ isError: true
661
+ }
662
+ });
663
+ }
664
+ /**
665
+ * Handles tool-output-denied stream parts.
666
+ */
667
+ _handleToolOutputDenied(part) {
668
+ this._agentEvent.emit({
669
+ type: 'tool_call_complete',
670
+ data: {
671
+ callId: part.toolCallId,
672
+ toolName: part.toolName,
673
+ outputData: 'Tool output was denied.',
674
+ isError: true
675
+ }
676
+ });
677
+ }
599
678
  /**
600
679
  * Handles tool-approval-request stream parts.
601
680
  */
@@ -681,8 +760,16 @@ export class AgentManager {
681
760
  const baseURL = activeProviderConfig.baseURL;
682
761
  let apiKey;
683
762
  if (this._secretsManager && this._settingsModel.config.useSecretsManager) {
684
- apiKey =
685
- (await this._secretsManager.get(Private.getToken(), SECRETS_NAMESPACE, `${provider}:apiKey`))?.value ?? '';
763
+ const token = Private.getToken();
764
+ if (!token) {
765
+ // This should never happen, the secrets manager should be disabled.
766
+ console.error('@jupyterlite/ai::AgentManager error: the settings manager token is not set.\nYou should disable the the secrets manager from the AI settings.');
767
+ apiKey = '';
768
+ }
769
+ else {
770
+ apiKey =
771
+ (await this._secretsManager.get(token, SECRETS_NAMESPACE, `${provider}:apiKey`))?.value ?? '';
772
+ }
686
773
  }
687
774
  else {
688
775
  apiKey = this._settingsModel.getApiKey(activeProviderConfig.id);
@@ -699,12 +786,11 @@ export class AgentManager {
699
786
  * @param baseSystemPrompt The base system prompt from settings
700
787
  * @returns The enhanced system prompt with dynamic additions
701
788
  */
702
- _getEnhancedSystemPrompt(baseSystemPrompt) {
703
- if (this._skills.length === 0) {
704
- return baseSystemPrompt;
705
- }
706
- const lines = this._skills.map(skill => `- ${skill.name}: ${skill.description}`);
707
- const skillsPrompt = `
789
+ _getEnhancedSystemPrompt(baseSystemPrompt, tools) {
790
+ let prompt = baseSystemPrompt;
791
+ if (this._skills.length > 0) {
792
+ const lines = this._skills.map(skill => `- ${skill.name}: ${skill.description}`);
793
+ const skillsPrompt = `
708
794
 
709
795
  AGENT SKILLS:
710
796
  Skills are provided via the skills registry and accessed through tools (not commands).
@@ -716,7 +802,41 @@ If the load_skill result includes a non-empty "resources" array, those are bundl
716
802
  AVAILABLE SKILLS (preloaded snapshot):
717
803
  ${lines.join('\n')}
718
804
  `;
719
- return baseSystemPrompt + skillsPrompt;
805
+ prompt += skillsPrompt;
806
+ }
807
+ const toolNames = new Set(Object.keys(tools));
808
+ const hasBrowserFetch = toolNames.has('browser_fetch');
809
+ const hasWebFetch = toolNames.has('web_fetch');
810
+ const hasWebSearch = toolNames.has('web_search');
811
+ if (hasBrowserFetch || hasWebFetch || hasWebSearch) {
812
+ const webRetrievalPrompt = `
813
+
814
+ WEB RETRIEVAL POLICY:
815
+ - If the user asks about a specific URL and browser_fetch is available, call browser_fetch first for that URL.
816
+ - If browser_fetch fails due to CORS/network/access, try web_fetch (if available) for that same URL.
817
+ - If web_fetch fails with access/policy errors (for example: url_not_accessible or url_not_allowed) and browser_fetch is available, you MUST call browser_fetch for that same URL before searching.
818
+ - If either fetch method fails with temporary access/network issues (for example: network_or_cors), try the other fetch method if available before searching.
819
+ - Only fall back to web_search after both fetch methods fail or are unavailable.
820
+ - If the user explicitly asks to inspect one exact URL, do not skip directly to search unless both fetch methods fail or are unavailable.
821
+ - In your final response, state which retrieval method succeeded (browser_fetch, web_fetch, or web_search) and mention relevant limitations.
822
+ `;
823
+ prompt += webRetrievalPrompt;
824
+ }
825
+ return prompt;
826
+ }
827
+ /**
828
+ * Build an instruction line describing MIME types supported by this session.
829
+ */
830
+ _getSupportedMimeTypesInstruction() {
831
+ const mimeTypes = this._renderMimeRegistry?.mimeTypes ?? [];
832
+ const safeMimeTypes = mimeTypes.filter(mimeType => {
833
+ const factory = this._renderMimeRegistry?.getFactory(mimeType);
834
+ return !!factory?.safe;
835
+ });
836
+ if (safeMimeTypes.length === 0) {
837
+ return 'Supported MIME types are determined by the active JupyterLab renderers in this session.';
838
+ }
839
+ return `Supported MIME types in this session: ${safeMimeTypes.join(', ')}`;
720
840
  }
721
841
  // Private attributes
722
842
  _settingsModel;
@@ -735,12 +855,29 @@ ${lines.join('\n')}
735
855
  _activeProvider = '';
736
856
  _activeProviderChanged = new Signal(this);
737
857
  _skills;
858
+ _renderMimeRegistry;
738
859
  _initQueue = Promise.resolve();
739
860
  _agentConfig;
740
861
  _pendingApprovals = new Map();
741
862
  }
742
863
  var Private;
743
864
  (function (Private) {
865
+ /**
866
+ * Keep only serializable messages by doing a JSON round-trip.
867
+ * Messages that cannot be serialized are dropped.
868
+ */
869
+ Private.sanitizeModelMessages = (messages) => {
870
+ const sanitized = [];
871
+ for (const message of messages) {
872
+ try {
873
+ sanitized.push(JSON.parse(JSON.stringify(message)));
874
+ }
875
+ catch {
876
+ // Drop messages that cannot be serialized
877
+ }
878
+ }
879
+ return sanitized;
880
+ };
744
881
  /**
745
882
  * The token to use with the secrets manager, setter and getter.
746
883
  */
@@ -3,33 +3,30 @@ import { TranslationBundle } from '@jupyterlab/translation';
3
3
  import { AgentManagerFactory } from './agent';
4
4
  import { AIChatModel } from './chat-model';
5
5
  import { AISettingsModel } from './models/settings-model';
6
- import { IChatModelRegistry, IProviderRegistry, ITokenUsage, IToolRegistry } from './tokens';
6
+ import { IChatModelHandler, IProviderRegistry, ITokenUsage, IToolRegistry } from './tokens';
7
7
  import { IDocumentManager } from '@jupyterlab/docmanager';
8
+ import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
8
9
  /**
9
- * The chat model registry.
10
+ * The chat model handler.
10
11
  */
11
- export declare class ChatModelRegistry implements IChatModelRegistry {
12
- constructor(options: ChatModelRegistry.IOptions);
13
- createModel(name?: string, activeProvider?: string, tokenUsage?: ITokenUsage): AIChatModel;
14
- add(model: AIChatModel): void;
15
- get(name: string): AIChatModel | undefined;
16
- getAll(): AIChatModel[];
17
- remove(name: string): void;
12
+ export declare class ChatModelHandler implements IChatModelHandler {
13
+ constructor(options: ChatModelHandler.IOptions);
14
+ createModel(name: string, activeProvider: string, tokenUsage?: ITokenUsage): AIChatModel;
18
15
  /**
19
16
  * Getter/setter for the active cell manager.
20
17
  */
21
18
  get activeCellManager(): ActiveCellManager | undefined;
22
19
  set activeCellManager(manager: ActiveCellManager | undefined);
23
- private _models;
24
20
  private _docManager;
25
21
  private _agentManagerFactory;
26
22
  private _settingsModel;
27
23
  private _toolRegistry?;
28
24
  private _providerRegistry?;
25
+ private _rmRegistry;
29
26
  private _activeCellManager?;
30
27
  private _trans;
31
28
  }
32
- export declare namespace ChatModelRegistry {
29
+ export declare namespace ChatModelHandler {
33
30
  interface IOptions {
34
31
  /**
35
32
  * The document manager.
@@ -51,6 +48,10 @@ export declare namespace ChatModelRegistry {
51
48
  * Optional provider registry for model creation
52
49
  */
53
50
  providerRegistry?: IProviderRegistry;
51
+ /**
52
+ * Render mime registry.
53
+ */
54
+ rmRegistry: IRenderMimeRegistry;
54
55
  /**
55
56
  * The active cell manager.
56
57
  */
@@ -1,15 +1,15 @@
1
1
  import { AIChatModel } from './chat-model';
2
- import { UUID } from '@lumino/coreutils';
3
2
  /**
4
- * The chat model registry.
3
+ * The chat model handler.
5
4
  */
6
- export class ChatModelRegistry {
5
+ export class ChatModelHandler {
7
6
  constructor(options) {
8
7
  this._docManager = options.docManager;
9
8
  this._agentManagerFactory = options.agentManagerFactory;
10
9
  this._settingsModel = options.settingsModel;
11
10
  this._toolRegistry = options.toolRegistry;
12
11
  this._providerRegistry = options.providerRegistry;
12
+ this._rmRegistry = options.rmRegistry;
13
13
  this._activeCellManager = options.activeCellManager;
14
14
  this._trans = options.trans;
15
15
  }
@@ -20,7 +20,8 @@ export class ChatModelRegistry {
20
20
  toolRegistry: this._toolRegistry,
21
21
  providerRegistry: this._providerRegistry,
22
22
  activeProvider,
23
- tokenUsage
23
+ tokenUsage,
24
+ renderMimeRegistry: this._rmRegistry
24
25
  });
25
26
  // Create AI chat model
26
27
  const model = new AIChatModel({
@@ -31,44 +32,9 @@ export class ChatModelRegistry {
31
32
  documentManager: this._docManager,
32
33
  trans: this._trans
33
34
  });
34
- // Set the name of the chat if not provided.
35
- // The name will be the name set by the user to the model if not already used by
36
- // another chat.
37
- if (!name || this._models.findIndex(m => m.name === name) !== -1) {
38
- const existingName = this.getAll().map(model => model.name);
39
- const modelName = this._settingsModel.getProvider(agentManager.activeProvider)?.name ||
40
- UUID.uuid4();
41
- name = modelName;
42
- let i = 1;
43
- while (existingName.includes(name)) {
44
- name = `${modelName}-${i}`;
45
- i += 1;
46
- }
47
- }
48
35
  model.name = name;
49
- this.add(model);
50
36
  return model;
51
37
  }
52
- add(model) {
53
- if (!this._models.find(m => m.name === model.name)) {
54
- this._models.push(model);
55
- model.disposed.connect(() => {
56
- this.remove(model.name);
57
- });
58
- }
59
- }
60
- get(name) {
61
- return this._models.find(m => m.name === name);
62
- }
63
- getAll() {
64
- return this._models;
65
- }
66
- remove(name) {
67
- const index = this._models.findIndex(m => m.name === name);
68
- if (index !== -1) {
69
- this._models.splice(index, 1);
70
- }
71
- }
72
38
  /**
73
39
  * Getter/setter for the active cell manager.
74
40
  */
@@ -78,12 +44,12 @@ export class ChatModelRegistry {
78
44
  set activeCellManager(manager) {
79
45
  this._activeCellManager = manager;
80
46
  }
81
- _models = [];
82
47
  _docManager;
83
48
  _agentManagerFactory;
84
49
  _settingsModel;
85
50
  _toolRegistry;
86
51
  _providerRegistry;
52
+ _rmRegistry;
87
53
  _activeCellManager;
88
54
  _trans;
89
55
  }
@@ -92,6 +92,10 @@ export declare class AIChatModel extends AbstractChatModel {
92
92
  * @returns A short summary string or empty string if none available
93
93
  */
94
94
  private _extractToolSummary;
95
+ /**
96
+ * Determine whether this tool call should auto-render trusted MIME bundles.
97
+ */
98
+ private _computeShouldAutoRenderMimeBundles;
95
99
  /**
96
100
  * Handles the start of a tool call execution.
97
101
  * @param event Event containing the tool call start data
@@ -101,6 +105,10 @@ export declare class AIChatModel extends AbstractChatModel {
101
105
  * Handles the completion of a tool call execution.
102
106
  */
103
107
  private _handleToolCallCompleteEvent;
108
+ /**
109
+ * Determine whether a tool call output should auto-render MIME bundles.
110
+ */
111
+ private _shouldAutoRenderMimeBundles;
104
112
  /**
105
113
  * Handles error events from the AI agent.
106
114
  */