@jupyterlite/ai 0.14.0 → 0.15.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 (52) hide show
  1. package/lib/agent.d.ts +28 -114
  2. package/lib/agent.js +140 -100
  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 +208 -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/model-select.d.ts +3 -3
  10. package/lib/components/save-button.d.ts +31 -0
  11. package/lib/components/save-button.js +41 -0
  12. package/lib/components/token-usage-display.d.ts +2 -3
  13. package/lib/components/tool-select.d.ts +3 -4
  14. package/lib/diff-manager.d.ts +2 -3
  15. package/lib/index.d.ts +2 -4
  16. package/lib/index.js +181 -23
  17. package/lib/models/settings-model.d.ts +11 -53
  18. package/lib/models/settings-model.js +37 -22
  19. package/lib/providers/built-in-providers.js +17 -36
  20. package/lib/tokens.d.ts +340 -36
  21. package/lib/tokens.js +11 -6
  22. package/lib/tools/commands.d.ts +2 -3
  23. package/lib/widgets/ai-settings.d.ts +3 -5
  24. package/lib/widgets/ai-settings.js +3 -0
  25. package/lib/widgets/main-area-chat.d.ts +2 -3
  26. package/lib/widgets/main-area-chat.js +9 -9
  27. package/lib/widgets/provider-config-dialog.d.ts +1 -2
  28. package/lib/widgets/provider-config-dialog.js +16 -29
  29. package/package.json +15 -9
  30. package/schema/settings-model.json +7 -1
  31. package/src/agent.ts +197 -242
  32. package/src/chat-model-handler.ts +25 -21
  33. package/src/chat-model.ts +304 -196
  34. package/src/completion/completion-provider.ts +7 -4
  35. package/src/components/completion-status.tsx +3 -3
  36. package/src/components/model-select.tsx +4 -3
  37. package/src/components/save-button.tsx +84 -0
  38. package/src/components/token-usage-display.tsx +2 -3
  39. package/src/components/tool-select.tsx +10 -4
  40. package/src/diff-manager.ts +4 -4
  41. package/src/index.ts +245 -49
  42. package/src/models/settings-model.ts +45 -88
  43. package/src/providers/built-in-providers.ts +17 -36
  44. package/src/tokens.ts +406 -52
  45. package/src/tools/commands.ts +2 -3
  46. package/src/widgets/ai-settings.tsx +27 -15
  47. package/src/widgets/main-area-chat.ts +15 -12
  48. package/src/widgets/provider-config-dialog.tsx +51 -56
  49. package/style/base.css +17 -195
  50. package/lib/approval-buttons.d.ts +0 -49
  51. package/lib/approval-buttons.js +0 -79
  52. package/src/approval-buttons.ts +0 -115
package/lib/agent.d.ts CHANGED
@@ -1,17 +1,16 @@
1
+ import type { IMessageContent } from '@jupyter/chat';
1
2
  import { ISignal } from '@lumino/signaling';
2
- import { type Tool } from 'ai';
3
3
  import { ISecretsManager } from 'jupyter-secrets-manager';
4
- import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
5
- import { AISettingsModel } from './models/settings-model';
6
- import type { IProviderRegistry } from './tokens';
7
- import { ISkillRegistry, ITool, IToolRegistry, ITokenUsage } from './tokens';
8
- type ToolMap = Record<string, Tool>;
4
+ import { type IAgentManager, type IAgentManagerFactory, type IAISettingsModel, type ISkillRegistry, type ITokenUsage, type ToolMap } from './tokens';
5
+ /**
6
+ * The agent manager factory namespace.
7
+ */
9
8
  export declare namespace AgentManagerFactory {
10
9
  interface IOptions {
11
10
  /**
12
11
  * The settings model.
13
12
  */
14
- settingsModel: AISettingsModel;
13
+ settingsModel: IAISettingsModel;
15
14
  /**
16
15
  * The skill registry for discovering skills.
17
16
  */
@@ -26,15 +25,21 @@ export declare namespace AgentManagerFactory {
26
25
  token: symbol | null;
27
26
  }
28
27
  }
29
- export declare class AgentManagerFactory {
28
+ /**
29
+ * The agent manager factory.
30
+ */
31
+ export declare class AgentManagerFactory implements IAgentManagerFactory {
30
32
  constructor(options: AgentManagerFactory.IOptions);
31
- createAgent(options: IAgentManagerOptions): AgentManager;
33
+ /**
34
+ * Create a new agent.
35
+ */
36
+ createAgent(options: IAgentManager.IOptions): IAgentManager;
32
37
  /**
33
38
  * Signal emitted when MCP connection status changes
34
39
  */
35
40
  get mcpConnectionChanged(): ISignal<this, boolean>;
36
41
  /**
37
- * Checks if a specific MCP server is connected by server name.
42
+ * Checks whether a specific MCP server is connected.
38
43
  * @param serverName The name of the MCP server to check
39
44
  * @returns True if the server is connected, false otherwise
40
45
  */
@@ -69,107 +74,22 @@ export declare class AgentManagerFactory {
69
74
  private _mcpConnectionChanged;
70
75
  private _initQueue;
71
76
  }
72
- /**
73
- * Event type mapping for type safety with inlined interface definitions
74
- */
75
- export interface IAgentEventTypeMap {
76
- message_start: {
77
- messageId: string;
78
- };
79
- message_chunk: {
80
- messageId: string;
81
- chunk: string;
82
- fullContent: string;
83
- };
84
- message_complete: {
85
- messageId: string;
86
- content: string;
87
- };
88
- tool_call_start: {
89
- callId: string;
90
- toolName: string;
91
- input: string;
92
- };
93
- tool_call_complete: {
94
- callId: string;
95
- toolName: string;
96
- outputData: unknown;
97
- isError: boolean;
98
- };
99
- tool_approval_request: {
100
- approvalId: string;
101
- toolCallId: string;
102
- toolName: string;
103
- args: unknown;
104
- };
105
- tool_approval_resolved: {
106
- approvalId: string;
107
- approved: boolean;
108
- };
109
- error: {
110
- error: Error;
111
- };
112
- }
113
- /**
114
- * Events emitted by the AgentManager
115
- */
116
- export type IAgentEvent<T extends keyof IAgentEventTypeMap = keyof IAgentEventTypeMap> = T extends keyof IAgentEventTypeMap ? {
117
- type: T;
118
- data: IAgentEventTypeMap[T];
119
- } : never;
120
- /**
121
- * Configuration options for the AgentManager
122
- */
123
- export interface IAgentManagerOptions {
124
- /**
125
- * AI settings model for configuration
126
- */
127
- settingsModel: AISettingsModel;
128
- /**
129
- * Optional tool registry for managing available tools
130
- */
131
- toolRegistry?: IToolRegistry;
132
- /**
133
- * Optional provider registry for model creation
134
- */
135
- providerRegistry?: IProviderRegistry;
136
- /**
137
- * The skill registry for discovering skills.
138
- */
139
- skillRegistry?: ISkillRegistry;
140
- /**
141
- * The secrets manager.
142
- */
143
- secretsManager?: ISecretsManager;
144
- /**
145
- * The active provider to use with this agent.
146
- */
147
- activeProvider?: string;
148
- /**
149
- * Initial token usage.
150
- */
151
- tokenUsage?: ITokenUsage;
152
- /**
153
- * JupyterLab render mime registry for discovering supported MIME types.
154
- */
155
- renderMimeRegistry?: IRenderMimeRegistry;
156
- }
157
77
  /**
158
78
  * Manages the AI agent lifecycle and execution loop.
159
79
  * Provides agent initialization, tool management, MCP server integration,
160
80
  * and handles the complete agent execution cycle.
161
81
  * Emits events for UI updates instead of directly manipulating the chat interface.
162
82
  */
163
- export declare class AgentManager {
83
+ export declare class AgentManager implements IAgentManager {
164
84
  /**
165
85
  * Creates a new AgentManager instance.
166
86
  * @param options Configuration options for the agent manager
167
87
  */
168
- constructor(options: IAgentManagerOptions);
88
+ constructor(options: IAgentManager.IOptions);
169
89
  /**
170
90
  * Signal emitted when agent events occur
171
91
  */
172
- get agentEvent(): ISignal<this, IAgentEvent>;
92
+ get agentEvent(): ISignal<this, IAgentManager.IAgentEvent>;
173
93
  /**
174
94
  * Signal emitted when the active provider has changed.
175
95
  */
@@ -200,7 +120,7 @@ export declare class AgentManager {
200
120
  * Gets the currently selected tools as a record.
201
121
  * @returns Record of selected tools
202
122
  */
203
- get selectedAgentTools(): Record<string, ITool>;
123
+ get selectedAgentTools(): ToolMap;
204
124
  /**
205
125
  * Checks if the current configuration is valid for agent operations.
206
126
  * Uses the provider registry to determine if an API key is required.
@@ -210,11 +130,17 @@ export declare class AgentManager {
210
130
  /**
211
131
  * Clears conversation history and resets agent state.
212
132
  */
213
- clearHistory(): void;
133
+ clearHistory(): Promise<void>;
134
+ /**
135
+ * Sets the history with a list of messages from the chat.
136
+ * @param messages The chat messages to set as history
137
+ */
138
+ setHistory(messages: IMessageContent[]): void;
214
139
  /**
215
140
  * Stops the current streaming response by aborting the request.
141
+ * Resolve any pending approval.
216
142
  */
217
- stopStreaming(): void;
143
+ stopStreaming(reason?: string): void;
218
144
  /**
219
145
  * Approves a pending tool call.
220
146
  * @param approvalId The approval ID to approve
@@ -317,18 +243,6 @@ export declare class AgentManager {
317
243
  * Build an instruction line describing MIME types supported by this session.
318
244
  */
319
245
  private _getSupportedMimeTypesInstruction;
320
- /**
321
- * Sanitizes history to ensure it's in a valid state in case of abort or error.
322
- */
323
- private _sanitizeHistory;
324
- /**
325
- * Extracts tool call IDs from a message
326
- */
327
- private _getToolCallIds;
328
- /**
329
- * Checks if a tool message contains results for all specified tool call IDs
330
- */
331
- private _matchesAllToolCalls;
332
246
  private _settingsModel;
333
247
  private _toolRegistry?;
334
248
  private _providerRegistry?;
@@ -349,5 +263,5 @@ export declare class AgentManager {
349
263
  private _initQueue;
350
264
  private _agentConfig;
351
265
  private _pendingApprovals;
266
+ private _streaming;
352
267
  }
353
- export {};
package/lib/agent.js CHANGED
@@ -1,9 +1,13 @@
1
+ import { createMCPClient } from '@ai-sdk/mcp';
2
+ import { PromiseDelegate } from '@lumino/coreutils';
1
3
  import { Signal } from '@lumino/signaling';
2
4
  import { ToolLoopAgent, stepCountIs } from 'ai';
3
- import { createMCPClient } from '@ai-sdk/mcp';
4
5
  import { createModel } from './providers/models';
5
6
  import { createProviderTools } from './providers/provider-tools';
6
7
  import { SECRETS_NAMESPACE } from './tokens';
8
+ /**
9
+ * The agent manager factory.
10
+ */
7
11
  export class AgentManagerFactory {
8
12
  constructor(options) {
9
13
  Private.setToken(options.token);
@@ -26,6 +30,9 @@ export class AgentManagerFactory {
26
30
  this._secretsManager = undefined;
27
31
  }
28
32
  }
33
+ /**
34
+ * Create a new agent.
35
+ */
29
36
  createAgent(options) {
30
37
  const agentManager = new AgentManager({
31
38
  ...options,
@@ -52,7 +59,7 @@ export class AgentManagerFactory {
52
59
  return this._mcpConnectionChanged;
53
60
  }
54
61
  /**
55
- * Checks if a specific MCP server is connected by server name.
62
+ * Checks whether a specific MCP server is connected.
56
63
  * @param serverName The name of the MCP server to check
57
64
  * @returns True if the server is connected, false otherwise
58
65
  */
@@ -196,6 +203,7 @@ export class AgentManager {
196
203
  this._skills = [];
197
204
  this._agentConfig = null;
198
205
  this._renderMimeRegistry = options.renderMimeRegistry;
206
+ this._streaming.resolve();
199
207
  this.activeProvider =
200
208
  options.activeProvider ?? this._settingsModel.config.defaultProvider;
201
209
  // Initialize selected tools to all available tools by default
@@ -301,28 +309,55 @@ export class AgentManager {
301
309
  /**
302
310
  * Clears conversation history and resets agent state.
303
311
  */
304
- clearHistory() {
312
+ async clearHistory() {
305
313
  // Stop any ongoing streaming
314
+ this.stopStreaming('Chat cleared');
315
+ await this._streaming.promise;
316
+ // Clear history and token usage
317
+ this._history = [];
318
+ this._tokenUsage = { inputTokens: 0, outputTokens: 0 };
319
+ this._tokenUsageChanged.emit(this._tokenUsage);
320
+ }
321
+ /**
322
+ * Sets the history with a list of messages from the chat.
323
+ * @param messages The chat messages to set as history
324
+ */
325
+ setHistory(messages) {
326
+ // Stop any ongoing streaming and reject awaiting approvals
306
327
  this.stopStreaming();
307
- // Reject any pending approvals
308
328
  for (const [approvalId, pending] of this._pendingApprovals) {
309
- pending.resolve(false, 'Chat cleared');
329
+ pending.resolve(false, 'Chat history changed');
310
330
  this._agentEvent.emit({
311
331
  type: 'tool_approval_resolved',
312
332
  data: { approvalId, approved: false }
313
333
  });
314
334
  }
315
335
  this._pendingApprovals.clear();
316
- // Clear history and token usage
317
- this._history = [];
318
- this._tokenUsage = { inputTokens: 0, outputTokens: 0 };
319
- this._tokenUsageChanged.emit(this._tokenUsage);
336
+ // Convert chat messages to model messages
337
+ const modelMessages = messages.map(msg => {
338
+ const isAIMessage = msg.sender.username === 'ai-assistant';
339
+ return {
340
+ role: isAIMessage ? 'assistant' : 'user',
341
+ content: msg.body
342
+ };
343
+ });
344
+ this._history = Private.sanitizeModelMessages(modelMessages);
320
345
  }
321
346
  /**
322
347
  * Stops the current streaming response by aborting the request.
348
+ * Resolve any pending approval.
323
349
  */
324
- stopStreaming() {
350
+ stopStreaming(reason) {
325
351
  this._controller?.abort();
352
+ // Reject any pending approvals
353
+ for (const [approvalId, pending] of this._pendingApprovals) {
354
+ pending.resolve(false, reason ?? 'Stream ended by user');
355
+ this._agentEvent.emit({
356
+ type: 'tool_approval_resolved',
357
+ data: { approvalId, approved: false }
358
+ });
359
+ }
360
+ this._pendingApprovals.clear();
326
361
  }
327
362
  /**
328
363
  * Approves a pending tool call.
@@ -362,7 +397,9 @@ export class AgentManager {
362
397
  * @param message The user message to respond to (may include processed attachment content)
363
398
  */
364
399
  async generateResponse(message) {
400
+ this._streaming = new PromiseDelegate();
365
401
  this._controller = new AbortController();
402
+ const responseHistory = [];
366
403
  try {
367
404
  // Ensure we have an agent
368
405
  if (!this._agent) {
@@ -372,14 +409,14 @@ export class AgentManager {
372
409
  throw new Error('Failed to initialize agent');
373
410
  }
374
411
  // Add user message to history
375
- this._history.push({
412
+ responseHistory.push({
376
413
  role: 'user',
377
414
  content: message
378
415
  });
379
416
  let continueLoop = true;
380
417
  while (continueLoop) {
381
418
  const result = await this._agent.stream({
382
- messages: this._history,
419
+ messages: [...this._history, ...responseHistory],
383
420
  abortSignal: this._controller.signal
384
421
  });
385
422
  const streamResult = await this._processStreamResult(result);
@@ -388,12 +425,12 @@ export class AgentManager {
388
425
  this._updateTokenUsage(await result.usage);
389
426
  // Add response messages to history
390
427
  if (responseMessages.messages?.length) {
391
- this._history.push(...Private.sanitizeModelMessages(responseMessages.messages));
428
+ responseHistory.push(...responseMessages.messages);
392
429
  }
393
430
  // Add approval response if processed
394
431
  if (streamResult.approvalResponse) {
395
432
  // Check if the last message is a tool message we can append to
396
- const lastMsg = this._history[this._history.length - 1];
433
+ const lastMsg = responseHistory[responseHistory.length - 1];
397
434
  if (lastMsg &&
398
435
  lastMsg.role === 'tool' &&
399
436
  Array.isArray(lastMsg.content) &&
@@ -403,11 +440,13 @@ export class AgentManager {
403
440
  }
404
441
  else {
405
442
  // Add as separate message
406
- this._history.push(streamResult.approvalResponse);
443
+ responseHistory.push(streamResult.approvalResponse);
407
444
  }
408
445
  }
409
446
  continueLoop = streamResult.approvalProcessed;
410
447
  }
448
+ // Add the messages to the history only if the response ended without error.
449
+ this._history.push(...Private.sanitizeModelMessages(responseHistory));
411
450
  }
412
451
  catch (error) {
413
452
  if (error.name !== 'AbortError') {
@@ -416,12 +455,10 @@ export class AgentManager {
416
455
  data: { error: error }
417
456
  });
418
457
  }
419
- // After an error (including AbortError), sanitize the history
420
- // to remove any trailing assistant messages without tool results
421
- this._sanitizeHistory();
422
458
  }
423
459
  finally {
424
460
  this._controller = null;
461
+ this._streaming.resolve();
425
462
  }
426
463
  }
427
464
  /**
@@ -851,81 +888,6 @@ WEB RETRIEVAL POLICY:
851
888
  }
852
889
  return `Supported MIME types in this session: ${safeMimeTypes.join(', ')}`;
853
890
  }
854
- /**
855
- * Sanitizes history to ensure it's in a valid state in case of abort or error.
856
- */
857
- _sanitizeHistory() {
858
- if (this._history.length === 0) {
859
- return;
860
- }
861
- const newHistory = [];
862
- for (let i = 0; i < this._history.length; i++) {
863
- const msg = this._history[i];
864
- if (msg.role === 'assistant') {
865
- const toolCallIds = this._getToolCallIds(msg);
866
- if (toolCallIds.length > 0) {
867
- // Find if there's a following tool message with results for these calls
868
- const nextMsg = this._history[i + 1];
869
- if (nextMsg &&
870
- nextMsg.role === 'tool' &&
871
- this._matchesAllToolCalls(nextMsg, toolCallIds)) {
872
- newHistory.push(msg);
873
- }
874
- else {
875
- // Message has unmatched tool calls drop it and everything after it
876
- break;
877
- }
878
- }
879
- else {
880
- newHistory.push(msg);
881
- }
882
- }
883
- else if (msg.role === 'tool') {
884
- // Tool messages are valid if they were preceded by a valid assistant message
885
- newHistory.push(msg);
886
- }
887
- else {
888
- newHistory.push(msg);
889
- }
890
- }
891
- this._history = newHistory;
892
- }
893
- /**
894
- * Extracts tool call IDs from a message
895
- */
896
- _getToolCallIds(message) {
897
- const ids = [];
898
- // Check content array for tool-call parts
899
- if (Array.isArray(message.content)) {
900
- for (const part of message.content) {
901
- if (typeof part === 'object' &&
902
- part !== null &&
903
- 'type' in part &&
904
- part.type === 'tool-call') {
905
- ids.push(part.toolCallId);
906
- }
907
- }
908
- }
909
- return ids;
910
- }
911
- /**
912
- * Checks if a tool message contains results for all specified tool call IDs
913
- */
914
- _matchesAllToolCalls(message, callIds) {
915
- if (message.role !== 'tool' || !Array.isArray(message.content)) {
916
- return false;
917
- }
918
- const resultIds = new Set();
919
- for (const part of message.content) {
920
- if (typeof part === 'object' &&
921
- part !== null &&
922
- 'type' in part &&
923
- part.type === 'tool-result') {
924
- resultIds.add(part.toolCallId);
925
- }
926
- }
927
- return callIds.every(id => resultIds.has(id));
928
- }
929
891
  // Private attributes
930
892
  _settingsModel;
931
893
  _toolRegistry;
@@ -947,24 +909,102 @@ WEB RETRIEVAL POLICY:
947
909
  _initQueue = Promise.resolve();
948
910
  _agentConfig;
949
911
  _pendingApprovals = new Map();
912
+ _streaming = new PromiseDelegate();
950
913
  }
951
914
  var Private;
952
915
  (function (Private) {
953
916
  /**
954
- * Keep only serializable messages by doing a JSON round-trip.
955
- * Messages that cannot be serialized are dropped.
917
+ * Sanitize the messages before adding them to the history.
918
+ *
919
+ * 1- Make sure the message sequence is not altered:
920
+ * - tool-call messages should have a corresponding tool-result (and vice-versa)
921
+ * - tool-approval-request should have a tool-approval-response (and vice-versa)
922
+ *
923
+ * 2- Keep only serializable messages by doing a JSON round-trip.
924
+ * Messages that cannot be serialized are dropped.
956
925
  */
957
926
  Private.sanitizeModelMessages = (messages) => {
958
927
  const sanitized = [];
959
928
  for (const message of messages) {
960
- try {
961
- sanitized.push(JSON.parse(JSON.stringify(message)));
929
+ if (message.role === 'assistant') {
930
+ let newMessage;
931
+ if (!Array.isArray(message.content)) {
932
+ newMessage = message;
933
+ }
934
+ else {
935
+ // Remove assistant message content without a required response.
936
+ const newContent = [];
937
+ for (const assistantContent of message.content) {
938
+ let isContentValid = true;
939
+ if (assistantContent.type === 'tool-call') {
940
+ const toolCallId = assistantContent.toolCallId;
941
+ isContentValid = !!messages.find(msg => msg.role === 'tool' &&
942
+ Array.isArray(msg.content) &&
943
+ msg.content.find(content => content.type === 'tool-result' &&
944
+ content.toolCallId === toolCallId));
945
+ }
946
+ else if (assistantContent.type === 'tool-approval-request') {
947
+ const approvalId = assistantContent.approvalId;
948
+ isContentValid = !!messages.find(msg => msg.role === 'tool' &&
949
+ Array.isArray(msg.content) &&
950
+ msg.content.find(content => content.type === 'tool-approval-response' &&
951
+ content.approvalId === approvalId));
952
+ }
953
+ if (isContentValid) {
954
+ newContent.push(assistantContent);
955
+ }
956
+ }
957
+ if (newContent.length) {
958
+ newMessage = { ...message, content: newContent };
959
+ }
960
+ }
961
+ if (newMessage) {
962
+ try {
963
+ sanitized.push(JSON.parse(JSON.stringify(newMessage)));
964
+ }
965
+ catch {
966
+ // Drop messages that cannot be serialized
967
+ }
968
+ }
962
969
  }
963
- catch {
964
- // Drop messages that cannot be serialized
970
+ else if (message.role === 'tool') {
971
+ // Remove tool message content without request.
972
+ const newContent = [];
973
+ for (const toolContent of message.content) {
974
+ let isContentValid = true;
975
+ if (toolContent.type === 'tool-result') {
976
+ const toolCallId = toolContent.toolCallId;
977
+ isContentValid = !!sanitized.find(msg => msg.role === 'assistant' &&
978
+ Array.isArray(msg.content) &&
979
+ msg.content.find(content => content.type === 'tool-call' &&
980
+ content.toolCallId === toolCallId));
981
+ }
982
+ else if (toolContent.type === 'tool-approval-response') {
983
+ const approvalId = toolContent.approvalId;
984
+ isContentValid = !!sanitized.find(msg => msg.role === 'assistant' &&
985
+ Array.isArray(msg.content) &&
986
+ msg.content.find(content => content.type === 'tool-approval-request' &&
987
+ content.approvalId === approvalId));
988
+ }
989
+ if (isContentValid) {
990
+ newContent.push(toolContent);
991
+ }
992
+ }
993
+ if (newContent.length) {
994
+ try {
995
+ sanitized.push(JSON.parse(JSON.stringify({ ...message, content: newContent })));
996
+ }
997
+ catch {
998
+ // Drop messages that cannot be serialized
999
+ }
1000
+ }
1001
+ }
1002
+ else {
1003
+ // Message is a system or user message.
1004
+ sanitized.push(message);
965
1005
  }
966
1006
  }
967
- return sanitized;
1007
+ return sanitized.length === messages.length ? sanitized : [];
968
1008
  };
969
1009
  /**
970
1010
  * The token to use with the secrets manager, setter and getter.
@@ -1,17 +1,15 @@
1
1
  import { ActiveCellManager } from '@jupyter/chat';
2
- import { TranslationBundle } from '@jupyterlab/translation';
3
- import { AgentManagerFactory } from './agent';
4
- import { AIChatModel } from './chat-model';
5
- import { AISettingsModel } from './models/settings-model';
6
- import { IChatModelHandler, IProviderRegistry, ITokenUsage, IToolRegistry } from './tokens';
7
2
  import { IDocumentManager } from '@jupyterlab/docmanager';
8
3
  import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
4
+ import { Contents } from '@jupyterlab/services';
5
+ import { AIChatModel } from './chat-model';
6
+ import type { IAgentManagerFactory, IAISettingsModel, IChatModelHandler, ICreateChatOptions, IProviderRegistry, IToolRegistry } from './tokens';
9
7
  /**
10
8
  * The chat model handler.
11
9
  */
12
10
  export declare class ChatModelHandler implements IChatModelHandler {
13
11
  constructor(options: ChatModelHandler.IOptions);
14
- createModel(name: string, activeProvider: string, tokenUsage?: ITokenUsage): AIChatModel;
12
+ createModel(options: ICreateChatOptions): AIChatModel;
15
13
  /**
16
14
  * Getter/setter for the active cell manager.
17
15
  */
@@ -24,7 +22,7 @@ export declare class ChatModelHandler implements IChatModelHandler {
24
22
  private _providerRegistry?;
25
23
  private _rmRegistry;
26
24
  private _activeCellManager?;
27
- private _trans;
25
+ private _contentsManager?;
28
26
  }
29
27
  export declare namespace ChatModelHandler {
30
28
  interface IOptions {
@@ -35,11 +33,11 @@ export declare namespace ChatModelHandler {
35
33
  /**
36
34
  * The agent manager factory.
37
35
  */
38
- agentManagerFactory: AgentManagerFactory;
36
+ agentManagerFactory: IAgentManagerFactory;
39
37
  /**
40
38
  * AI settings model for configuration
41
39
  */
42
- settingsModel: AISettingsModel;
40
+ settingsModel: IAISettingsModel;
43
41
  /**
44
42
  * Optional tool registry for managing available tools
45
43
  */
@@ -57,8 +55,8 @@ export declare namespace ChatModelHandler {
57
55
  */
58
56
  activeCellManager?: ActiveCellManager | undefined;
59
57
  /**
60
- * The application language translation bundle.
58
+ * The contents manager.
61
59
  */
62
- trans: TranslationBundle;
60
+ contentsManager?: Contents.IManager;
63
61
  }
64
62
  }
@@ -11,9 +11,10 @@ export class ChatModelHandler {
11
11
  this._providerRegistry = options.providerRegistry;
12
12
  this._rmRegistry = options.rmRegistry;
13
13
  this._activeCellManager = options.activeCellManager;
14
- this._trans = options.trans;
14
+ this._contentsManager = options.contentsManager;
15
15
  }
16
- createModel(name, activeProvider, tokenUsage) {
16
+ createModel(options) {
17
+ const { name, activeProvider, tokenUsage, messages, autosave } = options;
17
18
  // Create Agent Manager first so it can be shared
18
19
  const agentManager = this._agentManagerFactory.createAgent({
19
20
  settingsModel: this._settingsModel,
@@ -30,8 +31,12 @@ export class ChatModelHandler {
30
31
  agentManager,
31
32
  activeCellManager: this._activeCellManager,
32
33
  documentManager: this._docManager,
33
- trans: this._trans
34
+ contentsManager: this._contentsManager
34
35
  });
36
+ messages?.forEach(message => {
37
+ model.messageAdded({ ...message.content });
38
+ });
39
+ model.autosave = autosave ?? false;
35
40
  model.name = name;
36
41
  return model;
37
42
  }
@@ -51,5 +56,5 @@ export class ChatModelHandler {
51
56
  _providerRegistry;
52
57
  _rmRegistry;
53
58
  _activeCellManager;
54
- _trans;
59
+ _contentsManager;
55
60
  }