Skip to content

Commit e2b9ff1

Browse files
authored
Abstract ChatModel class (#197)
* Abstract ChatModel class * lint * Rename ChatModel to AbstractChatModel and ChatModel namespace to IChatModel
1 parent 6ba6c0e commit e2b9ff1

File tree

6 files changed

+59
-34
lines changed

6 files changed

+59
-34
lines changed

docs/jupyter-chat-example/src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
ActiveCellManager,
88
AttachmentOpenerRegistry,
99
buildChatSidebar,
10-
ChatModel,
10+
AbstractChatModel,
1111
IAttachment,
1212
IChatMessage,
1313
INewMessage,
@@ -24,7 +24,7 @@ import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
2424
import { ISettingRegistry } from '@jupyterlab/settingregistry';
2525
import { UUID } from '@lumino/coreutils';
2626

27-
class MyChatModel extends ChatModel {
27+
class MyChatModel extends AbstractChatModel {
2828
sendMessage(
2929
newMessage: INewMessage
3030
): Promise<boolean | void> | boolean | void {

docs/source/developers/developing_extensions/extension-providing-chat.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ As an example, here is a simple model that logs the message to the console and a
5252
the message list.
5353

5454
```typescript
55-
import { ChatModel, IChatMessage, INewMessage } from '@jupyter/chat';
55+
import { AbstractChatModel, IChatMessage, INewMessage } from '@jupyter/chat';
5656

57-
class MyModel extends ChatModel {
57+
class MyModel extends AbstractChatModel {
5858
sendMessage(
5959
newMessage: INewMessage
6060
): Promise<boolean | void> | boolean | void {
@@ -94,7 +94,7 @@ methods to correctly manage message transmission and reception.
9494

9595
```typescript
9696
import {
97-
ChatModel,
97+
AbstractChatModel,
9898
ChatWidget,
9999
IChatMessage,
100100
INewMessage
@@ -106,7 +106,7 @@ import {
106106
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
107107
import { UUID } from '@lumino/coreutils';
108108

109-
class MyModel extends ChatModel {
109+
class MyModel extends AbstractChatModel {
110110
sendMessage(
111111
newMessage: INewMessage
112112
): Promise<boolean | void> | boolean | void {
@@ -242,7 +242,7 @@ jupyterlab. In the previous example, the modification would be:
242242
```typescript
243243
import {
244244
ActiveCellManager,
245-
ChatModel,
245+
AbstractChatModel,
246246
ChatWidget,
247247
IChatMessage,
248248
INewMessage
@@ -325,7 +325,7 @@ specific function for an attachment type.
325325
```typescript
326326
import {
327327
AttachmentOpenerRegistry,
328-
ChatModel,
328+
AbstractChatModel,
329329
ChatWidget,
330330
IAttachment,
331331
IChatMessage,
@@ -335,7 +335,7 @@ import { IDefaultFileBrowser } from '@jupyterlab/filebrowser';
335335

336336
...
337337

338-
class MyModel extends ChatModel {
338+
class MyModel extends AbstractChatModel {
339339
sendMessage(
340340
newMessage: INewMessage
341341
): Promise<boolean | void> | boolean | void {

packages/jupyter-chat/src/__tests__/model.spec.ts

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,40 @@
77
* Example of [Jest](https://jestjs.io/docs/getting-started) unit tests
88
*/
99

10-
import { ChatModel, IChatModel } from '../model';
11-
import { IChatMessage } from '../types';
10+
import { AbstractChatModel, IChatModel } from '../model';
11+
import { IChatMessage, INewMessage } from '../types';
12+
13+
class MyChatModel extends AbstractChatModel {
14+
sendMessage(message: INewMessage): Promise<boolean | void> | boolean | void {
15+
// No-op
16+
}
17+
}
1218

1319
describe('test chat model', () => {
1420
describe('model instantiation', () => {
15-
it('should create a ChatModel', () => {
16-
const model = new ChatModel();
17-
expect(model).toBeInstanceOf(ChatModel);
21+
it('should create an AbstractChatModel', () => {
22+
const model = new MyChatModel();
23+
expect(model).toBeInstanceOf(AbstractChatModel);
1824
});
1925

20-
it('should dispose a ChatModel', () => {
21-
const model = new ChatModel();
26+
it('should dispose an AbstractChatModel', () => {
27+
const model = new MyChatModel();
2228
model.dispose();
2329
expect(model.isDisposed).toBeTruthy();
2430
});
2531
});
2632

2733
describe('incoming message', () => {
28-
class TestChat extends ChatModel {
34+
class TestChat extends AbstractChatModel {
2935
protected formatChatMessage(message: IChatMessage): IChatMessage {
3036
message.body = 'formatted msg';
3137
return message;
3238
}
39+
sendMessage(
40+
message: INewMessage
41+
): Promise<boolean | void> | boolean | void {
42+
// No-op
43+
}
3344
}
3445

3546
let model: IChatModel;
@@ -47,7 +58,7 @@ describe('test chat model', () => {
4758
});
4859

4960
it('should signal incoming message', () => {
50-
model = new ChatModel();
61+
model = new MyChatModel();
5162
model.messagesUpdated.connect((sender: IChatModel) => {
5263
expect(sender).toBe(model);
5364
messages = model.messages;
@@ -72,12 +83,12 @@ describe('test chat model', () => {
7283

7384
describe('model config', () => {
7485
it('should have empty config', () => {
75-
const model = new ChatModel();
86+
const model = new MyChatModel();
7687
expect(model.config.sendWithShiftEnter).toBeUndefined();
7788
});
7889

7990
it('should allow config', () => {
80-
const model = new ChatModel({ config: { sendWithShiftEnter: true } });
91+
const model = new MyChatModel({ config: { sendWithShiftEnter: true } });
8192
expect(model.config.sendWithShiftEnter).toBeTruthy();
8293
});
8394
});

packages/jupyter-chat/src/__tests__/widgets.spec.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,32 @@ import {
1111
IRenderMimeRegistry,
1212
RenderMimeRegistry
1313
} from '@jupyterlab/rendermime';
14-
import { ChatModel, IChatModel } from '../model';
14+
import { AbstractChatModel, IChatModel } from '../model';
15+
import { INewMessage } from '../types';
1516
import { ChatWidget } from '../widgets/chat-widget';
1617

18+
class MyChatModel extends AbstractChatModel {
19+
sendMessage(message: INewMessage): Promise<boolean | void> | boolean | void {
20+
// No-op
21+
}
22+
}
23+
1724
describe('test chat widget', () => {
1825
let model: IChatModel;
1926
let rmRegistry: IRenderMimeRegistry;
2027

2128
beforeEach(() => {
22-
model = new ChatModel();
29+
model = new MyChatModel();
2330
rmRegistry = new RenderMimeRegistry();
2431
});
2532

2633
describe('model instantiation', () => {
27-
it('should create a ChatModel', () => {
34+
it('should create an AbstractChatModel', () => {
2835
const widget = new ChatWidget({ model, rmRegistry });
2936
expect(widget).toBeInstanceOf(ChatWidget);
3037
});
3138

32-
it('should dispose a ChatModel', () => {
39+
it('should dispose an AbstractChatModel', () => {
3340
const widget = new ChatWidget({ model, rmRegistry });
3441
widget.dispose();
3542
expect(widget.isDisposed).toBeTruthy();

packages/jupyter-chat/src/model.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -175,15 +175,16 @@ export interface IChatModel extends IDisposable {
175175
}
176176

177177
/**
178-
* The default chat model implementation.
179-
* It is not able to send or update a message by itself, since it depends on the
180-
* chosen technology.
178+
* An abstract implementation of IChatModel.
179+
*
180+
* The class inheriting from it must implement at least:
181+
* - sendMessage(message: INewMessage)
181182
*/
182-
export class ChatModel implements IChatModel {
183+
export abstract class AbstractChatModel implements IChatModel {
183184
/**
184185
* Create a new chat model.
185186
*/
186-
constructor(options: ChatModel.IOptions = {}) {
187+
constructor(options: IChatModel.IOptions = {}) {
187188
if (options.id) {
188189
this.id = options.id;
189190
}
@@ -421,7 +422,9 @@ export class ChatModel implements IChatModel {
421422
* @param message - the message to send.
422423
* @returns whether the message has been sent or not.
423424
*/
424-
sendMessage(message: INewMessage): Promise<boolean | void> | boolean | void {}
425+
abstract sendMessage(
426+
message: INewMessage
427+
): Promise<boolean | void> | boolean | void;
425428

426429
/**
427430
* Clear the message list.
@@ -609,7 +612,7 @@ export class ChatModel implements IChatModel {
609612
/**
610613
* The chat model namespace.
611614
*/
612-
export namespace ChatModel {
615+
export namespace IChatModel {
613616
/**
614617
* The instantiation options for a ChatModel.
615618
*/

packages/jupyterlab-chat/src/model.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
*/
55

66
import {
7-
ChatModel,
7+
AbstractChatModel,
88
IAttachment,
99
IChatMessage,
10+
IChatModel,
1011
IInputModel,
1112
INewMessage,
1213
IUser
@@ -26,7 +27,7 @@ const WRITING_DELAY = 1000;
2627
* Chat model namespace.
2728
*/
2829
export namespace LabChatModel {
29-
export interface IOptions extends ChatModel.IOptions {
30+
export interface IOptions extends IChatModel.IOptions {
3031
widgetConfig: IWidgetConfig;
3132
user: User.IIdentity | null;
3233
sharedModel?: YChat;
@@ -37,7 +38,10 @@ export namespace LabChatModel {
3738
/**
3839
* The chat model.
3940
*/
40-
export class LabChatModel extends ChatModel implements DocumentRegistry.IModel {
41+
export class LabChatModel
42+
extends AbstractChatModel
43+
implements DocumentRegistry.IModel
44+
{
4145
constructor(options: LabChatModel.IOptions) {
4246
super(options);
4347

0 commit comments

Comments
 (0)