cozy-search 2.5.1 → 2.6.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/README.md CHANGED
@@ -59,48 +59,72 @@ of verbs (cozy-home and cozy-drive use `ALL`).
59
59
 
60
60
  ### RAG indexing setup
61
61
 
62
- Opening the assistant (`AssistantView` or `AssistantDialog`) calls
63
- `autoprovisionAssistants(client)` once per session: when the
64
- `cozy.assistant.autoprovision` flag lists assistants, it makes sure the
65
- `rag-index` triggers exist, gives the root folder to the assistants that
66
- have no knowledge base folder, then runs
67
- `ensureProvisionedAssistants(client, entries)`.
68
-
69
- A host app should only call the `useRagIndexTriggers` hook (or
70
- `ensureRagIndexTriggers(client)`) at startup: one request when the
71
- triggers already exist, and the knowledge base folders get indexed as
72
- they change before the assistant is ever opened. The assistants are
73
- provisioned when the assistant opens; a host app that wants that earlier
74
- can call `autoprovisionAssistants(client)` or the
75
- `useAssistantsAutoprovision` hook. Every call shares the first one's
76
- promise, the triggers step included, so nothing runs twice.
77
-
78
- `setupRagIndexing(client)` makes sure the instance's two
79
- `rag-index` triggers exist (one on `io.cozy.files`, one on
80
- `io.cozy.ai.chat.assistants`) and gives the root folder to any assistant
81
- that has no knowledge base folder yet — the stack's `rag-index` worker
82
- reads the assistants to know what to index, cozy-search only has to keep
83
- the triggers and the assistants' `knowledgeBase` in shape.
84
-
85
- It needs the following permissions: `io.cozy.triggers` and `io.cozy.jobs`
86
- (to create and launch the triggers), `io.cozy.ai.chat.assistants` and
87
- `io.cozy.files` (to read and migrate the assistants). It is idempotent and
88
- never throws: on a stack whose `rag-index` worker is still reserved, the
89
- 403 is logged and the app keeps working. `ensureProvisionedAssistants`
90
- additionally creates one `io.cozy.accounts` document per provisioned
91
- assistant, and the `dirName` folder in `io.cozy.files`.
92
-
93
- An entry of `cozy.assistant.autoprovision` can carry `"default": true`
94
- (the first flagged entry wins if there are several). Every NEW
95
- conversation then starts on that assistant once its document exists —
96
- from the session after it was provisioned onward. Existing conversations
97
- are unaffected: they keep their own assistant, or stay unscoped if they
98
- had none.
62
+ The stack's `rag-index` worker indexes the files of the assistants'
63
+ knowledge base folders. For that an instance needs two things: its two
64
+ `rag-index` triggers (one on `io.cozy.files`, one on
65
+ `io.cozy.ai.chat.assistants`), and assistants that carry a knowledge base
66
+ folder. cozy-search sets both up when the `cozy.assistant.autoprovision`
67
+ flag lists assistants. Without the flag, it does nothing.
68
+
69
+ #### The flag
70
+
71
+ A list of assistants to create, one entry each:
99
72
 
100
73
  ```json
101
- { "name": "Mes documents", "dirName": "Documents", "default": true }
74
+ [{ "name": "Mes documents", "dirName": "Documents", "default": true }]
102
75
  ```
103
76
 
77
+ - `name`: the name of the assistant. Its id is derived from it.
78
+ - `dirId` or `dirName`: its knowledge base folder. `dirId` wins; it can be
79
+ the root folder or a magic folder (`io.cozy.apps/<slug>`). `dirName` is
80
+ a folder at the root of the Drive, created when it does not exist.
81
+ - `prompt`, `icon`: optional.
82
+ - `default`: new conversations start on this assistant once it exists
83
+ (the first entry flagged so wins). Existing conversations keep their
84
+ own assistant.
85
+
86
+ #### Normal behaviour
87
+
88
+ A host app calls `ensureAssistantsSetup(client)` at startup (or its
89
+ `useAssistantsSetup` hook):
90
+
91
+ 1. It fetches the `rag-index` triggers. When both exist, an earlier
92
+ session went through the setup and it stops there: one request.
93
+ 2. Otherwise it runs the whole setup, `autoprovisionAssistants(client)`:
94
+ each entry of the flag gets its `io.cozy.accounts` document, its
95
+ assistant and its knowledge base folder, then the two triggers are
96
+ created and the files one is launched, which starts the indexing of
97
+ the folders. The triggers come last so that their presence means the
98
+ setup completed.
99
+
100
+ cozy-search also runs `autoprovisionAssistants(client)` itself when the
101
+ assistant is opened. On an instance already set up it only lists the
102
+ assistants; it is there to catch a flag changed since the setup, and to
103
+ give its folder back to a provisioned assistant that lost it.
104
+
105
+ Both run once per session and share their work, so nothing runs twice.
106
+ They never throw: on a stack whose `rag-index` worker is still reserved,
107
+ the 403 on the triggers is logged and the app keeps working.
108
+
109
+ #### Migration of the existing assistants
110
+
111
+ Assistants created before a knowledge base folder became mandatory have
112
+ none, and the worker indexes nothing for them. The setup gives them the
113
+ root folder, that is the whole Drive. This is a one-off data migration,
114
+ unrelated to the entries of the flag: once every assistant has a folder,
115
+ it finds nothing to do.
116
+
117
+ An app that manages its assistants itself, without the flag, can call
118
+ `setupRagIndexing(client)`: the triggers and this migration, no
119
+ provisioning.
120
+
121
+ #### Permissions
122
+
123
+ `io.cozy.triggers` and `io.cozy.jobs` (to create and launch the
124
+ triggers), `io.cozy.ai.chat.assistants` and `io.cozy.files` (to read,
125
+ migrate and provision the assistants and their folders), and
126
+ `io.cozy.accounts` (one document per provisioned assistant).
127
+
104
128
  ### On desktop
105
129
 
106
130
  You can add the search bar like this :
@@ -1,9 +1,5 @@
1
1
  export function resetAutoprovisionForTests(): void;
2
2
  export function autoprovisionEntries(): Array<object> | null;
3
- export function ensureRagIndexTriggers(client: import("cozy-client").CozyClient): Promise<{
4
- triggers: string[];
5
- error: Error | null;
6
- }>;
7
3
  export function autoprovisionAssistants(client: import("cozy-client").CozyClient): Promise<null | {
8
4
  setup: object;
9
5
  created: string[];
@@ -13,3 +9,4 @@ export function autoprovisionAssistants(client: import("cozy-client").CozyClient
13
9
  reason: string;
14
10
  }[];
15
11
  }>;
12
+ export function ensureAssistantsSetup(client: import("cozy-client").CozyClient): Promise<null | object>;
@@ -5,7 +5,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
5
5
  Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
- exports.resetAutoprovisionForTests = exports.ensureRagIndexTriggers = exports.autoprovisionEntries = exports.autoprovisionAssistants = void 0;
8
+ exports.resetAutoprovisionForTests = exports.ensureAssistantsSetup = exports.autoprovisionEntries = exports.autoprovisionAssistants = void 0;
9
9
 
10
10
  var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
11
11
 
@@ -34,12 +34,12 @@ var warn = function warn() {
34
34
  (_console = console).warn.apply(_console, ['cozy-search autoprovision:'].concat(args));
35
35
  };
36
36
 
37
- var triggersPending = null;
38
37
  var pending = null;
38
+ var setupPending = null;
39
39
 
40
40
  var resetAutoprovisionForTests = function resetAutoprovisionForTests() {
41
- triggersPending = null;
42
41
  pending = null;
42
+ setupPending = null;
43
43
  };
44
44
  /**
45
45
  * The entries of the autoprovision flag, or null when it lists nothing.
@@ -53,44 +53,12 @@ var autoprovisionEntries = function autoprovisionEntries() {
53
53
  var entries = (0, _cozyFlags.default)(_provisioning.AUTOPROVISION_FLAG);
54
54
  return Array.isArray(entries) && entries.length > 0 ? entries : null;
55
55
  };
56
- /**
57
- * Makes sure the instance has its rag-index triggers, so the files of the
58
- * knowledge base folders get indexed as they change. Runs once per session
59
- * and never rejects: a host app can call it at startup, it costs a single
60
- * request when the triggers already exist.
61
- * @param {import('cozy-client').CozyClient} client - The cozy client.
62
- * @returns {Promise<{triggers: string[], error: Error|null}>} The
63
- * `arguments` of the triggers created, and the failure if any.
64
- */
65
-
66
56
 
67
57
  exports.autoprovisionEntries = autoprovisionEntries;
68
58
 
69
- var ensureRagIndexTriggers = function ensureRagIndexTriggers(client) {
70
- if (!triggersPending) {
71
- triggersPending = (0, _ragIndexing.createRagIndexTriggers)(client).then(function (triggers) {
72
- return {
73
- triggers: triggers,
74
- error: null
75
- };
76
- }, function (error) {
77
- warn('cannot set up the rag-index triggers', error);
78
- return {
79
- triggers: [],
80
- error: error
81
- };
82
- });
83
- }
84
-
85
- return triggersPending;
86
- };
87
-
88
- exports.ensureRagIndexTriggers = ensureRagIndexTriggers;
89
-
90
59
  var run = /*#__PURE__*/function () {
91
60
  var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(client) {
92
- var entries, setup, _yield$ensureRagIndex, triggers, error, assistants, result;
93
-
61
+ var entries, setup, assistants, result;
94
62
  return _regenerator.default.wrap(function _callee$(_context) {
95
63
  while (1) {
96
64
  switch (_context.prev = _context.next) {
@@ -110,59 +78,68 @@ var run = /*#__PURE__*/function () {
110
78
  migrated: [],
111
79
  errors: []
112
80
  };
113
- _context.next = 6;
114
- return ensureRagIndexTriggers(client);
115
-
116
- case 6:
117
- _yield$ensureRagIndex = _context.sent;
118
- triggers = _yield$ensureRagIndex.triggers;
119
- error = _yield$ensureRagIndex.error;
120
- setup.triggers = triggers;
121
- if (error) setup.errors.push(error);
122
81
  assistants = null;
123
- _context.prev = 12;
124
- _context.next = 15;
82
+ _context.prev = 5;
83
+ _context.next = 8;
125
84
  return (0, _ragIndexing.fetchAssistants)(client);
126
85
 
127
- case 15:
86
+ case 8:
128
87
  assistants = _context.sent;
129
- _context.next = 18;
88
+ _context.next = 11;
130
89
  return (0, _ragIndexing.migrateAssistantsWithoutFolder)(client, assistants);
131
90
 
132
- case 18:
91
+ case 11:
133
92
  setup.migrated = _context.sent;
134
- _context.next = 25;
93
+ _context.next = 18;
135
94
  break;
136
95
 
137
- case 21:
138
- _context.prev = 21;
139
- _context.t0 = _context["catch"](12);
96
+ case 14:
97
+ _context.prev = 14;
98
+ _context.t0 = _context["catch"](5);
140
99
  warn('cannot migrate the assistants without folder', _context.t0);
141
100
  setup.errors.push(_context.t0);
142
101
 
143
- case 25:
144
- _context.next = 27;
102
+ case 18:
103
+ _context.next = 20;
145
104
  return (0, _provisioning.ensureProvisionedAssistants)(client, entries, {
146
105
  assistants: assistants
147
106
  });
148
107
 
149
- case 27:
108
+ case 20:
150
109
  result = _context.sent;
151
110
 
152
111
  if (result.skipped.length > 0) {
153
112
  warn('skipped entries', result.skipped);
154
- }
113
+ } // Last: the triggers tell ensureAssistantsSetup that the setup completed,
114
+ // and the launch of the files one indexes the folders just provisioned.
155
115
 
116
+
117
+ _context.prev = 22;
118
+ _context.next = 25;
119
+ return (0, _ragIndexing.createRagIndexTriggers)(client);
120
+
121
+ case 25:
122
+ setup.triggers = _context.sent;
123
+ _context.next = 32;
124
+ break;
125
+
126
+ case 28:
127
+ _context.prev = 28;
128
+ _context.t1 = _context["catch"](22);
129
+ warn('cannot set up the rag-index triggers', _context.t1);
130
+ setup.errors.push(_context.t1);
131
+
132
+ case 32:
156
133
  return _context.abrupt("return", _objectSpread({
157
134
  setup: setup
158
135
  }, result));
159
136
 
160
- case 30:
137
+ case 33:
161
138
  case "end":
162
139
  return _context.stop();
163
140
  }
164
141
  }
165
- }, _callee, null, [[12, 21]]);
142
+ }, _callee, null, [[5, 14], [22, 28]]);
166
143
  }));
167
144
 
168
145
  return function run(_x) {
@@ -170,12 +147,10 @@ var run = /*#__PURE__*/function () {
170
147
  };
171
148
  }();
172
149
  /**
173
- * Sets up the rag-index triggers, gives a folder to the assistants that
174
- * lack one, then provisions the assistants listed in the autoprovision
175
- * flag. Runs once per session: every call shares the first one's promise,
176
- * and the triggers step is shared with ensureRagIndexTriggers, so a host
177
- * app that ensured them at startup does not pay for them twice. Never
178
- * rejects.
150
+ * Gives a folder to the assistants that lack one, provisions the
151
+ * assistants listed in the autoprovision flag, then sets up the rag-index
152
+ * triggers. Runs once per session: every call shares the first one's
153
+ * promise. Never rejects.
179
154
  * @param {import('cozy-client').CozyClient} client - The cozy client.
180
155
  * @returns {Promise<null|{setup: object, created: string[], ensured: string[], skipped: {id: string, reason: string}[]}>} Null when the flag lists nothing.
181
156
  */
@@ -191,5 +166,68 @@ var autoprovisionAssistants = function autoprovisionAssistants(client) {
191
166
 
192
167
  return pending;
193
168
  };
169
+ /**
170
+ * The startup entry point of a host app: one request when the instance is
171
+ * already set up. The rag-index triggers are created last by
172
+ * autoprovisionAssistants, so finding both means an earlier session went
173
+ * through; anything changed since is caught when the assistant opens.
174
+ * Runs once per session, never rejects.
175
+ * @param {import('cozy-client').CozyClient} client - The cozy client.
176
+ * @returns {Promise<null|object>} Null when there was nothing to do, the
177
+ * result of autoprovisionAssistants otherwise.
178
+ */
179
+
180
+
181
+ exports.autoprovisionAssistants = autoprovisionAssistants;
182
+
183
+ var ensureAssistantsSetup = function ensureAssistantsSetup(client) {
184
+ if (!setupPending) {
185
+ setupPending = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2() {
186
+ var _yield$findRagIndexTr, files, assistants;
187
+
188
+ return _regenerator.default.wrap(function _callee2$(_context2) {
189
+ while (1) {
190
+ switch (_context2.prev = _context2.next) {
191
+ case 0:
192
+ if (autoprovisionEntries()) {
193
+ _context2.next = 2;
194
+ break;
195
+ }
196
+
197
+ return _context2.abrupt("return", null);
198
+
199
+ case 2:
200
+ _context2.next = 4;
201
+ return (0, _ragIndexing.findRagIndexTriggers)(client);
202
+
203
+ case 4:
204
+ _yield$findRagIndexTr = _context2.sent;
205
+ files = _yield$findRagIndexTr.files;
206
+ assistants = _yield$findRagIndexTr.assistants;
207
+
208
+ if (!(files && assistants)) {
209
+ _context2.next = 9;
210
+ break;
211
+ }
212
+
213
+ return _context2.abrupt("return", null);
214
+
215
+ case 9:
216
+ return _context2.abrupt("return", autoprovisionAssistants(client));
217
+
218
+ case 10:
219
+ case "end":
220
+ return _context2.stop();
221
+ }
222
+ }
223
+ }, _callee2);
224
+ }))().catch(function (error) {
225
+ warn('cannot check the rag-index triggers', error);
226
+ return null;
227
+ });
228
+ }
229
+
230
+ return setupPending;
231
+ };
194
232
 
195
- exports.autoprovisionAssistants = autoprovisionAssistants;
233
+ exports.ensureAssistantsSetup = ensureAssistantsSetup;
@@ -3,13 +3,14 @@ import flag from 'cozy-flags'
3
3
  import {
4
4
  autoprovisionAssistants,
5
5
  autoprovisionEntries,
6
- ensureRagIndexTriggers,
6
+ ensureAssistantsSetup,
7
7
  resetAutoprovisionForTests
8
8
  } from './autoprovision'
9
9
  import { ensureProvisionedAssistants } from './provisioning'
10
10
  import {
11
11
  createRagIndexTriggers,
12
12
  fetchAssistants,
13
+ findRagIndexTriggers,
13
14
  migrateAssistantsWithoutFolder
14
15
  } from './ragIndexing'
15
16
 
@@ -21,6 +22,7 @@ jest.mock('./provisioning', () => ({
21
22
  jest.mock('./ragIndexing', () => ({
22
23
  createRagIndexTriggers: jest.fn(),
23
24
  fetchAssistants: jest.fn(),
25
+ findRagIndexTriggers: jest.fn(),
24
26
  migrateAssistantsWithoutFolder: jest.fn()
25
27
  }))
26
28
 
@@ -35,6 +37,9 @@ beforeEach(() => {
35
37
  warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {})
36
38
  createRagIndexTriggers.mockReset().mockResolvedValue(['io.cozy.files'])
37
39
  fetchAssistants.mockReset().mockResolvedValue(assistants)
40
+ findRagIndexTriggers
41
+ .mockReset()
42
+ .mockResolvedValue({ files: null, assistants: null })
38
43
  migrateAssistantsWithoutFolder.mockReset().mockResolvedValue([])
39
44
  ensureProvisionedAssistants
40
45
  .mockReset()
@@ -58,35 +63,6 @@ describe('autoprovisionEntries', () => {
58
63
  })
59
64
  })
60
65
 
61
- describe('ensureRagIndexTriggers', () => {
62
- it('creates the missing triggers once per session', async () => {
63
- const first = ensureRagIndexTriggers(client)
64
- expect(ensureRagIndexTriggers(client)).toBe(first)
65
- await expect(first).resolves.toEqual({
66
- triggers: ['io.cozy.files'],
67
- error: null
68
- })
69
- await ensureRagIndexTriggers(client)
70
-
71
- expect(createRagIndexTriggers).toHaveBeenCalledTimes(1)
72
- expect(createRagIndexTriggers).toHaveBeenCalledWith(client)
73
- })
74
-
75
- it('reports a failure without rejecting', async () => {
76
- const error = new Error('forbidden')
77
- createRagIndexTriggers.mockRejectedValue(error)
78
- await expect(ensureRagIndexTriggers(client)).resolves.toEqual({
79
- triggers: [],
80
- error
81
- })
82
- expect(warnSpy).toHaveBeenCalledWith(
83
- 'cozy-search autoprovision:',
84
- 'cannot set up the rag-index triggers',
85
- error
86
- )
87
- })
88
- })
89
-
90
66
  describe('autoprovisionAssistants', () => {
91
67
  it('does nothing without flag entries', async () => {
92
68
  flag.mockReturnValue(null)
@@ -109,7 +85,7 @@ describe('autoprovisionAssistants', () => {
109
85
  expect(result.setup.errors.map(e => e.message)).toEqual(['nope'])
110
86
  })
111
87
 
112
- it('ensures the triggers, migrates, then provisions the flag entries', async () => {
88
+ it('migrates, provisions the flag entries, then ensures the triggers', async () => {
113
89
  flag.mockReturnValue(entries)
114
90
  migrateAssistantsWithoutFolder.mockResolvedValue(['legacy'])
115
91
  const result = await autoprovisionAssistants(client)
@@ -124,9 +100,9 @@ describe('autoprovisionAssistants', () => {
124
100
  assistants
125
101
  })
126
102
  const order = [
127
- createRagIndexTriggers,
128
103
  migrateAssistantsWithoutFolder,
129
- ensureProvisionedAssistants
104
+ ensureProvisionedAssistants,
105
+ createRagIndexTriggers
130
106
  ].map(fn => fn.mock.invocationCallOrder[0])
131
107
  expect(order).toEqual([...order].sort((a, b) => a - b))
132
108
  expect(result).toEqual({
@@ -148,15 +124,6 @@ describe('autoprovisionAssistants', () => {
148
124
  expect(ensureProvisionedAssistants).toHaveBeenCalledTimes(1)
149
125
  })
150
126
 
151
- it('shares the triggers step with ensureRagIndexTriggers', async () => {
152
- flag.mockReturnValue(entries)
153
- await ensureRagIndexTriggers(client)
154
- await autoprovisionAssistants(client)
155
-
156
- expect(createRagIndexTriggers).toHaveBeenCalledTimes(1)
157
- expect(ensureProvisionedAssistants).toHaveBeenCalledTimes(1)
158
- })
159
-
160
127
  it('still provisions when the setup steps failed', async () => {
161
128
  flag.mockReturnValue(entries)
162
129
  createRagIndexTriggers.mockRejectedValue(new Error('forbidden'))
@@ -165,8 +132,8 @@ describe('autoprovisionAssistants', () => {
165
132
 
166
133
  expect(ensureProvisionedAssistants).toHaveBeenCalledTimes(1)
167
134
  expect(result.setup.errors.map(e => e.message)).toEqual([
168
- 'forbidden',
169
- 'nope'
135
+ 'nope',
136
+ 'forbidden'
170
137
  ])
171
138
  })
172
139
 
@@ -197,3 +164,61 @@ describe('autoprovisionAssistants', () => {
197
164
  )
198
165
  })
199
166
  })
167
+
168
+ describe('ensureAssistantsSetup', () => {
169
+ it('does nothing without flag entries', async () => {
170
+ flag.mockReturnValue(null)
171
+ await expect(ensureAssistantsSetup(client)).resolves.toBeNull()
172
+ expect(findRagIndexTriggers).not.toHaveBeenCalled()
173
+ })
174
+
175
+ it('stops at the triggers when both exist', async () => {
176
+ flag.mockReturnValue(entries)
177
+ findRagIndexTriggers.mockResolvedValue({
178
+ files: { _id: 'files' },
179
+ assistants: { _id: 'assistants' }
180
+ })
181
+ await expect(ensureAssistantsSetup(client)).resolves.toBeNull()
182
+
183
+ expect(findRagIndexTriggers).toHaveBeenCalledWith(client)
184
+ expect(fetchAssistants).not.toHaveBeenCalled()
185
+ expect(ensureProvisionedAssistants).not.toHaveBeenCalled()
186
+ expect(createRagIndexTriggers).not.toHaveBeenCalled()
187
+ })
188
+
189
+ it.each([
190
+ ['none', { files: null, assistants: null }],
191
+ ['only the files one', { files: { _id: 'files' }, assistants: null }],
192
+ ['only the assistants one', { files: null, assistants: { _id: 'a' } }]
193
+ ])('runs the whole setup with %s', async (_label, found) => {
194
+ flag.mockReturnValue(entries)
195
+ findRagIndexTriggers.mockResolvedValue(found)
196
+ const result = await ensureAssistantsSetup(client)
197
+
198
+ expect(ensureProvisionedAssistants).toHaveBeenCalledTimes(1)
199
+ expect(createRagIndexTriggers).toHaveBeenCalledTimes(1)
200
+ expect(result.created).toEqual(['docs'])
201
+ })
202
+
203
+ it('runs once per session and shares the setup with the assistant', async () => {
204
+ flag.mockReturnValue(entries)
205
+ const first = ensureAssistantsSetup(client)
206
+ expect(ensureAssistantsSetup(client)).toBe(first)
207
+ await first
208
+ await autoprovisionAssistants(client)
209
+
210
+ expect(findRagIndexTriggers).toHaveBeenCalledTimes(1)
211
+ expect(ensureProvisionedAssistants).toHaveBeenCalledTimes(1)
212
+ })
213
+
214
+ it('never rejects', async () => {
215
+ flag.mockReturnValue(entries)
216
+ findRagIndexTriggers.mockRejectedValue(new Error('offline'))
217
+ await expect(ensureAssistantsSetup(client)).resolves.toBeNull()
218
+ expect(warnSpy).toHaveBeenCalledWith(
219
+ 'cozy-search autoprovision:',
220
+ 'cannot check the rag-index triggers',
221
+ expect.any(Error)
222
+ )
223
+ })
224
+ })
@@ -0,0 +1 @@
1
+ export function useAssistantsSetup(): void;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useAssistantsSetup = void 0;
7
+
8
+ var _react = require("react");
9
+
10
+ var _cozyClient = require("cozy-client");
11
+
12
+ var _autoprovision = require("./autoprovision");
13
+
14
+ /**
15
+ * Sets the flagged assistants and their RAG indexing up at the startup of
16
+ * a host app, the first time only: see ensureAssistantsSetup.
17
+ */
18
+ var useAssistantsSetup = function useAssistantsSetup() {
19
+ var client = (0, _cozyClient.useClient)();
20
+ (0, _react.useEffect)(function () {
21
+ if (client) (0, _autoprovision.ensureAssistantsSetup)(client);
22
+ }, [client]);
23
+ };
24
+
25
+ exports.useAssistantsSetup = useAssistantsSetup;
@@ -0,0 +1,33 @@
1
+ import { renderHook } from '@testing-library/react-hooks/dom'
2
+
3
+ import { useClient } from 'cozy-client'
4
+
5
+ import { ensureAssistantsSetup } from './autoprovision'
6
+ import { useAssistantsSetup } from './useAssistantsSetup'
7
+
8
+ jest.mock('cozy-client', () => ({ useClient: jest.fn() }))
9
+ jest.mock('./autoprovision', () => ({ ensureAssistantsSetup: jest.fn() }))
10
+
11
+ const client = { id: 'client' }
12
+
13
+ describe('useAssistantsSetup', () => {
14
+ beforeEach(() => {
15
+ useClient.mockReset().mockReturnValue(client)
16
+ ensureAssistantsSetup.mockReset().mockResolvedValue(null)
17
+ })
18
+
19
+ it('ensures the setup with the client on mount', () => {
20
+ const { rerender } = renderHook(() => useAssistantsSetup())
21
+ rerender()
22
+
23
+ expect(ensureAssistantsSetup).toHaveBeenCalledTimes(1)
24
+ expect(ensureAssistantsSetup).toHaveBeenCalledWith(client)
25
+ })
26
+
27
+ it('waits for a client', () => {
28
+ useClient.mockReturnValue(null)
29
+ renderHook(() => useAssistantsSetup())
30
+
31
+ expect(ensureAssistantsSetup).not.toHaveBeenCalled()
32
+ })
33
+ })
package/dist/index.d.ts CHANGED
@@ -11,6 +11,6 @@ export { StreamBridge, createCozyRealtimeChatAdapter } from './components/adapte
11
11
  export { default as AssistantView } from './components/Views/AssistantView';
12
12
  export { assistantIdFromName, AUTOPROVISION_FLAG, ensureProvisionedAssistants, getDefaultProvisionedAssistantId } from './components/KnowledgeBase/provisioning';
13
13
  export { setupRagIndexing } from './components/KnowledgeBase/ragIndexing';
14
- export { autoprovisionAssistants, ensureRagIndexTriggers } from './components/KnowledgeBase/autoprovision';
15
- export { useRagIndexTriggers } from './components/KnowledgeBase/useRagIndexTriggers';
14
+ export { autoprovisionAssistants, ensureAssistantsSetup } from './components/KnowledgeBase/autoprovision';
15
+ export { useAssistantsSetup } from './components/KnowledgeBase/useAssistantsSetup';
16
16
  export { useAssistantsAutoprovision } from './components/KnowledgeBase/useAssistantsAutoprovision';
package/dist/index.js CHANGED
@@ -95,16 +95,16 @@ Object.defineProperty(exports, "createCozyRealtimeChatAdapter", {
95
95
  return _adapters.createCozyRealtimeChatAdapter;
96
96
  }
97
97
  });
98
- Object.defineProperty(exports, "ensureProvisionedAssistants", {
98
+ Object.defineProperty(exports, "ensureAssistantsSetup", {
99
99
  enumerable: true,
100
100
  get: function get() {
101
- return _provisioning.ensureProvisionedAssistants;
101
+ return _autoprovision.ensureAssistantsSetup;
102
102
  }
103
103
  });
104
- Object.defineProperty(exports, "ensureRagIndexTriggers", {
104
+ Object.defineProperty(exports, "ensureProvisionedAssistants", {
105
105
  enumerable: true,
106
106
  get: function get() {
107
- return _autoprovision.ensureRagIndexTriggers;
107
+ return _provisioning.ensureProvisionedAssistants;
108
108
  }
109
109
  });
110
110
  Object.defineProperty(exports, "getDefaultProvisionedAssistantId", {
@@ -125,10 +125,10 @@ Object.defineProperty(exports, "useAssistantsAutoprovision", {
125
125
  return _useAssistantsAutoprovision.useAssistantsAutoprovision;
126
126
  }
127
127
  });
128
- Object.defineProperty(exports, "useRagIndexTriggers", {
128
+ Object.defineProperty(exports, "useAssistantsSetup", {
129
129
  enumerable: true,
130
130
  get: function get() {
131
- return _useRagIndexTriggers.useRagIndexTriggers;
131
+ return _useAssistantsSetup.useAssistantsSetup;
132
132
  }
133
133
  });
134
134
 
@@ -160,6 +160,6 @@ var _ragIndexing = require("./components/KnowledgeBase/ragIndexing");
160
160
 
161
161
  var _autoprovision = require("./components/KnowledgeBase/autoprovision");
162
162
 
163
- var _useRagIndexTriggers = require("./components/KnowledgeBase/useRagIndexTriggers");
163
+ var _useAssistantsSetup = require("./components/KnowledgeBase/useAssistantsSetup");
164
164
 
165
165
  var _useAssistantsAutoprovision = require("./components/KnowledgeBase/useAssistantsAutoprovision");
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cozy-search",
3
3
  "description": "UI components about search bar and IA assistant",
4
- "version": "2.5.1",
4
+ "version": "2.6.0",
5
5
  "author": {
6
6
  "name": "Cozy Cloud",
7
7
  "url": "https://github.com/cozy"
@@ -96,5 +96,5 @@
96
96
  "lint": "cd .. && yarn eslint --ext js,jsx,ts packages/cozy-search"
97
97
  },
98
98
  "types": "dist/index.d.ts",
99
- "gitHead": "368b1e85eb1f6a6a0731681ef2a38a7bbc3fe779"
99
+ "gitHead": "2103fb9d929275519efab0419630593d07d1ce8a"
100
100
  }
@@ -1 +0,0 @@
1
- export function useRagIndexTriggers(): void;
@@ -1,27 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.useRagIndexTriggers = void 0;
7
-
8
- var _react = require("react");
9
-
10
- var _cozyClient = require("cozy-client");
11
-
12
- var _autoprovision = require("./autoprovision");
13
-
14
- /**
15
- * Ensures the rag-index triggers at startup, when the autoprovision flag
16
- * lists assistants: the knowledge base folders are then indexed as they
17
- * change, before the assistant is ever opened. The assistants themselves
18
- * are provisioned when the assistant opens.
19
- */
20
- var useRagIndexTriggers = function useRagIndexTriggers() {
21
- var client = (0, _cozyClient.useClient)();
22
- (0, _react.useEffect)(function () {
23
- if (client && (0, _autoprovision.autoprovisionEntries)()) (0, _autoprovision.ensureRagIndexTriggers)(client);
24
- }, [client]);
25
- };
26
-
27
- exports.useRagIndexTriggers = useRagIndexTriggers;
@@ -1,47 +0,0 @@
1
- import { renderHook } from '@testing-library/react-hooks/dom'
2
-
3
- import { useClient } from 'cozy-client'
4
-
5
- import { autoprovisionEntries, ensureRagIndexTriggers } from './autoprovision'
6
- import { useRagIndexTriggers } from './useRagIndexTriggers'
7
-
8
- jest.mock('cozy-client', () => ({ useClient: jest.fn() }))
9
- jest.mock('./autoprovision', () => ({
10
- autoprovisionEntries: jest.fn(),
11
- ensureRagIndexTriggers: jest.fn()
12
- }))
13
-
14
- const client = { id: 'client' }
15
-
16
- describe('useRagIndexTriggers', () => {
17
- beforeEach(() => {
18
- useClient.mockReset().mockReturnValue(client)
19
- autoprovisionEntries.mockReset().mockReturnValue([{ name: 'Docs' }])
20
- ensureRagIndexTriggers.mockReset().mockResolvedValue({
21
- triggers: [],
22
- error: null
23
- })
24
- })
25
-
26
- it('ensures the triggers with the client on mount', () => {
27
- const { rerender } = renderHook(() => useRagIndexTriggers())
28
- rerender()
29
-
30
- expect(ensureRagIndexTriggers).toHaveBeenCalledTimes(1)
31
- expect(ensureRagIndexTriggers).toHaveBeenCalledWith(client)
32
- })
33
-
34
- it('does nothing without flag entries', () => {
35
- autoprovisionEntries.mockReturnValue(null)
36
- renderHook(() => useRagIndexTriggers())
37
-
38
- expect(ensureRagIndexTriggers).not.toHaveBeenCalled()
39
- })
40
-
41
- it('waits for a client', () => {
42
- useClient.mockReturnValue(null)
43
- renderHook(() => useRagIndexTriggers())
44
-
45
- expect(ensureRagIndexTriggers).not.toHaveBeenCalled()
46
- })
47
- })