@jupyterlite/ai 0.13.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.
- package/lib/agent.d.ts +28 -102
- package/lib/agent.js +150 -22
- package/lib/chat-model-handler.d.ts +9 -11
- package/lib/chat-model-handler.js +9 -4
- package/lib/chat-model.d.ts +84 -13
- package/lib/chat-model.js +208 -136
- package/lib/completion/completion-provider.d.ts +2 -3
- package/lib/components/completion-status.d.ts +2 -2
- package/lib/components/model-select.d.ts +3 -3
- package/lib/components/save-button.d.ts +31 -0
- package/lib/components/save-button.js +41 -0
- package/lib/components/token-usage-display.d.ts +2 -3
- package/lib/components/tool-select.d.ts +3 -4
- package/lib/diff-manager.d.ts +2 -3
- package/lib/index.d.ts +2 -4
- package/lib/index.js +306 -78
- package/lib/models/settings-model.d.ts +11 -53
- package/lib/models/settings-model.js +37 -22
- package/lib/providers/built-in-providers.js +29 -54
- package/lib/tokens.d.ts +351 -26
- package/lib/tokens.js +11 -6
- package/lib/tools/commands.d.ts +2 -3
- package/lib/tools/commands.js +58 -20
- package/lib/widgets/ai-settings.d.ts +6 -13
- package/lib/widgets/ai-settings.js +18 -48
- package/lib/widgets/main-area-chat.d.ts +2 -3
- package/lib/widgets/main-area-chat.js +9 -9
- package/lib/widgets/provider-config-dialog.d.ts +1 -2
- package/lib/widgets/provider-config-dialog.js +21 -37
- package/package.json +15 -9
- package/schema/settings-model.json +7 -1
- package/src/agent.ts +211 -149
- package/src/chat-model-handler.ts +25 -21
- package/src/chat-model.ts +304 -196
- package/src/completion/completion-provider.ts +7 -4
- package/src/components/completion-status.tsx +3 -3
- package/src/components/model-select.tsx +4 -3
- package/src/components/save-button.tsx +84 -0
- package/src/components/token-usage-display.tsx +2 -3
- package/src/components/tool-select.tsx +10 -4
- package/src/diff-manager.ts +4 -4
- package/src/index.ts +451 -151
- package/src/models/settings-model.ts +45 -88
- package/src/providers/built-in-providers.ts +29 -54
- package/src/tokens.ts +418 -35
- package/src/tools/commands.ts +97 -32
- package/src/widgets/ai-settings.tsx +45 -83
- package/src/widgets/main-area-chat.ts +15 -12
- package/src/widgets/provider-config-dialog.tsx +59 -64
- package/style/base.css +17 -195
- package/lib/approval-buttons.d.ts +0 -49
- package/lib/approval-buttons.js +0 -79
- 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 {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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:
|
|
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
|
-
|
|
28
|
+
/**
|
|
29
|
+
* The agent manager factory.
|
|
30
|
+
*/
|
|
31
|
+
export declare class AgentManagerFactory implements IAgentManagerFactory {
|
|
30
32
|
constructor(options: AgentManagerFactory.IOptions);
|
|
31
|
-
|
|
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
|
|
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:
|
|
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():
|
|
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
|
|
@@ -337,5 +263,5 @@ export declare class AgentManager {
|
|
|
337
263
|
private _initQueue;
|
|
338
264
|
private _agentConfig;
|
|
339
265
|
private _pendingApprovals;
|
|
266
|
+
private _streaming;
|
|
340
267
|
}
|
|
341
|
-
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,
|
|
@@ -33,6 +40,16 @@ export class AgentManagerFactory {
|
|
|
33
40
|
secretsManager: this._secretsManager
|
|
34
41
|
});
|
|
35
42
|
this._agentManagers.push(agentManager);
|
|
43
|
+
// New chats can be created before MCP setup finishes.
|
|
44
|
+
// Reinitialize them with connected MCP tools once it does.
|
|
45
|
+
this._initQueue
|
|
46
|
+
.then(() => this.getMCPTools())
|
|
47
|
+
.then(mcpTools => {
|
|
48
|
+
if (Object.keys(mcpTools).length > 0) {
|
|
49
|
+
agentManager.initializeAgent(mcpTools);
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
.catch(error => console.warn('Failed to pass MCP tools to new agent:', error));
|
|
36
53
|
return agentManager;
|
|
37
54
|
}
|
|
38
55
|
/**
|
|
@@ -42,7 +59,7 @@ export class AgentManagerFactory {
|
|
|
42
59
|
return this._mcpConnectionChanged;
|
|
43
60
|
}
|
|
44
61
|
/**
|
|
45
|
-
* Checks
|
|
62
|
+
* Checks whether a specific MCP server is connected.
|
|
46
63
|
* @param serverName The name of the MCP server to check
|
|
47
64
|
* @returns True if the server is connected, false otherwise
|
|
48
65
|
*/
|
|
@@ -186,6 +203,7 @@ export class AgentManager {
|
|
|
186
203
|
this._skills = [];
|
|
187
204
|
this._agentConfig = null;
|
|
188
205
|
this._renderMimeRegistry = options.renderMimeRegistry;
|
|
206
|
+
this._streaming.resolve();
|
|
189
207
|
this.activeProvider =
|
|
190
208
|
options.activeProvider ?? this._settingsModel.config.defaultProvider;
|
|
191
209
|
// Initialize selected tools to all available tools by default
|
|
@@ -291,28 +309,55 @@ export class AgentManager {
|
|
|
291
309
|
/**
|
|
292
310
|
* Clears conversation history and resets agent state.
|
|
293
311
|
*/
|
|
294
|
-
clearHistory() {
|
|
312
|
+
async clearHistory() {
|
|
295
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
|
|
296
327
|
this.stopStreaming();
|
|
297
|
-
// Reject any pending approvals
|
|
298
328
|
for (const [approvalId, pending] of this._pendingApprovals) {
|
|
299
|
-
pending.resolve(false, 'Chat
|
|
329
|
+
pending.resolve(false, 'Chat history changed');
|
|
300
330
|
this._agentEvent.emit({
|
|
301
331
|
type: 'tool_approval_resolved',
|
|
302
332
|
data: { approvalId, approved: false }
|
|
303
333
|
});
|
|
304
334
|
}
|
|
305
335
|
this._pendingApprovals.clear();
|
|
306
|
-
//
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
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);
|
|
310
345
|
}
|
|
311
346
|
/**
|
|
312
347
|
* Stops the current streaming response by aborting the request.
|
|
348
|
+
* Resolve any pending approval.
|
|
313
349
|
*/
|
|
314
|
-
stopStreaming() {
|
|
350
|
+
stopStreaming(reason) {
|
|
315
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();
|
|
316
361
|
}
|
|
317
362
|
/**
|
|
318
363
|
* Approves a pending tool call.
|
|
@@ -352,7 +397,9 @@ export class AgentManager {
|
|
|
352
397
|
* @param message The user message to respond to (may include processed attachment content)
|
|
353
398
|
*/
|
|
354
399
|
async generateResponse(message) {
|
|
400
|
+
this._streaming = new PromiseDelegate();
|
|
355
401
|
this._controller = new AbortController();
|
|
402
|
+
const responseHistory = [];
|
|
356
403
|
try {
|
|
357
404
|
// Ensure we have an agent
|
|
358
405
|
if (!this._agent) {
|
|
@@ -362,14 +409,14 @@ export class AgentManager {
|
|
|
362
409
|
throw new Error('Failed to initialize agent');
|
|
363
410
|
}
|
|
364
411
|
// Add user message to history
|
|
365
|
-
|
|
412
|
+
responseHistory.push({
|
|
366
413
|
role: 'user',
|
|
367
414
|
content: message
|
|
368
415
|
});
|
|
369
416
|
let continueLoop = true;
|
|
370
417
|
while (continueLoop) {
|
|
371
418
|
const result = await this._agent.stream({
|
|
372
|
-
messages: this._history,
|
|
419
|
+
messages: [...this._history, ...responseHistory],
|
|
373
420
|
abortSignal: this._controller.signal
|
|
374
421
|
});
|
|
375
422
|
const streamResult = await this._processStreamResult(result);
|
|
@@ -378,12 +425,12 @@ export class AgentManager {
|
|
|
378
425
|
this._updateTokenUsage(await result.usage);
|
|
379
426
|
// Add response messages to history
|
|
380
427
|
if (responseMessages.messages?.length) {
|
|
381
|
-
|
|
428
|
+
responseHistory.push(...responseMessages.messages);
|
|
382
429
|
}
|
|
383
430
|
// Add approval response if processed
|
|
384
431
|
if (streamResult.approvalResponse) {
|
|
385
432
|
// Check if the last message is a tool message we can append to
|
|
386
|
-
const lastMsg =
|
|
433
|
+
const lastMsg = responseHistory[responseHistory.length - 1];
|
|
387
434
|
if (lastMsg &&
|
|
388
435
|
lastMsg.role === 'tool' &&
|
|
389
436
|
Array.isArray(lastMsg.content) &&
|
|
@@ -393,11 +440,13 @@ export class AgentManager {
|
|
|
393
440
|
}
|
|
394
441
|
else {
|
|
395
442
|
// Add as separate message
|
|
396
|
-
|
|
443
|
+
responseHistory.push(streamResult.approvalResponse);
|
|
397
444
|
}
|
|
398
445
|
}
|
|
399
446
|
continueLoop = streamResult.approvalProcessed;
|
|
400
447
|
}
|
|
448
|
+
// Add the messages to the history only if the response ended without error.
|
|
449
|
+
this._history.push(...Private.sanitizeModelMessages(responseHistory));
|
|
401
450
|
}
|
|
402
451
|
catch (error) {
|
|
403
452
|
if (error.name !== 'AbortError') {
|
|
@@ -409,6 +458,7 @@ export class AgentManager {
|
|
|
409
458
|
}
|
|
410
459
|
finally {
|
|
411
460
|
this._controller = null;
|
|
461
|
+
this._streaming.resolve();
|
|
412
462
|
}
|
|
413
463
|
}
|
|
414
464
|
/**
|
|
@@ -859,24 +909,102 @@ WEB RETRIEVAL POLICY:
|
|
|
859
909
|
_initQueue = Promise.resolve();
|
|
860
910
|
_agentConfig;
|
|
861
911
|
_pendingApprovals = new Map();
|
|
912
|
+
_streaming = new PromiseDelegate();
|
|
862
913
|
}
|
|
863
914
|
var Private;
|
|
864
915
|
(function (Private) {
|
|
865
916
|
/**
|
|
866
|
-
*
|
|
867
|
-
*
|
|
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.
|
|
868
925
|
*/
|
|
869
926
|
Private.sanitizeModelMessages = (messages) => {
|
|
870
927
|
const sanitized = [];
|
|
871
928
|
for (const message of messages) {
|
|
872
|
-
|
|
873
|
-
|
|
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
|
+
}
|
|
969
|
+
}
|
|
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
|
+
}
|
|
874
1001
|
}
|
|
875
|
-
|
|
876
|
-
//
|
|
1002
|
+
else {
|
|
1003
|
+
// Message is a system or user message.
|
|
1004
|
+
sanitized.push(message);
|
|
877
1005
|
}
|
|
878
1006
|
}
|
|
879
|
-
return sanitized;
|
|
1007
|
+
return sanitized.length === messages.length ? sanitized : [];
|
|
880
1008
|
};
|
|
881
1009
|
/**
|
|
882
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(
|
|
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
|
|
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:
|
|
36
|
+
agentManagerFactory: IAgentManagerFactory;
|
|
39
37
|
/**
|
|
40
38
|
* AI settings model for configuration
|
|
41
39
|
*/
|
|
42
|
-
settingsModel:
|
|
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
|
|
58
|
+
* The contents manager.
|
|
61
59
|
*/
|
|
62
|
-
|
|
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.
|
|
14
|
+
this._contentsManager = options.contentsManager;
|
|
15
15
|
}
|
|
16
|
-
createModel(
|
|
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
|
-
|
|
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
|
-
|
|
59
|
+
_contentsManager;
|
|
55
60
|
}
|