@jupyterlite/ai 0.17.0 → 0.18.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 +12 -9
- package/lib/agent.js +38 -51
- package/lib/chat-model-handler.d.ts +2 -3
- package/lib/chat-model-handler.js +2 -1
- package/lib/chat-model.d.ts +110 -8
- package/lib/chat-model.js +322 -63
- package/lib/components/save-button.d.ts +2 -2
- package/lib/index.js +29 -49
- package/lib/models/settings-model.js +1 -0
- package/lib/providers/built-in-providers.js +1 -1
- package/lib/providers/{generated-context-windows.d.ts → generated-model-info.d.ts} +2 -2
- package/lib/providers/generated-model-info.js +502 -0
- package/lib/providers/model-info.d.ts +3 -0
- package/lib/providers/model-info.js +33 -0
- package/lib/tokens.d.ts +85 -12
- package/lib/widgets/ai-settings.js +5 -0
- package/lib/widgets/main-area-chat.d.ts +2 -3
- package/lib/widgets/main-area-chat.js +2 -4
- package/package.json +3 -3
- package/schema/settings-model.json +6 -0
- package/src/agent.ts +46 -56
- package/src/chat-model-handler.ts +4 -2
- package/src/chat-model.ts +435 -90
- package/src/components/save-button.tsx +3 -3
- package/src/index.ts +52 -74
- package/src/models/settings-model.ts +1 -0
- package/src/providers/built-in-providers.ts +1 -1
- package/src/providers/generated-model-info.ts +508 -0
- package/src/providers/model-info.ts +57 -0
- package/src/tokens.ts +87 -12
- package/src/widgets/ai-settings.tsx +26 -0
- package/src/widgets/main-area-chat.ts +5 -8
- package/lib/providers/generated-context-windows.js +0 -96
- package/src/providers/generated-context-windows.ts +0 -102
|
@@ -45,6 +45,39 @@ export function getProviderModelInfo(providerInfo, model) {
|
|
|
45
45
|
return normalizeModelId(candidateId) === normalizedModelId;
|
|
46
46
|
})?.[1];
|
|
47
47
|
}
|
|
48
|
+
export function modelSupportsImages(providerConfig, providerRegistry) {
|
|
49
|
+
if (!providerConfig) {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
const providerInfo = providerRegistry?.getProviderInfo(providerConfig.provider);
|
|
53
|
+
const modelInfo = getProviderModelInfo(providerInfo, providerConfig.model);
|
|
54
|
+
if (!modelInfo) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
return modelInfo.supportsImages ?? true;
|
|
58
|
+
}
|
|
59
|
+
export function modelSupportsPdf(providerConfig, providerRegistry) {
|
|
60
|
+
if (!providerConfig) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
const providerInfo = providerRegistry?.getProviderInfo(providerConfig.provider);
|
|
64
|
+
const modelInfo = getProviderModelInfo(providerInfo, providerConfig.model);
|
|
65
|
+
if (!modelInfo) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
return modelInfo.supportsPdf ?? true;
|
|
69
|
+
}
|
|
70
|
+
export function modelSupportsAudio(providerConfig, providerRegistry) {
|
|
71
|
+
if (!providerConfig) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
const providerInfo = providerRegistry?.getProviderInfo(providerConfig.provider);
|
|
75
|
+
const modelInfo = getProviderModelInfo(providerInfo, providerConfig.model);
|
|
76
|
+
if (!modelInfo) {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
return modelInfo.supportsAudio ?? true;
|
|
80
|
+
}
|
|
48
81
|
export function getEffectiveContextWindow(providerConfig, providerRegistry) {
|
|
49
82
|
if (!providerConfig) {
|
|
50
83
|
return undefined;
|
package/lib/tokens.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ActiveCellManager,
|
|
1
|
+
import { ActiveCellManager, IChatModel, IMessage } from '@jupyter/chat';
|
|
2
2
|
import { VDomRenderer } from '@jupyterlab/apputils';
|
|
3
3
|
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
4
4
|
import { Token } from '@lumino/coreutils';
|
|
@@ -7,7 +7,6 @@ import { ISignal } from '@lumino/signaling';
|
|
|
7
7
|
import type { Tool, LanguageModel, UserContent, ModelMessage } from 'ai';
|
|
8
8
|
import { ISecretsManager } from 'jupyter-secrets-manager';
|
|
9
9
|
import type { IModelOptions } from './providers/models';
|
|
10
|
-
import { AIChatModel } from './chat-model';
|
|
11
10
|
import type { ISkillDefinition, ISkillRegistration, ISkillResourceResult, ISkillSummary } from './skills/types';
|
|
12
11
|
export type { ISkillDefinition, ISkillRegistration, ISkillResourceResult, ISkillSummary } from './skills/types';
|
|
13
12
|
/**
|
|
@@ -159,6 +158,18 @@ export interface IProviderModelInfo {
|
|
|
159
158
|
* Default context window for the model in tokens.
|
|
160
159
|
*/
|
|
161
160
|
contextWindow?: number;
|
|
161
|
+
/**
|
|
162
|
+
* Whether the model supports image inputs.
|
|
163
|
+
*/
|
|
164
|
+
supportsImages?: boolean;
|
|
165
|
+
/**
|
|
166
|
+
* Whether the model supports PDF inputs.
|
|
167
|
+
*/
|
|
168
|
+
supportsPdf?: boolean;
|
|
169
|
+
/**
|
|
170
|
+
* Whether the model supports audio inputs.
|
|
171
|
+
*/
|
|
172
|
+
supportsAudio?: boolean;
|
|
162
173
|
}
|
|
163
174
|
export interface IProviderInfo {
|
|
164
175
|
/**
|
|
@@ -303,6 +314,7 @@ export interface IAIConfig {
|
|
|
303
314
|
diffDisplayMode: 'split' | 'unified';
|
|
304
315
|
skillsPaths: string[];
|
|
305
316
|
chatBackupDirectory: string;
|
|
317
|
+
autoTitle: boolean;
|
|
306
318
|
}
|
|
307
319
|
export interface IAISettingsModel extends VDomRenderer.IModel {
|
|
308
320
|
readonly config: IAIConfig;
|
|
@@ -401,13 +413,12 @@ export declare namespace IAgentManager {
|
|
|
401
413
|
isError: boolean;
|
|
402
414
|
};
|
|
403
415
|
tool_approval_request: {
|
|
404
|
-
approvalId: string;
|
|
405
416
|
toolCallId: string;
|
|
406
417
|
toolName: string;
|
|
407
418
|
args: unknown;
|
|
408
419
|
};
|
|
409
420
|
tool_approval_resolved: {
|
|
410
|
-
|
|
421
|
+
toolCallId: string;
|
|
411
422
|
approved: boolean;
|
|
412
423
|
};
|
|
413
424
|
error: {
|
|
@@ -468,26 +479,26 @@ export interface IAgentManager {
|
|
|
468
479
|
*/
|
|
469
480
|
clearHistory(): Promise<void>;
|
|
470
481
|
/**
|
|
471
|
-
* Sets the
|
|
472
|
-
* @param messages
|
|
482
|
+
* Sets the history from already-processed model messages.
|
|
483
|
+
* @param messages Pre-built model messages (may include binary content)
|
|
473
484
|
*/
|
|
474
|
-
setHistory(messages:
|
|
485
|
+
setHistory(messages: ModelMessage[]): void;
|
|
475
486
|
/**
|
|
476
487
|
* Stops the current streaming response by aborting the request.
|
|
477
488
|
*/
|
|
478
489
|
stopStreaming(): void;
|
|
479
490
|
/**
|
|
480
491
|
* Approves a pending tool call.
|
|
481
|
-
* @param
|
|
492
|
+
* @param toolCallId The tool call ID to approve
|
|
482
493
|
* @param reason Optional reason for approval
|
|
483
494
|
*/
|
|
484
|
-
approveToolCall(
|
|
495
|
+
approveToolCall(toolCallId: string, reason?: string): void;
|
|
485
496
|
/**
|
|
486
497
|
* Rejects a pending tool call.
|
|
487
|
-
* @param
|
|
498
|
+
* @param toolCallId The tool call ID to reject
|
|
488
499
|
* @param reason Optional reason for rejection
|
|
489
500
|
*/
|
|
490
|
-
rejectToolCall(
|
|
501
|
+
rejectToolCall(toolCallId: string, reason?: string): void;
|
|
491
502
|
/**
|
|
492
503
|
* Generates AI response to user message using the agent.
|
|
493
504
|
* Handles the complete execution cycle including tool calls.
|
|
@@ -533,6 +544,68 @@ export interface IAgentManagerFactory {
|
|
|
533
544
|
getMCPTools(): Promise<ToolMap>;
|
|
534
545
|
}
|
|
535
546
|
export declare const IAgentManagerFactory: Token<IAgentManagerFactory>;
|
|
547
|
+
export interface IAIChatModel extends IChatModel {
|
|
548
|
+
/**
|
|
549
|
+
* A signal emitting when the chat name has changed.
|
|
550
|
+
*/
|
|
551
|
+
readonly nameChanged: ISignal<IAIChatModel, string>;
|
|
552
|
+
/**
|
|
553
|
+
* The title of the chat.
|
|
554
|
+
*/
|
|
555
|
+
title: string | null;
|
|
556
|
+
/**
|
|
557
|
+
* A signal emitting when the chat title has changed.
|
|
558
|
+
*/
|
|
559
|
+
readonly titleChanged: ISignal<IAIChatModel, string | null>;
|
|
560
|
+
/**
|
|
561
|
+
* Whether to save the chat automatically.
|
|
562
|
+
*/
|
|
563
|
+
autosave: boolean;
|
|
564
|
+
/**
|
|
565
|
+
* A signal emitting when the autosave flag changed.
|
|
566
|
+
*/
|
|
567
|
+
readonly autosaveChanged: ISignal<IAIChatModel, boolean>;
|
|
568
|
+
/**
|
|
569
|
+
* Whether save/restore is available.
|
|
570
|
+
*/
|
|
571
|
+
readonly saveAvailable: boolean;
|
|
572
|
+
/**
|
|
573
|
+
* A signal emitting when the token usage changed.
|
|
574
|
+
*/
|
|
575
|
+
readonly tokenUsageChanged: ISignal<IAgentManager, ITokenUsage>;
|
|
576
|
+
/**
|
|
577
|
+
* The agent manager used in the model.
|
|
578
|
+
*/
|
|
579
|
+
readonly agentManager: IAgentManager;
|
|
580
|
+
/**
|
|
581
|
+
* Save the chat as json file.
|
|
582
|
+
*/
|
|
583
|
+
save(): Promise<void>;
|
|
584
|
+
/**
|
|
585
|
+
* Restore the chat from a json file.
|
|
586
|
+
*
|
|
587
|
+
* @param silent - Whether a log should be displayed in the console if the
|
|
588
|
+
* restoration is not possible.
|
|
589
|
+
*/
|
|
590
|
+
restore(filepath: string, silent?: boolean): Promise<boolean>;
|
|
591
|
+
/**
|
|
592
|
+
* Request a title to this chat, regarding the message history.
|
|
593
|
+
*/
|
|
594
|
+
requestTitle(): Promise<string>;
|
|
595
|
+
/**
|
|
596
|
+
* Removes a queued message by its ID.
|
|
597
|
+
* @param messageId The ID of the queued message to remove
|
|
598
|
+
*/
|
|
599
|
+
removeQueuedMessage(messageId: string): void;
|
|
600
|
+
/**
|
|
601
|
+
* The current message queue
|
|
602
|
+
*/
|
|
603
|
+
messageQueue: any[];
|
|
604
|
+
/**
|
|
605
|
+
* Whether the chat is currently busy processing a message
|
|
606
|
+
*/
|
|
607
|
+
isBusy: boolean;
|
|
608
|
+
}
|
|
536
609
|
/**
|
|
537
610
|
* The interface for the chat model handler.
|
|
538
611
|
*/
|
|
@@ -540,7 +613,7 @@ export interface IChatModelHandler {
|
|
|
540
613
|
/**
|
|
541
614
|
* The function to create a new model.
|
|
542
615
|
*/
|
|
543
|
-
createModel(options: ICreateChatOptions):
|
|
616
|
+
createModel(options: ICreateChatOptions): IAIChatModel;
|
|
544
617
|
/**
|
|
545
618
|
* The active cell manager (to copy code from chat to cell).
|
|
546
619
|
*/
|
|
@@ -482,6 +482,11 @@ const AISettingsComponent = ({ model, agentManagerFactory, themeManager, provide
|
|
|
482
482
|
}), color: "primary" }), label: React.createElement(Box, null,
|
|
483
483
|
React.createElement(Typography, { variant: "body1" }, trans.__('Send with Shift+Enter')),
|
|
484
484
|
React.createElement(Typography, { variant: "caption", color: "text.secondary" }, trans.__('Use Shift+Enter to send messages (Enter creates new line)'))) }),
|
|
485
|
+
React.createElement(FormControlLabel, { control: React.createElement(Switch, { checked: config.autoTitle, onChange: e => handleConfigUpdate({
|
|
486
|
+
autoTitle: e.target.checked
|
|
487
|
+
}), color: "primary" }), label: React.createElement(Box, null,
|
|
488
|
+
React.createElement(Typography, { variant: "body1" }, trans.__('Auto Title')),
|
|
489
|
+
React.createElement(Typography, { variant: "caption", color: "text.secondary" }, trans.__('Automatically generate a chat title from the model for every message until there are 5 messages'))) }),
|
|
485
490
|
React.createElement(FormControlLabel, { control: React.createElement(Switch, { checked: config.showTokenUsage, onChange: e => handleConfigUpdate({
|
|
486
491
|
showTokenUsage: e.target.checked
|
|
487
492
|
}), color: "primary" }), label: React.createElement(Box, null,
|
|
@@ -2,8 +2,7 @@ import { ChatWidget } from '@jupyter/chat';
|
|
|
2
2
|
import { MainAreaWidget } from '@jupyterlab/apputils';
|
|
3
3
|
import type { TranslationBundle } from '@jupyterlab/translation';
|
|
4
4
|
import { CommandRegistry } from '@lumino/commands';
|
|
5
|
-
import {
|
|
6
|
-
import { type IAISettingsModel } from '../tokens';
|
|
5
|
+
import { IAIChatModel, type IAISettingsModel } from '../tokens';
|
|
7
6
|
export declare namespace MainAreaChat {
|
|
8
7
|
interface IOptions extends MainAreaWidget.IOptions<ChatWidget> {
|
|
9
8
|
commands: CommandRegistry;
|
|
@@ -20,7 +19,7 @@ export declare class MainAreaChat extends MainAreaWidget<ChatWidget> {
|
|
|
20
19
|
/**
|
|
21
20
|
* Get the model of the chat.
|
|
22
21
|
*/
|
|
23
|
-
get model():
|
|
22
|
+
get model(): IAIChatModel;
|
|
24
23
|
/**
|
|
25
24
|
* Get the area of the chat.
|
|
26
25
|
*/
|
|
@@ -43,14 +43,14 @@ export class MainAreaChat extends MainAreaWidget {
|
|
|
43
43
|
this._outputAreaCompat = new RenderedMessageOutputAreaCompat({
|
|
44
44
|
chatPanel: this.content
|
|
45
45
|
});
|
|
46
|
-
this.model.writersChanged
|
|
46
|
+
this.model.writersChanged?.connect(this._writersChanged);
|
|
47
47
|
this.model.titleChanged.connect(this._titleChanged);
|
|
48
48
|
}
|
|
49
49
|
dispose() {
|
|
50
50
|
super.dispose();
|
|
51
51
|
// Dispose of the approval buttons widget when the chat is disposed.
|
|
52
52
|
this._outputAreaCompat.dispose();
|
|
53
|
-
this.model.writersChanged
|
|
53
|
+
this.model.writersChanged?.disconnect(this._writersChanged);
|
|
54
54
|
this.model.titleChanged.disconnect(this._titleChanged);
|
|
55
55
|
}
|
|
56
56
|
/**
|
|
@@ -69,12 +69,10 @@ export class MainAreaChat extends MainAreaWidget {
|
|
|
69
69
|
// Check if AI is currently writing (streaming)
|
|
70
70
|
const aiWriting = writers.some(writer => writer.user.username === 'ai-assistant');
|
|
71
71
|
if (aiWriting) {
|
|
72
|
-
this.content.inputToolbarRegistry?.hide('send');
|
|
73
72
|
this.content.inputToolbarRegistry?.show('stop');
|
|
74
73
|
}
|
|
75
74
|
else {
|
|
76
75
|
this.content.inputToolbarRegistry?.hide('stop');
|
|
77
|
-
this.content.inputToolbarRegistry?.show('send');
|
|
78
76
|
}
|
|
79
77
|
};
|
|
80
78
|
_titleChanged = () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jupyterlite/ai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "AI code completions and chat for JupyterLite",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jupyter",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"watch:labextension": "jupyter labextension watch .",
|
|
55
55
|
"docs": "jupyter book start",
|
|
56
56
|
"docs:build": "sed -e 's/\\[@/[/g' -e 's/@/\\@/g' CHANGELOG.md > docs/_changelog_content.md && jupyter book build --html",
|
|
57
|
-
"sync:model-
|
|
57
|
+
"sync:model-info": "node scripts/sync-model-info.mjs && prettier --write src/providers/generated-model-info.ts && eslint --fix src/providers/generated-model-info.ts"
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
60
|
"@ai-sdk/anthropic": "^3.0.58",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"@mui/icons-material": "^7",
|
|
90
90
|
"@mui/material": "^7",
|
|
91
91
|
"ai": "^6.0.116",
|
|
92
|
-
"jupyter-chat-components": "^0.
|
|
92
|
+
"jupyter-chat-components": "^0.5.0",
|
|
93
93
|
"jupyter-secrets-manager": "^0.5.0",
|
|
94
94
|
"yaml": "^2.8.1",
|
|
95
95
|
"zod": "^4.3.6"
|
|
@@ -210,6 +210,12 @@
|
|
|
210
210
|
"type": "boolean",
|
|
211
211
|
"default": false
|
|
212
212
|
},
|
|
213
|
+
"autoTitle": {
|
|
214
|
+
"title": "Auto Title",
|
|
215
|
+
"description": "Automatically request a title from the model for every message until there are 5 messages",
|
|
216
|
+
"type": "boolean",
|
|
217
|
+
"default": false
|
|
218
|
+
},
|
|
213
219
|
"showTokenUsage": {
|
|
214
220
|
"title": "Show Token Usage",
|
|
215
221
|
"description": "Display token usage information in the chat toolbar",
|
package/src/agent.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { createMCPClient, type MCPClient } from '@ai-sdk/mcp';
|
|
2
|
-
import type { IMessageContent } from '@jupyter/chat';
|
|
3
2
|
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
4
3
|
import { PromiseDelegate } from '@lumino/coreutils';
|
|
5
4
|
import { ISignal, Signal } from '@lumino/signaling';
|
|
@@ -490,32 +489,12 @@ export class AgentManager implements IAgentManager {
|
|
|
490
489
|
}
|
|
491
490
|
|
|
492
491
|
/**
|
|
493
|
-
* Sets the history
|
|
494
|
-
* @param messages
|
|
492
|
+
* Sets the history from already-processed model messages.
|
|
493
|
+
* @param messages Pre-built model messages (may include binary content)
|
|
495
494
|
*/
|
|
496
|
-
setHistory(messages:
|
|
497
|
-
|
|
498
|
-
this.
|
|
499
|
-
|
|
500
|
-
for (const [approvalId, pending] of this._pendingApprovals) {
|
|
501
|
-
pending.resolve(false, 'Chat history changed');
|
|
502
|
-
this._agentEvent.emit({
|
|
503
|
-
type: 'tool_approval_resolved',
|
|
504
|
-
data: { approvalId, approved: false }
|
|
505
|
-
});
|
|
506
|
-
}
|
|
507
|
-
this._pendingApprovals.clear();
|
|
508
|
-
|
|
509
|
-
// Convert chat messages to model messages
|
|
510
|
-
const modelMessages: ModelMessage[] = messages.map(msg => {
|
|
511
|
-
const role =
|
|
512
|
-
msg.sender.username === 'ai-assistant' ? 'assistant' : 'user';
|
|
513
|
-
return {
|
|
514
|
-
role,
|
|
515
|
-
content: msg.body
|
|
516
|
-
};
|
|
517
|
-
});
|
|
518
|
-
this._history = Private.sanitizeModelMessages(modelMessages);
|
|
495
|
+
setHistory(messages: ModelMessage[]): void {
|
|
496
|
+
this.stopStreaming('Chat history changed');
|
|
497
|
+
this._history = Private.sanitizeModelMessages(messages);
|
|
519
498
|
}
|
|
520
499
|
|
|
521
500
|
/**
|
|
@@ -526,11 +505,11 @@ export class AgentManager implements IAgentManager {
|
|
|
526
505
|
this._controller?.abort();
|
|
527
506
|
|
|
528
507
|
// Reject any pending approvals
|
|
529
|
-
for (const [
|
|
508
|
+
for (const [toolCallId, pending] of this._pendingApprovals) {
|
|
530
509
|
pending.resolve(false, reason ?? 'Stream ended by user');
|
|
531
510
|
this._agentEvent.emit({
|
|
532
511
|
type: 'tool_approval_resolved',
|
|
533
|
-
data: {
|
|
512
|
+
data: { toolCallId, approved: false }
|
|
534
513
|
});
|
|
535
514
|
}
|
|
536
515
|
this._pendingApprovals.clear();
|
|
@@ -538,34 +517,34 @@ export class AgentManager implements IAgentManager {
|
|
|
538
517
|
|
|
539
518
|
/**
|
|
540
519
|
* Approves a pending tool call.
|
|
541
|
-
* @param
|
|
520
|
+
* @param toolCallId The tool call ID to approve
|
|
542
521
|
* @param reason Optional reason for approval
|
|
543
522
|
*/
|
|
544
|
-
approveToolCall(
|
|
545
|
-
const pending = this._pendingApprovals.get(
|
|
523
|
+
approveToolCall(toolCallId: string, reason?: string): void {
|
|
524
|
+
const pending = this._pendingApprovals.get(toolCallId);
|
|
546
525
|
if (pending) {
|
|
547
526
|
pending.resolve(true, reason);
|
|
548
|
-
this._pendingApprovals.delete(
|
|
527
|
+
this._pendingApprovals.delete(toolCallId);
|
|
549
528
|
this._agentEvent.emit({
|
|
550
529
|
type: 'tool_approval_resolved',
|
|
551
|
-
data: {
|
|
530
|
+
data: { toolCallId, approved: true }
|
|
552
531
|
});
|
|
553
532
|
}
|
|
554
533
|
}
|
|
555
534
|
|
|
556
535
|
/**
|
|
557
536
|
* Rejects a pending tool call.
|
|
558
|
-
* @param
|
|
537
|
+
* @param toolCallId The tool call ID to reject
|
|
559
538
|
* @param reason Optional reason for rejection
|
|
560
539
|
*/
|
|
561
|
-
rejectToolCall(
|
|
562
|
-
const pending = this._pendingApprovals.get(
|
|
540
|
+
rejectToolCall(toolCallId: string, reason?: string): void {
|
|
541
|
+
const pending = this._pendingApprovals.get(toolCallId);
|
|
563
542
|
if (pending) {
|
|
564
543
|
pending.resolve(false, reason);
|
|
565
|
-
this._pendingApprovals.delete(
|
|
544
|
+
this._pendingApprovals.delete(toolCallId);
|
|
566
545
|
this._agentEvent.emit({
|
|
567
546
|
type: 'tool_approval_resolved',
|
|
568
|
-
data: {
|
|
547
|
+
data: { toolCallId, approved: false }
|
|
569
548
|
});
|
|
570
549
|
}
|
|
571
550
|
}
|
|
@@ -663,19 +642,10 @@ export class AgentManager implements IAgentManager {
|
|
|
663
642
|
error.statusCode === 415 ||
|
|
664
643
|
error.statusCode === 422)
|
|
665
644
|
) {
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
const textContent = msg.content
|
|
671
|
-
.filter(p => p.type === 'text')
|
|
672
|
-
.map(p => (p as { text: string }).text)
|
|
673
|
-
.join('\n');
|
|
674
|
-
msg.content =
|
|
675
|
-
textContent || '_Attachment removed due to error_';
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
}
|
|
645
|
+
this._stripAttachments(
|
|
646
|
+
[...this._history, ...responseHistory],
|
|
647
|
+
'_Attachment removed due to error_'
|
|
648
|
+
);
|
|
679
649
|
helpMessage +=
|
|
680
650
|
'\n\nAttachments have been removed from history. Please send your prompt again.';
|
|
681
651
|
}
|
|
@@ -735,6 +705,27 @@ export class AgentManager implements IAgentManager {
|
|
|
735
705
|
this._tokenUsageChanged.emit(this._tokenUsage);
|
|
736
706
|
}
|
|
737
707
|
|
|
708
|
+
/**
|
|
709
|
+
* Removes image and file parts from all user messages in the given list.
|
|
710
|
+
*/
|
|
711
|
+
private _stripAttachments(
|
|
712
|
+
messages: ModelMessage[],
|
|
713
|
+
placeholder: string
|
|
714
|
+
): void {
|
|
715
|
+
for (const msg of messages) {
|
|
716
|
+
if (msg.role === 'user' && Array.isArray(msg.content)) {
|
|
717
|
+
const hasMedia = msg.content.some(p => p.type !== 'text');
|
|
718
|
+
if (hasMedia) {
|
|
719
|
+
const textContent = msg.content
|
|
720
|
+
.filter(p => p.type === 'text')
|
|
721
|
+
.map(p => (p as { text: string }).text)
|
|
722
|
+
.join('\n');
|
|
723
|
+
msg.content = textContent || placeholder;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
|
|
738
729
|
/**
|
|
739
730
|
* Gets the configured context window for the active provider.
|
|
740
731
|
*/
|
|
@@ -1092,14 +1083,13 @@ ${richOutputWorkflowInstruction}`;
|
|
|
1092
1083
|
this._agentEvent.emit({
|
|
1093
1084
|
type: 'tool_approval_request',
|
|
1094
1085
|
data: {
|
|
1095
|
-
approvalId,
|
|
1096
1086
|
toolCallId: toolCall.toolCallId,
|
|
1097
1087
|
toolName: toolCall.toolName,
|
|
1098
1088
|
args: toolCall.input
|
|
1099
1089
|
}
|
|
1100
1090
|
});
|
|
1101
1091
|
|
|
1102
|
-
const approved = await this._waitForApproval(
|
|
1092
|
+
const approved = await this._waitForApproval(toolCall.toolCallId);
|
|
1103
1093
|
|
|
1104
1094
|
result.approvalProcessed = true;
|
|
1105
1095
|
result.approvalResponse = {
|
|
@@ -1116,12 +1106,12 @@ ${richOutputWorkflowInstruction}`;
|
|
|
1116
1106
|
|
|
1117
1107
|
/**
|
|
1118
1108
|
* Waits for user approval of a tool call.
|
|
1119
|
-
* @param
|
|
1109
|
+
* @param toolCallId The tool call ID to wait for approval
|
|
1120
1110
|
* @returns Promise that resolves to true if approved, false if rejected
|
|
1121
1111
|
*/
|
|
1122
|
-
private _waitForApproval(
|
|
1112
|
+
private _waitForApproval(toolCallId: string): Promise<boolean> {
|
|
1123
1113
|
return new Promise(resolve => {
|
|
1124
|
-
this._pendingApprovals.set(
|
|
1114
|
+
this._pendingApprovals.set(toolCallId, {
|
|
1125
1115
|
resolve: (approved: boolean) => {
|
|
1126
1116
|
resolve(approved);
|
|
1127
1117
|
}
|
|
@@ -6,6 +6,7 @@ import { Contents } from '@jupyterlab/services';
|
|
|
6
6
|
import { AIChatModel } from './chat-model';
|
|
7
7
|
import type {
|
|
8
8
|
IAgentManagerFactory,
|
|
9
|
+
IAIChatModel,
|
|
9
10
|
IAISettingsModel,
|
|
10
11
|
IChatModelHandler,
|
|
11
12
|
ICreateChatOptions,
|
|
@@ -28,7 +29,7 @@ export class ChatModelHandler implements IChatModelHandler {
|
|
|
28
29
|
this._contentsManager = options.contentsManager;
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
createModel(options: ICreateChatOptions):
|
|
32
|
+
createModel(options: ICreateChatOptions): IAIChatModel {
|
|
32
33
|
const { name, activeProvider, tokenUsage, messages, autosave, title } =
|
|
33
34
|
options;
|
|
34
35
|
|
|
@@ -49,7 +50,8 @@ export class ChatModelHandler implements IChatModelHandler {
|
|
|
49
50
|
agentManager,
|
|
50
51
|
activeCellManager: this._activeCellManager,
|
|
51
52
|
documentManager: this._docManager,
|
|
52
|
-
contentsManager: this._contentsManager
|
|
53
|
+
contentsManager: this._contentsManager,
|
|
54
|
+
providerRegistry: this._providerRegistry
|
|
53
55
|
});
|
|
54
56
|
|
|
55
57
|
messages?.forEach(message => {
|