@jupyter-ai/persona-manager 0.2.0-a3 → 0.2.0-a4
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/index.js +11 -3
- package/lib/persona-controls.d.ts +6 -0
- package/lib/persona-controls.js +17 -1
- package/lib/persona-events.d.ts +1 -0
- package/lib/persona-events.js +1 -0
- package/package.json +1 -1
- package/src/index.ts +12 -3
- package/src/persona-controls.tsx +24 -1
- package/src/persona-events.ts +2 -0
package/lib/index.js
CHANGED
|
@@ -76,9 +76,17 @@ const toolbarPlugin = {
|
|
|
76
76
|
provides: IInputToolbarRegistryFactory,
|
|
77
77
|
requires: [IPersonaControlRegistry, IPersonaSessionRegistry],
|
|
78
78
|
activate: (app, controlRegistry, sessionRegistry) => {
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
const
|
|
79
|
+
// The event bus front-end; `PersonaControls` uses it to emit
|
|
80
|
+
// `persona_selected` on selection.
|
|
81
|
+
const events = app.serviceManager.events;
|
|
82
|
+
// Wrap the persona controls to inject the control + session registries and
|
|
83
|
+
// the event manager, which the generic toolbar-item props don't carry.
|
|
84
|
+
const PersonaControlsItem = (itemProps) => PersonaControls({
|
|
85
|
+
...itemProps,
|
|
86
|
+
controlRegistry,
|
|
87
|
+
sessionRegistry,
|
|
88
|
+
events
|
|
89
|
+
});
|
|
82
90
|
return {
|
|
83
91
|
create: () => {
|
|
84
92
|
// Start with the default toolbar (Send, Attach, Cancel, SaveEdit)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Event } from '@jupyterlab/services';
|
|
1
2
|
import { InputToolbarRegistry } from '@jupyter/chat';
|
|
2
3
|
import { PersonaOption, Usage } from './awareness';
|
|
3
4
|
import { PersonaSessionRegistry, PersonaSessionState } from './persona-events';
|
|
@@ -177,5 +178,10 @@ export declare function PersonaControls(props: InputToolbarRegistry.IToolbarItem
|
|
|
177
178
|
* Optional so the component still works without it (renders nothing).
|
|
178
179
|
*/
|
|
179
180
|
sessionRegistry?: PersonaSessionRegistry;
|
|
181
|
+
/**
|
|
182
|
+
* The event bus front-end, used to emit a `persona_selected` event when the
|
|
183
|
+
* user picks a persona so the server prepares it eagerly.
|
|
184
|
+
*/
|
|
185
|
+
events?: Event.IManager;
|
|
180
186
|
}): JSX.Element | null;
|
|
181
187
|
export {};
|
package/lib/persona-controls.js
CHANGED
|
@@ -6,6 +6,7 @@ import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
|
|
|
6
6
|
import { PageConfig } from '@jupyterlab/coreutils';
|
|
7
7
|
import { EMPTY_USAGE } from './awareness';
|
|
8
8
|
import { buildMessageMetadata, emptyPersonaSettings } from './metadata';
|
|
9
|
+
import { PERSONA_SELECTED_EVENT_SCHEMA_ID } from './persona-events';
|
|
9
10
|
const SELECTOR_CLASS = 'jp-jai-personaControls';
|
|
10
11
|
const MENU_CLASS = 'jp-jai-controlMenu';
|
|
11
12
|
const USAGE_CLASS = 'jp-jai-usage';
|
|
@@ -635,7 +636,7 @@ export function UsageChip(props) {
|
|
|
635
636
|
*/
|
|
636
637
|
export function PersonaControls(props) {
|
|
637
638
|
var _a, _b, _c, _d, _e, _f;
|
|
638
|
-
const { chatModel, model, controlRegistry, sessionRegistry } = props;
|
|
639
|
+
const { chatModel, model, controlRegistry, sessionRegistry, events } = props;
|
|
639
640
|
// The chat's stable id scopes persona events to this chat. It is assigned
|
|
640
641
|
// asynchronously (once the model is `ready`: the WS connection frame arrives,
|
|
641
642
|
// or the RTC document syncs), so track it in state and update it when the
|
|
@@ -748,6 +749,21 @@ export function PersonaControls(props) {
|
|
|
748
749
|
model.clearMetadata();
|
|
749
750
|
model.updateMetadata(buildMessageMetadata(selectedId, settings));
|
|
750
751
|
}, [model, metadataSignature]);
|
|
752
|
+
// On selection, tell the server to prepare the persona by
|
|
753
|
+
// emitting `persona_selected` over the event bus, so its controls appear
|
|
754
|
+
// before the first message. Skips "No one"; idempotent server-side.
|
|
755
|
+
useEffect(() => {
|
|
756
|
+
if (!events || !chatId || !selectedId) {
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
void events
|
|
760
|
+
.emit({
|
|
761
|
+
schema_id: PERSONA_SELECTED_EVENT_SCHEMA_ID,
|
|
762
|
+
version: '1',
|
|
763
|
+
data: { chat_id: chatId, persona_id: selectedId }
|
|
764
|
+
})
|
|
765
|
+
.catch(e => console.warn('Error emitting persona_selected event: ', e));
|
|
766
|
+
}, [events, chatId, selectedId]);
|
|
751
767
|
// No personas yet. While the manager's slot or its first list read is still
|
|
752
768
|
// pending, show a loading placeholder (on slow networks this takes seconds);
|
|
753
769
|
// once ready with no personas, show nothing.
|
package/lib/persona-events.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { ISignal } from '@lumino/signaling';
|
|
|
5
5
|
import { CommandOption, ModelConfiguration, PersonaOption, SettingConfiguration, Usage } from './awareness';
|
|
6
6
|
export declare const PERSONAS_EVENT_SCHEMA_ID = "https://schema.jupyter.org/jupyter_ai_persona_manager/personas/v1";
|
|
7
7
|
export declare const PERSONA_STATE_EVENT_SCHEMA_ID = "https://schema.jupyter.org/jupyter_ai_persona_manager/persona_state/v1";
|
|
8
|
+
export declare const PERSONA_SELECTED_EVENT_SCHEMA_ID = "https://schema.jupyter.org/jupyter_ai_persona_manager/persona_selected/v1";
|
|
8
9
|
/** The wire shape of a `persona_state` event. */
|
|
9
10
|
type PersonaStatePayload = {
|
|
10
11
|
chat_id?: string;
|
package/lib/persona-events.js
CHANGED
|
@@ -3,6 +3,7 @@ import { Signal } from '@lumino/signaling';
|
|
|
3
3
|
import { EMPTY_MODEL_CONFIGURATION, EMPTY_USAGE } from './awareness';
|
|
4
4
|
export const PERSONAS_EVENT_SCHEMA_ID = 'https://schema.jupyter.org/jupyter_ai_persona_manager/personas/v1';
|
|
5
5
|
export const PERSONA_STATE_EVENT_SCHEMA_ID = 'https://schema.jupyter.org/jupyter_ai_persona_manager/persona_state/v1';
|
|
6
|
+
export const PERSONA_SELECTED_EVENT_SCHEMA_ID = 'https://schema.jupyter.org/jupyter_ai_persona_manager/persona_selected/v1';
|
|
6
7
|
/**
|
|
7
8
|
* One persona's live session state, built from a `persona_state` event.
|
|
8
9
|
* Immutable: each update produces a new instance, so React consumers see a new
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -119,11 +119,20 @@ const toolbarPlugin: JupyterFrontEndPlugin<IInputToolbarRegistryFactory> = {
|
|
|
119
119
|
controlRegistry: IPersonaControlRegistry,
|
|
120
120
|
sessionRegistry: PersonaSessionRegistry
|
|
121
121
|
): IInputToolbarRegistryFactory => {
|
|
122
|
-
//
|
|
123
|
-
//
|
|
122
|
+
// The event bus front-end; `PersonaControls` uses it to emit
|
|
123
|
+
// `persona_selected` on selection.
|
|
124
|
+
const events = app.serviceManager.events;
|
|
125
|
+
// Wrap the persona controls to inject the control + session registries and
|
|
126
|
+
// the event manager, which the generic toolbar-item props don't carry.
|
|
124
127
|
const PersonaControlsItem = (
|
|
125
128
|
itemProps: InputToolbarRegistry.IToolbarItemProps
|
|
126
|
-
) =>
|
|
129
|
+
) =>
|
|
130
|
+
PersonaControls({
|
|
131
|
+
...itemProps,
|
|
132
|
+
controlRegistry,
|
|
133
|
+
sessionRegistry,
|
|
134
|
+
events
|
|
135
|
+
});
|
|
127
136
|
return {
|
|
128
137
|
create: () => {
|
|
129
138
|
// Start with the default toolbar (Send, Attach, Cancel, SaveEdit)
|
package/src/persona-controls.tsx
CHANGED
|
@@ -21,6 +21,7 @@ import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
|
|
|
21
21
|
import CheckIcon from '@mui/icons-material/Check';
|
|
22
22
|
import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
|
|
23
23
|
import { PageConfig } from '@jupyterlab/coreutils';
|
|
24
|
+
import { Event } from '@jupyterlab/services';
|
|
24
25
|
import { InputToolbarRegistry } from '@jupyter/chat';
|
|
25
26
|
import {
|
|
26
27
|
EMPTY_USAGE,
|
|
@@ -35,6 +36,7 @@ import {
|
|
|
35
36
|
emptyPersonaSettings
|
|
36
37
|
} from './metadata';
|
|
37
38
|
import { IPersonaControlRegistry } from './persona-control-registry';
|
|
39
|
+
import { PERSONA_SELECTED_EVENT_SCHEMA_ID } from './persona-events';
|
|
38
40
|
|
|
39
41
|
const SELECTOR_CLASS = 'jp-jai-personaControls';
|
|
40
42
|
const MENU_CLASS = 'jp-jai-controlMenu';
|
|
@@ -1072,9 +1074,14 @@ export function PersonaControls(
|
|
|
1072
1074
|
* Optional so the component still works without it (renders nothing).
|
|
1073
1075
|
*/
|
|
1074
1076
|
sessionRegistry?: PersonaSessionRegistry;
|
|
1077
|
+
/**
|
|
1078
|
+
* The event bus front-end, used to emit a `persona_selected` event when the
|
|
1079
|
+
* user picks a persona so the server prepares it eagerly.
|
|
1080
|
+
*/
|
|
1081
|
+
events?: Event.IManager;
|
|
1075
1082
|
}
|
|
1076
1083
|
): JSX.Element | null {
|
|
1077
|
-
const { chatModel, model, controlRegistry, sessionRegistry } = props;
|
|
1084
|
+
const { chatModel, model, controlRegistry, sessionRegistry, events } = props;
|
|
1078
1085
|
// The chat's stable id scopes persona events to this chat. It is assigned
|
|
1079
1086
|
// asynchronously (once the model is `ready`: the WS connection frame arrives,
|
|
1080
1087
|
// or the RTC document syncs), so track it in state and update it when the
|
|
@@ -1207,6 +1214,22 @@ export function PersonaControls(
|
|
|
1207
1214
|
model.updateMetadata(buildMessageMetadata(selectedId, settings));
|
|
1208
1215
|
}, [model, metadataSignature]);
|
|
1209
1216
|
|
|
1217
|
+
// On selection, tell the server to prepare the persona by
|
|
1218
|
+
// emitting `persona_selected` over the event bus, so its controls appear
|
|
1219
|
+
// before the first message. Skips "No one"; idempotent server-side.
|
|
1220
|
+
useEffect(() => {
|
|
1221
|
+
if (!events || !chatId || !selectedId) {
|
|
1222
|
+
return;
|
|
1223
|
+
}
|
|
1224
|
+
void events
|
|
1225
|
+
.emit({
|
|
1226
|
+
schema_id: PERSONA_SELECTED_EVENT_SCHEMA_ID,
|
|
1227
|
+
version: '1',
|
|
1228
|
+
data: { chat_id: chatId, persona_id: selectedId }
|
|
1229
|
+
})
|
|
1230
|
+
.catch(e => console.warn('Error emitting persona_selected event: ', e));
|
|
1231
|
+
}, [events, chatId, selectedId]);
|
|
1232
|
+
|
|
1210
1233
|
// No personas yet. While the manager's slot or its first list read is still
|
|
1211
1234
|
// pending, show a loading placeholder (on slow networks this takes seconds);
|
|
1212
1235
|
// once ready with no personas, show nothing.
|
package/src/persona-events.ts
CHANGED
|
@@ -31,6 +31,8 @@ export const PERSONAS_EVENT_SCHEMA_ID =
|
|
|
31
31
|
'https://schema.jupyter.org/jupyter_ai_persona_manager/personas/v1';
|
|
32
32
|
export const PERSONA_STATE_EVENT_SCHEMA_ID =
|
|
33
33
|
'https://schema.jupyter.org/jupyter_ai_persona_manager/persona_state/v1';
|
|
34
|
+
export const PERSONA_SELECTED_EVENT_SCHEMA_ID =
|
|
35
|
+
'https://schema.jupyter.org/jupyter_ai_persona_manager/persona_selected/v1';
|
|
34
36
|
|
|
35
37
|
/** The wire shape of a `persona_state` event. */
|
|
36
38
|
type PersonaStatePayload = {
|