@aleph-alpha/chat-kit 1.1.0 → 1.2.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/dist/{CkInput.vue_vue_type_script_setup_true_lang-DpYyyCgU.js → CkInput.vue_vue_type_script_setup_true_lang-CRymGkQs.js} +1 -1
- package/dist/components/index.js +1 -1
- package/dist/composables/index.d.ts +2 -0
- package/dist/composables/index.d.ts.map +1 -1
- package/dist/composables/index.js +3 -2
- package/dist/composables/useConversationSessions.d.ts +29 -0
- package/dist/composables/useConversationSessions.d.ts.map +1 -0
- package/dist/handlers/index.js +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -6
- package/dist/purify.es-md74IFlY.js +1081 -0
- package/dist/{useChatKitLabels-Dvi2FmjE.js → useChatKitLabels-BmWmMyqX.js} +75 -1152
- package/dist/{useConversations-Ca242D2P.js → useConversationSessions-ulFhtpQr.js} +50 -2
- package/dist/{useMessageHandler-uLHNac39.js → useMessageHandler-BmBdu2EW.js} +4 -1
- package/package.json +1 -1
- package/src/composables/index.ts +6 -0
- package/src/composables/useConversationSessions.spec.ts +86 -0
- package/src/composables/useConversationSessions.ts +85 -0
- package/src/index.ts +8 -1
- package/dist/generateId-BHf0W4Rq.js +0 -6
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { g as generateId } from "./
|
|
1
|
+
import { g as generateId, u as useMessageHandler } from "./useMessageHandler-BmBdu2EW.js";
|
|
2
2
|
import { ref, shallowRef, computed, readonly } from "vue";
|
|
3
|
+
import "./purify.es-md74IFlY.js";
|
|
3
4
|
function secondsToDate(seconds) {
|
|
4
5
|
return new Date(seconds * 1e3);
|
|
5
6
|
}
|
|
@@ -189,7 +190,54 @@ function makePlaceholder(title) {
|
|
|
189
190
|
updatedAt: now
|
|
190
191
|
};
|
|
191
192
|
}
|
|
193
|
+
function useConversationSessions() {
|
|
194
|
+
const sessions = /* @__PURE__ */ new Map();
|
|
195
|
+
const focusedId = ref(null);
|
|
196
|
+
function createSession(conversationId) {
|
|
197
|
+
const existing = sessions.get(conversationId);
|
|
198
|
+
if (existing) return existing;
|
|
199
|
+
const session = {
|
|
200
|
+
id: conversationId,
|
|
201
|
+
messageHandler: useMessageHandler()
|
|
202
|
+
};
|
|
203
|
+
sessions.set(conversationId, session);
|
|
204
|
+
return session;
|
|
205
|
+
}
|
|
206
|
+
function getSession(conversationId) {
|
|
207
|
+
return sessions.get(conversationId);
|
|
208
|
+
}
|
|
209
|
+
function setActiveConversation(conversationId) {
|
|
210
|
+
if (conversationId === null) {
|
|
211
|
+
focusedId.value = null;
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
createSession(conversationId);
|
|
215
|
+
focusedId.value = conversationId;
|
|
216
|
+
}
|
|
217
|
+
function removeSession(conversationId) {
|
|
218
|
+
sessions.delete(conversationId);
|
|
219
|
+
if (focusedId.value === conversationId) {
|
|
220
|
+
focusedId.value = null;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
const activeSession = computed(() => {
|
|
224
|
+
const id = focusedId.value;
|
|
225
|
+
return id !== null ? sessions.get(id) ?? null : null;
|
|
226
|
+
});
|
|
227
|
+
const messageHandler = computed(
|
|
228
|
+
() => activeSession.value?.messageHandler ?? null
|
|
229
|
+
);
|
|
230
|
+
return {
|
|
231
|
+
activeSession,
|
|
232
|
+
messageHandler,
|
|
233
|
+
createSession,
|
|
234
|
+
getSession,
|
|
235
|
+
setActiveConversation,
|
|
236
|
+
removeSession
|
|
237
|
+
};
|
|
238
|
+
}
|
|
192
239
|
export {
|
|
193
|
-
|
|
240
|
+
useConversationSessions as a,
|
|
241
|
+
useConversations as b,
|
|
194
242
|
useChat as u
|
|
195
243
|
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { g as generateId } from "./generateId-BHf0W4Rq.js";
|
|
2
1
|
import { reactive, ref, computed, readonly } from "vue";
|
|
3
2
|
function createEmptyTree() {
|
|
4
3
|
return { nodes: {}, rootId: null };
|
|
@@ -78,6 +77,9 @@ function navigate(tree, targetId) {
|
|
|
78
77
|
if (idx === -1) return;
|
|
79
78
|
parent.activeChildIndex = idx;
|
|
80
79
|
}
|
|
80
|
+
function generateId() {
|
|
81
|
+
return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : String(Date.now());
|
|
82
|
+
}
|
|
81
83
|
const useMessageHandler = () => {
|
|
82
84
|
const tree = reactive(createEmptyTree());
|
|
83
85
|
const currentUserMessage = ref("");
|
|
@@ -178,5 +180,6 @@ const useMessageHandler = () => {
|
|
|
178
180
|
};
|
|
179
181
|
};
|
|
180
182
|
export {
|
|
183
|
+
generateId as g,
|
|
181
184
|
useMessageHandler as u
|
|
182
185
|
};
|
package/package.json
CHANGED
package/src/composables/index.ts
CHANGED
|
@@ -6,4 +6,10 @@ export type {
|
|
|
6
6
|
UseConversationsOptions,
|
|
7
7
|
UseConversationsReturn,
|
|
8
8
|
} from './useConversations';
|
|
9
|
+
export { useConversationSessions } from './useConversationSessions';
|
|
10
|
+
export type {
|
|
11
|
+
ConversationSession,
|
|
12
|
+
MessageHandler,
|
|
13
|
+
UseConversationSessionsReturn,
|
|
14
|
+
} from './useConversationSessions';
|
|
9
15
|
export type { ChatActions, ChatState, UseChatReturn } from './types';
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { nextTick } from 'vue';
|
|
2
|
+
import { useConversationSessions } from './useConversationSessions';
|
|
3
|
+
|
|
4
|
+
describe('useConversationSessions', () => {
|
|
5
|
+
it('starts with no active session', () => {
|
|
6
|
+
const sessions = useConversationSessions();
|
|
7
|
+
|
|
8
|
+
expect(sessions.activeSession.value).toBeNull();
|
|
9
|
+
expect(sessions.messageHandler.value).toBeNull();
|
|
10
|
+
expect(sessions.messageHandler.value?.messages.value ?? []).toEqual([]);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('createSession is idempotent', () => {
|
|
14
|
+
const sessions = useConversationSessions();
|
|
15
|
+
const a = sessions.createSession('c1');
|
|
16
|
+
const b = sessions.createSession('c1');
|
|
17
|
+
|
|
18
|
+
expect(a).toBe(b);
|
|
19
|
+
expect(sessions.getSession('c1')).toBe(a);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('isolates message trees per session', () => {
|
|
23
|
+
const sessions = useConversationSessions();
|
|
24
|
+
const sa = sessions.createSession('a');
|
|
25
|
+
const sb = sessions.createSession('b');
|
|
26
|
+
|
|
27
|
+
expect(sa.messageHandler).not.toBe(sb.messageHandler);
|
|
28
|
+
|
|
29
|
+
sa.messageHandler.setCurrentUserMessage('from A');
|
|
30
|
+
sa.messageHandler.commitUserMessage();
|
|
31
|
+
|
|
32
|
+
expect(sa.messageHandler.messages.value).toHaveLength(1);
|
|
33
|
+
expect(sb.messageHandler.messages.value).toHaveLength(0);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('activeSession tracks the focused conversation handler', async () => {
|
|
37
|
+
const sessions = useConversationSessions();
|
|
38
|
+
sessions.createSession('a');
|
|
39
|
+
sessions.createSession('b');
|
|
40
|
+
sessions.setActiveConversation('a');
|
|
41
|
+
|
|
42
|
+
sessions.activeSession.value?.messageHandler.setCurrentUserMessage('hi');
|
|
43
|
+
sessions.activeSession.value?.messageHandler.commitUserMessage();
|
|
44
|
+
|
|
45
|
+
expect(
|
|
46
|
+
sessions.activeSession.value?.messageHandler.messages.value,
|
|
47
|
+
).toHaveLength(1);
|
|
48
|
+
expect(
|
|
49
|
+
sessions.getSession('b')?.messageHandler.messages.value,
|
|
50
|
+
).toHaveLength(0);
|
|
51
|
+
|
|
52
|
+
sessions.setActiveConversation('b');
|
|
53
|
+
await nextTick();
|
|
54
|
+
|
|
55
|
+
expect(sessions.messageHandler.value).toBe(
|
|
56
|
+
sessions.getSession('b')?.messageHandler,
|
|
57
|
+
);
|
|
58
|
+
expect(sessions.messageHandler.value?.messages.value).toHaveLength(0);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('updating a background session does not change the focused handler messages', async () => {
|
|
62
|
+
const sessions = useConversationSessions();
|
|
63
|
+
const sa = sessions.createSession('a');
|
|
64
|
+
sessions.createSession('b');
|
|
65
|
+
sessions.setActiveConversation('b');
|
|
66
|
+
|
|
67
|
+
sa.messageHandler.setCurrentUserMessage('background');
|
|
68
|
+
sa.messageHandler.commitUserMessage();
|
|
69
|
+
|
|
70
|
+
await nextTick();
|
|
71
|
+
expect(sessions.messageHandler.value?.messages.value ?? []).toEqual([]);
|
|
72
|
+
expect(sa.messageHandler.messages.value).toHaveLength(1);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('removeSession clears focus when that session was active', () => {
|
|
76
|
+
const sessions = useConversationSessions();
|
|
77
|
+
sessions.createSession('x');
|
|
78
|
+
sessions.setActiveConversation('x');
|
|
79
|
+
|
|
80
|
+
sessions.removeSession('x');
|
|
81
|
+
|
|
82
|
+
expect(sessions.getSession('x')).toBeUndefined();
|
|
83
|
+
expect(sessions.activeSession.value).toBeNull();
|
|
84
|
+
expect(sessions.messageHandler.value).toBeNull();
|
|
85
|
+
});
|
|
86
|
+
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { useMessageHandler } from '../handlers';
|
|
2
|
+
import { computed, ref, type ComputedRef, type Ref } from 'vue';
|
|
3
|
+
|
|
4
|
+
export type MessageHandler = ReturnType<typeof useMessageHandler>;
|
|
5
|
+
|
|
6
|
+
/** One conversation’s runtime message tree (`useMessageHandler` per id). */
|
|
7
|
+
export interface ConversationSession {
|
|
8
|
+
readonly id: string;
|
|
9
|
+
readonly messageHandler: MessageHandler;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Per-conversation `useMessageHandler` instances; `setActiveConversation` picks
|
|
14
|
+
* which session is exposed as `activeSession` / `messageHandler`.
|
|
15
|
+
*/
|
|
16
|
+
export interface UseConversationSessionsReturn {
|
|
17
|
+
/** Focused session, or `null`. */
|
|
18
|
+
activeSession: ComputedRef<ConversationSession | null>;
|
|
19
|
+
/** `activeSession?.messageHandler`, or `null`. */
|
|
20
|
+
messageHandler: ComputedRef<MessageHandler | null>;
|
|
21
|
+
/** Get or create a session for `conversationId` (idempotent). */
|
|
22
|
+
createSession: (conversationId: string) => ConversationSession;
|
|
23
|
+
/** Session if it exists; does not create. */
|
|
24
|
+
getSession: (conversationId: string) => ConversationSession | undefined;
|
|
25
|
+
/** Focus `conversationId` (creates session if needed), or `null` to unfocus. */
|
|
26
|
+
setActiveConversation: (conversationId: string | null) => void;
|
|
27
|
+
/** Remove session; clears focus if it was active. */
|
|
28
|
+
removeSession: (conversationId: string) => void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Registry of sessions by id (plain `Map` so nested refs stay valid). */
|
|
32
|
+
export function useConversationSessions(): UseConversationSessionsReturn {
|
|
33
|
+
const sessions = new Map<string, ConversationSession>();
|
|
34
|
+
const focusedId: Ref<string | null> = ref(null);
|
|
35
|
+
|
|
36
|
+
function createSession(conversationId: string): ConversationSession {
|
|
37
|
+
const existing = sessions.get(conversationId);
|
|
38
|
+
if (existing) return existing;
|
|
39
|
+
|
|
40
|
+
const session: ConversationSession = {
|
|
41
|
+
id: conversationId,
|
|
42
|
+
messageHandler: useMessageHandler(),
|
|
43
|
+
};
|
|
44
|
+
sessions.set(conversationId, session);
|
|
45
|
+
return session;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function getSession(conversationId: string): ConversationSession | undefined {
|
|
49
|
+
return sessions.get(conversationId);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function setActiveConversation(conversationId: string | null): void {
|
|
53
|
+
if (conversationId === null) {
|
|
54
|
+
focusedId.value = null;
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
createSession(conversationId);
|
|
58
|
+
focusedId.value = conversationId;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function removeSession(conversationId: string): void {
|
|
62
|
+
sessions.delete(conversationId);
|
|
63
|
+
if (focusedId.value === conversationId) {
|
|
64
|
+
focusedId.value = null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const activeSession = computed<ConversationSession | null>(() => {
|
|
69
|
+
const id = focusedId.value;
|
|
70
|
+
return id !== null ? (sessions.get(id) ?? null) : null;
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const messageHandler = computed<MessageHandler | null>(
|
|
74
|
+
() => activeSession.value?.messageHandler ?? null,
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
activeSession,
|
|
79
|
+
messageHandler,
|
|
80
|
+
createSession,
|
|
81
|
+
getSession,
|
|
82
|
+
setActiveConversation,
|
|
83
|
+
removeSession,
|
|
84
|
+
};
|
|
85
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -24,13 +24,20 @@ export {
|
|
|
24
24
|
export type { ChatKitLabels } from './handlers';
|
|
25
25
|
|
|
26
26
|
// Composables
|
|
27
|
-
export {
|
|
27
|
+
export {
|
|
28
|
+
useChat,
|
|
29
|
+
useConversationSessions,
|
|
30
|
+
useConversations,
|
|
31
|
+
} from './composables';
|
|
28
32
|
export type {
|
|
29
33
|
ChatActions,
|
|
30
34
|
ChatState,
|
|
35
|
+
ConversationSession,
|
|
31
36
|
CreateConversationInput,
|
|
37
|
+
MessageHandler,
|
|
32
38
|
MutationOptions,
|
|
33
39
|
UseChatReturn,
|
|
40
|
+
UseConversationSessionsReturn,
|
|
34
41
|
UseConversationsOptions,
|
|
35
42
|
UseConversationsReturn,
|
|
36
43
|
} from './composables';
|