@jupyterlite/ai 0.16.0 → 0.17.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 +7 -1
- package/lib/agent.js +59 -10
- package/lib/chat-commands/clear.js +1 -1
- package/lib/chat-model-handler.js +4 -1
- package/lib/chat-model.d.ts +25 -24
- package/lib/chat-model.js +254 -130
- package/lib/components/clear-button.d.ts +1 -1
- package/lib/components/clear-button.js +1 -1
- package/lib/index.js +200 -15
- package/lib/tokens.d.ts +13 -3
- package/lib/tokens.js +1 -0
- package/lib/widgets/main-area-chat.d.ts +1 -0
- package/lib/widgets/main-area-chat.js +7 -1
- package/package.json +1 -1
- package/src/agent.ts +72 -14
- package/src/chat-commands/clear.ts +1 -1
- package/src/chat-model-handler.ts +6 -1
- package/src/chat-model.ts +343 -171
- package/src/components/clear-button.tsx +3 -3
- package/src/index.ts +245 -17
- package/src/tokens.ts +13 -3
- package/src/widgets/main-area-chat.ts +9 -1
package/lib/agent.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { IMessageContent } from '@jupyter/chat';
|
|
2
2
|
import { ISignal } from '@lumino/signaling';
|
|
3
|
+
import { type ModelMessage, type UserContent } from 'ai';
|
|
3
4
|
import { ISecretsManager } from 'jupyter-secrets-manager';
|
|
4
5
|
import { type IAgentManager, type IAgentManagerFactory, type IAISettingsModel, type ISkillRegistry, type ITokenUsage, type ToolMap } from './tokens';
|
|
5
6
|
/**
|
|
@@ -158,7 +159,12 @@ export declare class AgentManager implements IAgentManager {
|
|
|
158
159
|
* Handles the complete execution cycle including tool calls.
|
|
159
160
|
* @param message The user message to respond to (may include processed attachment content)
|
|
160
161
|
*/
|
|
161
|
-
generateResponse(message:
|
|
162
|
+
generateResponse(message: UserContent): Promise<void>;
|
|
163
|
+
/**
|
|
164
|
+
* Create a transient language model to request a text response which won't be added to history.
|
|
165
|
+
* @param messages - the messages sequence to send to the model.
|
|
166
|
+
*/
|
|
167
|
+
textResponse(messages: ModelMessage[]): Promise<string>;
|
|
162
168
|
/**
|
|
163
169
|
* Updates cumulative token usage statistics from a completed model step.
|
|
164
170
|
*/
|
package/lib/agent.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createMCPClient } from '@ai-sdk/mcp';
|
|
2
2
|
import { PromiseDelegate } from '@lumino/coreutils';
|
|
3
3
|
import { Signal } from '@lumino/signaling';
|
|
4
|
-
import { ToolLoopAgent, stepCountIs } from 'ai';
|
|
4
|
+
import { generateText, ToolLoopAgent, stepCountIs, APICallError } from 'ai';
|
|
5
5
|
import { createModel } from './providers/models';
|
|
6
6
|
import { getEffectiveContextWindow } from './providers/model-info';
|
|
7
7
|
import { createProviderTools } from './providers/provider-tools';
|
|
@@ -347,9 +347,9 @@ export class AgentManager {
|
|
|
347
347
|
this._pendingApprovals.clear();
|
|
348
348
|
// Convert chat messages to model messages
|
|
349
349
|
const modelMessages = messages.map(msg => {
|
|
350
|
-
const
|
|
350
|
+
const role = msg.sender.username === 'ai-assistant' ? 'assistant' : 'user';
|
|
351
351
|
return {
|
|
352
|
-
role
|
|
352
|
+
role,
|
|
353
353
|
content: msg.body
|
|
354
354
|
};
|
|
355
355
|
});
|
|
@@ -412,6 +412,11 @@ export class AgentManager {
|
|
|
412
412
|
this._streaming = new PromiseDelegate();
|
|
413
413
|
this._controller = new AbortController();
|
|
414
414
|
const responseHistory = [];
|
|
415
|
+
// Add user message to history
|
|
416
|
+
responseHistory.push({
|
|
417
|
+
role: 'user',
|
|
418
|
+
content: message
|
|
419
|
+
});
|
|
415
420
|
try {
|
|
416
421
|
// Ensure we have an agent
|
|
417
422
|
if (!this._agent) {
|
|
@@ -420,11 +425,6 @@ export class AgentManager {
|
|
|
420
425
|
if (!this._agent) {
|
|
421
426
|
throw new Error('Failed to initialize agent');
|
|
422
427
|
}
|
|
423
|
-
// Add user message to history
|
|
424
|
-
responseHistory.push({
|
|
425
|
-
role: 'user',
|
|
426
|
-
content: message
|
|
427
|
-
});
|
|
428
428
|
let continueLoop = true;
|
|
429
429
|
while (continueLoop) {
|
|
430
430
|
const result = await this._agent.stream({
|
|
@@ -473,9 +473,38 @@ export class AgentManager {
|
|
|
473
473
|
}
|
|
474
474
|
catch (error) {
|
|
475
475
|
if (error.name !== 'AbortError') {
|
|
476
|
+
let helpMessage = `${error.message}`;
|
|
477
|
+
// Remove attachments from history on payload rejection errors
|
|
478
|
+
if (APICallError.isInstance(error) &&
|
|
479
|
+
(error.statusCode === 400 ||
|
|
480
|
+
error.statusCode === 404 ||
|
|
481
|
+
error.statusCode === 413 ||
|
|
482
|
+
error.statusCode === 415 ||
|
|
483
|
+
error.statusCode === 422)) {
|
|
484
|
+
for (const msg of [...this._history, ...responseHistory]) {
|
|
485
|
+
if (msg.role === 'user' && Array.isArray(msg.content)) {
|
|
486
|
+
const hasMedia = msg.content.some(p => p.type !== 'text');
|
|
487
|
+
if (hasMedia) {
|
|
488
|
+
const textContent = msg.content
|
|
489
|
+
.filter(p => p.type === 'text')
|
|
490
|
+
.map(p => p.text)
|
|
491
|
+
.join('\n');
|
|
492
|
+
msg.content =
|
|
493
|
+
textContent || '_Attachment removed due to error_';
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
helpMessage +=
|
|
498
|
+
'\n\nAttachments have been removed from history. Please send your prompt again.';
|
|
499
|
+
}
|
|
476
500
|
this._agentEvent.emit({
|
|
477
501
|
type: 'error',
|
|
478
|
-
data: { error:
|
|
502
|
+
data: { error: new Error(helpMessage) }
|
|
503
|
+
});
|
|
504
|
+
this._history.push(...Private.sanitizeModelMessages(responseHistory));
|
|
505
|
+
this._history.push({
|
|
506
|
+
role: 'assistant',
|
|
507
|
+
content: helpMessage
|
|
479
508
|
});
|
|
480
509
|
}
|
|
481
510
|
}
|
|
@@ -484,6 +513,24 @@ export class AgentManager {
|
|
|
484
513
|
this._streaming.resolve();
|
|
485
514
|
}
|
|
486
515
|
}
|
|
516
|
+
/**
|
|
517
|
+
* Create a transient language model to request a text response which won't be added to history.
|
|
518
|
+
* @param messages - the messages sequence to send to the model.
|
|
519
|
+
*/
|
|
520
|
+
async textResponse(messages) {
|
|
521
|
+
try {
|
|
522
|
+
const model = await this._createModel();
|
|
523
|
+
const result = await generateText({
|
|
524
|
+
model,
|
|
525
|
+
messages
|
|
526
|
+
});
|
|
527
|
+
this._updateTokenUsage(result.totalUsage, result.totalUsage.inputTokens);
|
|
528
|
+
return result.text;
|
|
529
|
+
}
|
|
530
|
+
catch (e) {
|
|
531
|
+
throw `Error while getting the topic of the chat\n${e}`;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
487
534
|
/**
|
|
488
535
|
* Updates cumulative token usage statistics from a completed model step.
|
|
489
536
|
*/
|
|
@@ -694,13 +741,15 @@ ${richOutputWorkflowInstruction}`;
|
|
|
694
741
|
}
|
|
695
742
|
await this._handleApprovalRequest(part, processResult);
|
|
696
743
|
break;
|
|
744
|
+
case 'error':
|
|
745
|
+
throw part.error;
|
|
697
746
|
case 'finish-step':
|
|
698
747
|
this._updateTokenUsage(part.usage, part.usage.inputTokens);
|
|
699
748
|
break;
|
|
700
749
|
case 'abort':
|
|
701
750
|
processResult.aborted = true;
|
|
702
751
|
break;
|
|
703
|
-
// Ignore: text-start, text-end, finish,
|
|
752
|
+
// Ignore: text-start, text-end, finish, and others
|
|
704
753
|
default:
|
|
705
754
|
break;
|
|
706
755
|
}
|
|
@@ -14,7 +14,7 @@ export class ChatModelHandler {
|
|
|
14
14
|
this._contentsManager = options.contentsManager;
|
|
15
15
|
}
|
|
16
16
|
createModel(options) {
|
|
17
|
-
const { name, activeProvider, tokenUsage, messages, autosave } = options;
|
|
17
|
+
const { name, activeProvider, tokenUsage, messages, autosave, title } = options;
|
|
18
18
|
// Create Agent Manager first so it can be shared
|
|
19
19
|
const agentManager = this._agentManagerFactory.createAgent({
|
|
20
20
|
settingsModel: this._settingsModel,
|
|
@@ -38,6 +38,9 @@ export class ChatModelHandler {
|
|
|
38
38
|
});
|
|
39
39
|
model.autosave = autosave ?? false;
|
|
40
40
|
model.name = name;
|
|
41
|
+
if (title) {
|
|
42
|
+
model.title = title;
|
|
43
|
+
}
|
|
41
44
|
return model;
|
|
42
45
|
}
|
|
43
46
|
/**
|
package/lib/chat-model.d.ts
CHANGED
|
@@ -18,6 +18,19 @@ export declare class AIChatModel extends AbstractChatModel {
|
|
|
18
18
|
*/
|
|
19
19
|
get name(): string;
|
|
20
20
|
set name(value: string);
|
|
21
|
+
/**
|
|
22
|
+
* A signal emitting when the chat name has changed.
|
|
23
|
+
*/
|
|
24
|
+
get nameChanged(): ISignal<AIChatModel, string>;
|
|
25
|
+
/**
|
|
26
|
+
* The title of the chat.
|
|
27
|
+
*/
|
|
28
|
+
get title(): string | null;
|
|
29
|
+
set title(value: string | null);
|
|
30
|
+
/**
|
|
31
|
+
* A signal emitting when the chat title has changed.
|
|
32
|
+
*/
|
|
33
|
+
get titleChanged(): ISignal<AIChatModel, string | null>;
|
|
21
34
|
/**
|
|
22
35
|
* Whether to save the chat automatically.
|
|
23
36
|
*/
|
|
@@ -27,10 +40,6 @@ export declare class AIChatModel extends AbstractChatModel {
|
|
|
27
40
|
* A signal emitting when the autosave flag changed.
|
|
28
41
|
*/
|
|
29
42
|
get autosaveChanged(): ISignal<AIChatModel, boolean>;
|
|
30
|
-
/**
|
|
31
|
-
* A signal emitting when the chat name has changed.
|
|
32
|
-
*/
|
|
33
|
-
get nameChanged(): ISignal<AIChatModel, string>;
|
|
34
43
|
/**
|
|
35
44
|
* Gets the current user information.
|
|
36
45
|
*/
|
|
@@ -62,7 +71,7 @@ export declare class AIChatModel extends AbstractChatModel {
|
|
|
62
71
|
/**
|
|
63
72
|
* Clears all messages from the chat and resets conversation state.
|
|
64
73
|
*/
|
|
65
|
-
clearMessages: () => void
|
|
74
|
+
clearMessages: () => Promise<void>;
|
|
66
75
|
/**
|
|
67
76
|
* Adds a non-user message to the chat (used by chat commands).
|
|
68
77
|
*/
|
|
@@ -83,6 +92,10 @@ export declare class AIChatModel extends AbstractChatModel {
|
|
|
83
92
|
* restoration is not possible.
|
|
84
93
|
*/
|
|
85
94
|
restore: (filepath: string, silent?: boolean) => Promise<boolean>;
|
|
95
|
+
/**
|
|
96
|
+
* Request a title to this chat, regarding the message history.
|
|
97
|
+
*/
|
|
98
|
+
requestTitle(): Promise<string>;
|
|
86
99
|
/**
|
|
87
100
|
* Serialize the model for backup
|
|
88
101
|
*/
|
|
@@ -155,24 +168,6 @@ export declare class AIChatModel extends AbstractChatModel {
|
|
|
155
168
|
* Updates a tool call's UI with new status and optional output.
|
|
156
169
|
*/
|
|
157
170
|
private _updateToolCallUI;
|
|
158
|
-
/**
|
|
159
|
-
* Processes file attachments and returns their content as formatted strings.
|
|
160
|
-
* @param attachments Array of file attachments to process
|
|
161
|
-
* @returns Array of formatted attachment contents
|
|
162
|
-
*/
|
|
163
|
-
private _processAttachments;
|
|
164
|
-
/**
|
|
165
|
-
* Reads the content of a notebook cell.
|
|
166
|
-
* @param attachment The notebook attachment to read
|
|
167
|
-
* @returns Cell content as string or null if unable to read
|
|
168
|
-
*/
|
|
169
|
-
private _readNotebookCells;
|
|
170
|
-
/**
|
|
171
|
-
* Reads the content of a file attachment.
|
|
172
|
-
* @param attachment The file attachment to read
|
|
173
|
-
* @returns File content as string or null if unable to read
|
|
174
|
-
*/
|
|
175
|
-
private _readFileAttachment;
|
|
176
171
|
private _settingsModel;
|
|
177
172
|
private _user;
|
|
178
173
|
private _toolContexts;
|
|
@@ -183,6 +178,8 @@ export declare class AIChatModel extends AbstractChatModel {
|
|
|
183
178
|
private _autosave;
|
|
184
179
|
private _autosaveChanged;
|
|
185
180
|
private _autosaveDebouncer;
|
|
181
|
+
private _title;
|
|
182
|
+
private _titleChanged;
|
|
186
183
|
}
|
|
187
184
|
/**
|
|
188
185
|
* Namespace containing types and interfaces for AIChatModel.
|
|
@@ -232,7 +229,7 @@ export declare namespace AIChatModel {
|
|
|
232
229
|
/**
|
|
233
230
|
* The clear messages callback.
|
|
234
231
|
*/
|
|
235
|
-
clearMessages: () => void
|
|
232
|
+
clearMessages: () => Promise<void>;
|
|
236
233
|
/**
|
|
237
234
|
* Adds an assistant/system message to the chat.
|
|
238
235
|
*/
|
|
@@ -274,6 +271,10 @@ export declare namespace AIChatModel {
|
|
|
274
271
|
* Whether the chat is automatically saved.
|
|
275
272
|
*/
|
|
276
273
|
autosave?: boolean;
|
|
274
|
+
/**
|
|
275
|
+
* An optional title of the chat.
|
|
276
|
+
*/
|
|
277
|
+
title?: string;
|
|
277
278
|
};
|
|
278
279
|
};
|
|
279
280
|
}
|