@aleph-alpha/chat-kit 2.0.0 → 2.1.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.
@@ -1 +1 @@
1
- {"version":3,"file":"useFileUpload.d.ts","sourceRoot":"","sources":["../../../src/composables/fileUpload/useFileUpload.ts"],"names":[],"mappings":"AACA,OAAO,EAkBL,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EAKzB,MAAM,SAAS,CAAC;AAEjB,cAAc,SAAS,CAAC;AAybxB,wBAAgB,aAAa,CAC3B,OAAO,EAAE,oBAAoB,GAC5B,mBAAmB,CAmwBrB"}
1
+ {"version":3,"file":"useFileUpload.d.ts","sourceRoot":"","sources":["../../../src/composables/fileUpload/useFileUpload.ts"],"names":[],"mappings":"AACA,OAAO,EAkBL,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EAKzB,MAAM,SAAS,CAAC;AAEjB,cAAc,SAAS,CAAC;AAybxB,wBAAgB,aAAa,CAC3B,OAAO,EAAE,oBAAoB,GAC5B,mBAAmB,CA6xBrB"}
@@ -1,4 +1,4 @@
1
- import { c, d, u, b, e, f } from "../index-Ct5hD214.js";
1
+ import { c, d, u, b, e, f } from "../index-DrtHeZpl.js";
2
2
  export {
3
3
  c as createDocumentUploadProvider,
4
4
  d as defaultDocumentUploadConfig,
@@ -1033,6 +1033,19 @@ function useFileUpload(options) {
1033
1033
  for (const key of involvedStateKeys) {
1034
1034
  updateEntry(key, { status: "processing", progress: 0 });
1035
1035
  }
1036
+ const completeInvolvedFiles = (documents = []) => {
1037
+ const documentIdByFileId = new Map(
1038
+ documents.filter((doc) => doc.file_id && doc.document_id).map((doc) => [doc.file_id, doc.document_id])
1039
+ );
1040
+ for (const key of involvedStateKeys) {
1041
+ updateEntry(key, { status: "success", progress: 100 });
1042
+ const remoteFileId = files.value.get(key)?.remoteFileId;
1043
+ const documentId = remoteFileId ? documentIdByFileId.get(remoteFileId) : void 0;
1044
+ if (documentId) {
1045
+ updateFileMetadata(key, { documentId });
1046
+ }
1047
+ }
1048
+ };
1036
1049
  const runResponse = await client.post(
1037
1050
  endpoints.workflowRun(storeId, workflowId),
1038
1051
  { input },
@@ -1075,9 +1088,7 @@ function useFileUpload(options) {
1075
1088
  if (data.status === "completed") {
1076
1089
  workflowRun.value.status = "completed";
1077
1090
  workflowRun.value.completedAt = now();
1078
- for (const key of involvedStateKeys) {
1079
- updateEntry(key, { status: "success", progress: 100 });
1080
- }
1091
+ completeInvolvedFiles(Array.isArray(data.documents) ? data.documents : []);
1081
1092
  emit({ type: "workflow:completed", runId });
1082
1093
  } else if (data.status === "failed" || data.status === "error") {
1083
1094
  workflowRun.value.status = "failed";
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { u } from "./useMessageHandler-CMdy-lm0.js";
2
2
  import { C, d, p, u as u2, a } from "./useChatKitLabels-ZutacPad.js";
3
- import { S, c, d as d2, a as a2, u as u3, b, e, f } from "./index-Ct5hD214.js";
3
+ import { S, c, d as d2, a as a2, u as u3, b, e, f } from "./index-DrtHeZpl.js";
4
4
  import { _, a as a3, b as b2, C as C2, c as c2, d as d3, e as e2, f as f2, g, h, i, j, k, l, m, n, o, p as p2, q, r, s, t } from "./CkInput.vue_vue_type_script_setup_true_lang-DPZedAQS.js";
5
5
  export {
6
6
  C as CHAT_KIT_LABELS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aleph-alpha/chat-kit",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Chat kit package for building chat interfaces with Vue",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -0,0 +1,111 @@
1
+ import { useFileUpload } from './useFileUpload';
2
+ import type { FileEntry, HttpClient, SseEvent } from './types';
3
+
4
+ /**
5
+ * Build a minimal `FileEntry` in the post-upload `processing` state so
6
+ * `runWorkflow` treats it as an involved file (it filters on `remoteFileId`).
7
+ */
8
+ function makeEntry(id: string, remoteFileId: string): FileEntry {
9
+ return {
10
+ id,
11
+ groupId: 'group-1',
12
+ fileName: `${id}.pdf`,
13
+ fileSize: 1,
14
+ fileType: 'application/pdf',
15
+ status: 'processing',
16
+ progress: 0,
17
+ queuedAt: 'now',
18
+ uploadStartedAt: null,
19
+ uploadCompletedAt: null,
20
+ cancelledAt: null,
21
+ removedAt: null,
22
+ uploadDurationMs: null,
23
+ remoteFileId,
24
+ error: null,
25
+ attemptCount: 0,
26
+ lastAttemptAt: null,
27
+ thumbnail: null,
28
+ metadata: {},
29
+ };
30
+ }
31
+
32
+ /**
33
+ * Mock `HttpClient` whose `stream` captures the subscriber so the test can
34
+ * drive SSE events synchronously. `post` resolves the workflow run id.
35
+ */
36
+ function createMockClient(captured: { cb?: (event: SseEvent) => void }) {
37
+ return {
38
+ get: vi.fn(),
39
+ delete: vi.fn(),
40
+ post: vi.fn().mockResolvedValue({ id: 'run-1' }),
41
+ stream: vi.fn(() => ({
42
+ subscribe: (cb: (event: SseEvent) => void) => {
43
+ captured.cb = cb;
44
+ },
45
+ close: vi.fn(),
46
+ })),
47
+ } as unknown as HttpClient;
48
+ }
49
+
50
+ function completeEvent(
51
+ documents: Array<{ document_id?: string; file_id?: string }>,
52
+ ): SseEvent {
53
+ return {
54
+ event: 'complete',
55
+ data: JSON.stringify({
56
+ document_ids: documents.map((d) => d.document_id),
57
+ documents,
58
+ status: 'completed',
59
+ }),
60
+ };
61
+ }
62
+
63
+ describe('useFileUpload runWorkflow', () => {
64
+ it('stamps documentId onto each file from the completed event, matched by file_id', async () => {
65
+ const captured: { cb?: (event: SseEvent) => void } = {};
66
+ const upload = useFileUpload({
67
+ client: createMockClient(captured),
68
+ workflowId: 'wf',
69
+ storeId: 'ss-1',
70
+ });
71
+
72
+ upload.files.value.set('key-1', makeEntry('key-1', 'file-1'));
73
+ upload.files.value.set('key-2', makeEntry('key-2', 'file-2'));
74
+
75
+ await upload.runWorkflow(['file-1', 'file-2']);
76
+ expect(captured.cb).toBeDefined();
77
+
78
+ // Reverse order on purpose: mapping must be keyed by file_id, not position.
79
+ captured.cb!(
80
+ completeEvent([
81
+ { document_id: 'doc-2', file_id: 'file-2' },
82
+ { document_id: 'doc-1', file_id: 'file-1' },
83
+ ]),
84
+ );
85
+
86
+ expect(upload.getFileState('key-1')?.metadata.documentId).toBe('doc-1');
87
+ expect(upload.getFileState('key-2')?.metadata.documentId).toBe('doc-2');
88
+ expect(upload.getFileState('key-1')?.status).toBe('success');
89
+ expect(upload.getFileState('key-2')?.status).toBe('success');
90
+ });
91
+
92
+ it('marks files successful without a documentId when the event has no documents', async () => {
93
+ const captured: { cb?: (event: SseEvent) => void } = {};
94
+ const upload = useFileUpload({
95
+ client: createMockClient(captured),
96
+ workflowId: 'wf',
97
+ storeId: 'ss-1',
98
+ });
99
+
100
+ upload.files.value.set('key-1', makeEntry('key-1', 'file-1'));
101
+
102
+ await upload.runWorkflow(['file-1']);
103
+ captured.cb!({
104
+ event: 'complete',
105
+ data: JSON.stringify({ status: 'completed' }),
106
+ });
107
+
108
+ expect(upload.getFileState('key-1')?.status).toBe('success');
109
+ expect(upload.getFileState('key-1')?.metadata.documentId).toBeUndefined();
110
+ });
111
+ });
@@ -1054,6 +1054,30 @@ export function useFileUpload(
1054
1054
  updateEntry(key, { status: 'processing', progress: 0 });
1055
1055
  }
1056
1056
 
1057
+ // Mark the involved files successful and stamp the `documentId` resolved
1058
+ // from the terminal event's `documents` array (mapping `file_id` ->
1059
+ // `document_id`) onto each matching entry, so consumers can reference the
1060
+ // produced document directly without a separate lookup.
1061
+ const completeInvolvedFiles = (
1062
+ documents: Array<{ document_id?: string; file_id?: string }> = [],
1063
+ ) => {
1064
+ const documentIdByFileId = new Map(
1065
+ documents
1066
+ .filter((doc) => doc.file_id && doc.document_id)
1067
+ .map((doc) => [doc.file_id, doc.document_id] as const),
1068
+ );
1069
+ for (const key of involvedStateKeys) {
1070
+ updateEntry(key, { status: 'success', progress: 100 });
1071
+ const remoteFileId = files.value.get(key)?.remoteFileId;
1072
+ const documentId = remoteFileId
1073
+ ? documentIdByFileId.get(remoteFileId)
1074
+ : undefined;
1075
+ if (documentId) {
1076
+ updateFileMetadata(key, { documentId });
1077
+ }
1078
+ }
1079
+ };
1080
+
1057
1081
  const runResponse = await client.post<{ id: string }>(
1058
1082
  endpoints.workflowRun(storeId, workflowId),
1059
1083
  { input },
@@ -1087,7 +1111,11 @@ export function useFileUpload(
1087
1111
  sseStream.subscribe((event: SseEvent) => {
1088
1112
  if (!workflowRun.value) return;
1089
1113
 
1090
- let data: { id?: string; status?: string };
1114
+ let data: {
1115
+ id?: string;
1116
+ status?: string;
1117
+ documents?: Array<{ document_id?: string; file_id?: string }>;
1118
+ };
1091
1119
  try {
1092
1120
  data = JSON.parse(event.data);
1093
1121
  } catch {
@@ -1105,9 +1133,7 @@ export function useFileUpload(
1105
1133
  if (data.status === 'completed') {
1106
1134
  workflowRun.value.status = 'completed';
1107
1135
  workflowRun.value.completedAt = now();
1108
- for (const key of involvedStateKeys) {
1109
- updateEntry(key, { status: 'success', progress: 100 });
1110
- }
1136
+ completeInvolvedFiles(Array.isArray(data.documents) ? data.documents : []);
1111
1137
  emit({ type: 'workflow:completed', runId });
1112
1138
  } else if (data.status === 'failed' || data.status === 'error') {
1113
1139
  workflowRun.value.status = 'failed';