unique_sdk 0.10.51__py3-none-any.whl → 0.10.56__py3-none-any.whl

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,2496 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: unique_sdk
3
- Version: 0.10.51
4
- Summary:
5
- License: MIT
6
- Author: Martin Fadler
7
- Author-email: martin.fadler@unique.ch
8
- Requires-Python: >=3.11,<4.0
9
- Classifier: License :: OSI Approved :: MIT License
10
- Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 3.11
12
- Classifier: Programming Language :: Python :: 3.12
13
- Provides-Extra: openai
14
- Requires-Dist: openai (>=1.105.0,<2.0.0) ; extra == "openai"
15
- Requires-Dist: requests (>=2.32.3,<3.0.0)
16
- Requires-Dist: typing-extensions (>=4.9.0,<5.0.0)
17
- Description-Content-Type: text/markdown
18
-
19
- # Unique Python SDK
20
-
21
- Unique AI is a tailored solution for the financial industry, designed to increase productivity by automating manual workloads through AI and ChatGPT solutions.
22
-
23
- The Unique Python SDK provides access to the public API of Unique AI. It also enables verification of Webhook signatures to ensure the authenticity of incoming Webhook requests.
24
-
25
- ## Table of Contents
26
-
27
- 1. [Installation](#installation)
28
- 2. [Requirements](#requirements)
29
- 3. [Usage Instructions](#usage-instructions)
30
- 4. [Webhook Triggers](#webhook-triggers)
31
- 5. [Available API Resources](#available-api-resources)
32
- - [Content](#content)
33
- - [Message](#message)
34
- - [Message Log](#message-log)
35
- - [Message Execution](#message-execution)
36
- - [Chat Completion](#chat-completion)
37
- - [Embeddings](#embeddings)
38
- - [Acronyms](#acronyms)
39
- - [Search](#search)
40
- - [Search String](#search-string)
41
- - [Short Term Memory](#short-term-memory)
42
- - [Message Assessment](#message-assessment)
43
- - [Folder](#folder)
44
- - [Space](#space)
45
- - [LLM Models](#llm-models)
46
- - [User](#user)
47
- - [Group](#group)
48
- - [Agentic Table](#agentic-table)
49
- 6. [UniqueQL](#uniqueql)
50
- - [Query Structure](#uniqueql-query-structure)
51
- - [Metadata Filtering](#metadata-filtering)
52
- 7. [Util functions](#utils)
53
- - [Chat History](#chat-history)
54
- - [File Io](#file-io)
55
- - [Sources](#sources)
56
- - [token](#token)
57
- - [Chat In Space](#chat-in-space)
58
- 8. [Error Handling](#error-handling)
59
- 9. [Examples](#examples)
60
-
61
- ## Installation
62
-
63
- Install UniqueSDK and its peer dependency `requests` and when planning to run async requests also `httpx` or `aiohttp` via pip using the following commands:
64
-
65
- ```bash
66
- pip install unique_sdk
67
- pip install requests
68
- ```
69
-
70
- Optional for async requests:
71
-
72
- ```bash
73
- pip install httpx
74
- ```
75
-
76
- or
77
-
78
- ```bash
79
- pip install aiohttp
80
- ```
81
-
82
- ## Requirements
83
-
84
- - Python >=3.11 (Other Python versions 3.6+ might work but are not tested)
85
- - requests (peer dependency. Other HTTP request libraries might be supported in the future)
86
- - Unique App-ID & API Key
87
-
88
- Please contact your customer success manager at Unique for your personal developer App-ID & API Key.
89
-
90
- ## Usage instructions
91
-
92
- The library needs to be configured with your Unique `app_id` & `api_key`. Additionally, each individual request must be scoped to a User and provide a `user_id` & `company_id`.
93
-
94
- ```python
95
- import unique_sdk
96
- unique_sdk.api_key = "ukey_..."
97
- unique_sdk.app_id = "app_..."
98
- ```
99
-
100
- The SDK includes a set of classes for API resources. Each class contains CRUD methods to interact with the resource.
101
-
102
- ### Example
103
-
104
- ```python
105
- import unique_sdk
106
- unique_sdk.api_key = "ukey_..."
107
- unique_sdk.app_id = "app_..."
108
-
109
- # list messages for a single chat
110
- messages = unique_sdk.Message.list(
111
- user_id=user_id,
112
- company_id=company_id,
113
- chatId=chat_id,
114
- )
115
-
116
- print(messages.data[0].text)
117
- ```
118
-
119
- ## Webhook Triggers
120
-
121
- A core functionality of Unique AI is the ability for users to engage in an interactive chat feature. SDK developers can hook into this chat to provide new functionalities.
122
-
123
- Your App (refer to `app-id` in [Requirements](#requirements)) must be subscribed to each individual Unique event in order to receive a webhook.
124
-
125
- Each webhook sent by Unique includes a set of headers:
126
-
127
- ```yaml
128
- X-Unique-Id: evt_... # Event id, same as in the body.
129
- X-Unique-Signature: ... # A HMAC-SHA256 hex signature of the entire body.
130
- X-Unique-Version: 1.0.0 # Event payload version.
131
- X-Unique-Created-At: 1705960141 # Unix timestamp (seconds) of the delivery time.
132
- X-Unique-User-Id: ... # The user who initiated the message.
133
- X-Unique-Company-Id: ... # The company to which the user belongs.
134
- ```
135
-
136
- ### Success & Retry on Failure
137
-
138
- - Webhooks are considered successfully delivered if your endpoint returns a status code between `200` and `299`.
139
- - If your endpoint returns a status code of `300` - `399`, `429`, or `500` - `599`, Unique will retry the delivery of the webhook with an exponential backoff up to five times.
140
- - If your endpoint returns any other status (e.g., `404`), it is marked as expired and will not receive any further requests.
141
-
142
- ### Webhook Signature Verification
143
-
144
- The webhook body, containing a timestamp of the delivery time, is signed with HMAC-SHA256. Verify the signature by constructing the `event` with the `unique_sdk.Webhook` class:
145
-
146
- ```python
147
- from http import HTTPStatus
148
- from flask import Flask, jsonify, request
149
- import unique_sdk
150
-
151
- endpoint_secret = "YOUR_ENDPOINT_SECRET"
152
-
153
- @app.route("/webhook", methods=["POST"])
154
- def webhook():
155
- event = None
156
- payload = request.data
157
-
158
- sig_header = request.headers.get("X-Unique-Signature")
159
- timestamp = request.headers.get("X-Unique-Created-At")
160
-
161
- if not sig_header or not timestamp:
162
- print("⚠️ Webhook signature or timestamp headers missing.")
163
- return jsonify(success=False), HTTPStatus.BAD_REQUEST
164
-
165
- try:
166
- event = unique_sdk.Webhook.construct_event(
167
- payload, sig_header, timestamp, endpoint_secret
168
- )
169
- except unique_sdk.SignatureVerificationError as e:
170
- print("⚠️ Webhook signature verification failed. " + str(e))
171
- return jsonify(success=False), HTTPStatus.BAD_REQUEST
172
- ```
173
-
174
- The `construct_event` method will compare the signature and raise a `unique_sdk.SignatureVerificationError` if the signature does not match. It will also raise this error if the `createdAt` timestamp is outside of a default tolerance of 5 minutes. Adjust the `tolerance` by passing a fifth parameter to the method (tolerance in seconds), e.g.:
175
-
176
- ```python
177
- event = unique_sdk.Webhook.construct_event(
178
- payload, sig_header, timestamp, endpoint_secret, 0
179
- )
180
- ```
181
-
182
- ### Available Unique Events
183
-
184
- #### User Message Created
185
-
186
- ```json
187
- {
188
- "id": "evt_...", // see header
189
- "version": "1.0.0", // see header
190
- "event": "unique.chat.user-message.created", // The name of the event
191
- "createdAt": "1705960141", // see header
192
- "userId": "...", // see header
193
- "companyId": "...", // see header
194
- "payload": {
195
- "chatId": "chat_...", // The id of the chat
196
- "assistantId": "assistant_...", // The id of the selected assistant
197
- "text": "Hello, how can I help you?" // The user message
198
- }
199
- }
200
- ```
201
-
202
- This webhook is triggered for every new chat message sent by the user. This event occurs regardless of whether it is the first or a subsequent message in a chat. Use the `unique_sdk.Message` class to retrieve other messages from the same `chatId` or maintain a local state of the messages in a single chat.
203
-
204
- This trigger can be used in combination with assistants marked as `external`. Those assistants will not execute any logic, enabling your code to respond to the user message and create an answer.
205
-
206
- #### External Module Chosen
207
-
208
- ```json
209
- {
210
- "id": "evt_...",
211
- "version": "1.0.0",
212
- "event": "unique.chat.external-module.chosen",
213
- "createdAt": "1705960141", // Unix timestamp (seconds)
214
- "userId": "...",
215
- "companyId": "...",
216
- "payload": {
217
- "name": "example-sdk", // The name of the module selected by the module chooser
218
- "description": "Example SDK", // The description of the module
219
- "configuration": {}, // Module configuration in JSON format
220
- "chatid": "chat_...", // The chat ID
221
- "assistantId:": "assistant_...", // The assistant ID
222
- "userMessage": {
223
- "id": "msg_...",
224
- "text": "Hello World!", // The user message leading to the module selection
225
- "createdAt": "2024-01-01T00:00:00.000Z" // ISO 8601
226
- },
227
- "assistantMessage": {
228
- "id": "msg_...",
229
- "createdAt": "2024-01-01T00:00:00.000Z" // ISO 8601
230
- }
231
- }
232
- }
233
- ```
234
-
235
- This Webhook is triggered when the Unique AI selects an external module as the best response to a user message. The module must be marked as `external` and available for the assistant used in the chat to be selected by the AI.
236
-
237
- Unique's UI will create an empty `assistantMessage` below the user message and update this message with status updates.
238
-
239
- **The SDK is expected to modify this assistantMessage with its answer to the user message.**
240
-
241
- ```python
242
- unique_sdk.Message.modify(
243
- user_id=user_id,
244
- company_id=company_id,
245
- id=assistant_message_id,
246
- chatId=chat_id,
247
- text="Here is your answer.",
248
- )
249
- ```
250
-
251
- ## Available API Resources
252
-
253
- - [Content](#content)
254
- - [Message](#message)
255
- - [Message Log](#message-log)
256
- - [Message Execution](#message-execution)
257
- - [Chat Completion](#chat-completion)
258
- - [Embeddings](#embeddings)
259
- - [Acronyms](#acronyms)
260
- - [Search](#search)
261
- - [Search String](#search-string)
262
- - [Short Term Memory](#short-term-memory)
263
- - [Message Assessment](#message-assessment)
264
- - [Folder](#folder)
265
- - [Space](#space)
266
- - [LLM Models](#llm-models)
267
- - [User](#user)
268
- - [Group](#group)
269
- - [Agentic Table](#agentic-table)
270
-
271
- Most of the API services provide an asynchronous version of the method. The async methods are suffixed with `_async`.
272
-
273
- ### Content
274
-
275
- #### `unique_sdk.Content.search`
276
-
277
- Allows you to load full content/files from the knowledge-base of unique with the rights of the userId and companyId. Provided a `where` query for filtering. Filtering can be done on any of the following fields: `
278
-
279
- - `id`
280
- - `key`
281
- - `ownerId`
282
- - `title`
283
- - `url`
284
-
285
- Here an example of retrieving all files that contain the number 42 in the `title` or the `key` typically this is used to search by filename.
286
-
287
- ```python
288
- unique_sdk.Content.search(
289
- user_id=userId,
290
- company_id=companyId,
291
- where={
292
- "OR": [
293
- {
294
- "title": {
295
- "contains": "42",
296
- },
297
- },
298
- {
299
- "key": {
300
- "contains": "42",
301
- },
302
- },
303
- ],
304
- },
305
- chatId=chatId,
306
- )
307
- ```
308
-
309
- #### `unique_sdk.Content.get_info`
310
-
311
- [Deprecated, use `unique_sdk.Content.get_infos` instead.] Allows you to get content info. To filter the results you can define a metadata filter in UniqueQL language. Find out more about it in the UniqueQL section. An example of a metadata filter defined with UniqueQL is the following:
312
-
313
- ```python
314
- metadataFilter: {
315
- "or": [
316
- {
317
- "and": [
318
- {
319
- "operator": "contains",
320
- "path": [
321
- "folderIdPath"
322
- ],
323
- "value": "uniquepathid://test_id"
324
- },
325
- {
326
- "operator": "contains",
327
- "path": [
328
- "title"
329
- ],
330
- "value": "ai"
331
- }
332
- ]
333
- }
334
- ]
335
- },
336
- ```
337
-
338
- Pagination is also enabled for this functionality, and the default number of returned results is 50 with no entries skipped. Use the following paramteres to get the desired page:`
339
-
340
- - `skip`
341
- - `take`
342
-
343
- Here is an example of retrieving the first 3 content infos that contain the value `uniquepathid://scope_abcdibgznc4bkdcx120zm5d` in the `folderIdPath` metadata and the value `ai` for the `title` metadata.
344
-
345
- ```python
346
- content_info_result = unique_sdk.Content.get_info(
347
- user_id=user_id,
348
- company_id=company_id,
349
- metadataFilter={
350
- "or": [
351
- {
352
- "and": [
353
- {
354
- "operator": "contains",
355
- "path": [
356
- "folderIdPath"
357
- ],
358
- "value": "uniquepathid://scope_abcdibgznc4bkdcx120zm5d"
359
- },
360
- {
361
- "operator": "contains",
362
- "path": [
363
- "title"
364
- ],
365
- "value": "ai"
366
- }
367
- ]
368
- }
369
- ]
370
- },
371
- skip=0,
372
- take=3,
373
- )
374
- ```
375
-
376
- #### `unique_sdk.Content.get_infos`
377
-
378
- Allows you to get content infos. To filter the results you can define a either metadata filter in UniqueQL language or specify a parentId. If both are defined, the function will throw an error.
379
-
380
- I f you want to learn more about UniqueQL, you can find out more about it in the [UniqueQL](#uniqueql) section. An example of a metadata filter defined with UniqueQL is the following:
381
-
382
- ```python
383
- metadataFilter: {
384
- "or": [
385
- {
386
- "and": [
387
- {
388
- "operator": "contains",
389
- "path": [
390
- "folderIdPath"
391
- ],
392
- "value": "uniquepathid://test_id"
393
- },
394
- {
395
- "operator": "contains",
396
- "path": [
397
- "title"
398
- ],
399
- "value": "ai"
400
- }
401
- ]
402
- }
403
- ]
404
- },
405
- ```
406
-
407
- Pagination is also enabled for this functionality, and the default number of returned results is 50 with no entries skipped. Use the following paramteres to get the desired page:`
408
-
409
- - `skip`
410
- - `take`
411
-
412
- Here is an example of retrieving the first 3 content infos that contain the value `uniquepathid://scope_abcdibgznc4bkdcx120zm5d` in the `folderIdPath` metadata and the value `ai` for the `title` metadata.
413
-
414
- ```python
415
- content_info_result = unique_sdk.Content.get_infos(
416
- user_id=user_id,
417
- company_id=company_id,
418
- metadataFilter={
419
- "or": [
420
- {
421
- "and": [
422
- {
423
- "operator": "contains",
424
- "path": [
425
- "folderIdPath"
426
- ],
427
- "value": "uniquepathid://scope_abcdibgznc4bkdcx120zm5d"
428
- },
429
- {
430
- "operator": "contains",
431
- "path": [
432
- "title"
433
- ],
434
- "value": "ai"
435
- }
436
- ]
437
- }
438
- ]
439
- },
440
- skip=0,
441
- take=3,
442
- )
443
- ```
444
-
445
- Here is an example of retrieving the contents based on a parentId.
446
-
447
- ```python
448
- content_info_result = unique_sdk.Content.get_infos(
449
- user_id=user_id,
450
- company_id=company_id,
451
- parentId="scope_ahefgj389srjbfejkkk98u"
452
- )
453
- ```
454
-
455
- #### `unique_sdk.Content.upsert`
456
-
457
- Enables upload of a new Content into the Knowledge base of unique into a specific scope with `scopeId` or a specific `chatId`. One of the two must be set.
458
-
459
- Typical usage is the following. That creates a Content and uploads a file
460
-
461
- ```python
462
-
463
- createdContent = upload_file(
464
- userId,
465
- companyId,
466
- "/path/to/file.pdf",
467
- "test.pdf",
468
- "application/pdf",
469
- "scope_stcj2osgbl722m22jayidx0n",
470
- ingestionConfig={
471
- "chunkMaxTokens": 1000,
472
- "chunkStrategy": "default",
473
- "uniqueIngestionMode": "standard",
474
- },
475
- metadata={
476
- "folderIdPath": "uniquepathid://scope_id"
477
- }
478
- )
479
-
480
- def upload_file(
481
- userId,
482
- companyId,
483
- path_to_file,
484
- displayed_filename,
485
- mimeType,
486
- description=None,
487
- scope_or_unique_path,
488
- ingestion_config=None,
489
- metadata=None,
490
- ):
491
- size = os.path.getsize(path_to_file)
492
- createdContent = unique_sdk.Content.upsert(
493
- user_id=userId,
494
- company_id=companyId,
495
- input={
496
- "key": displayed_filename,
497
- "title": displayed_filename,
498
- "mimeType": mimeType,
499
- "description": description,
500
- "ingestionConfig": ingestionConfig,
501
- "metadata": metadata,
502
- },
503
- scopeId=scope_or_unique_path,
504
- )
505
-
506
- uploadUrl = createdContent.writeUrl
507
-
508
- # upload to azure blob storage SAS url uploadUrl the pdf file translatedFile make sure it is treated as a application/pdf
509
- with open(path_to_file, "rb") as file:
510
- requests.put(
511
- uploadUrl,
512
- data=file,
513
- headers={
514
- "X-Ms-Blob-Content-Type": mimeType,
515
- "X-Ms-Blob-Type": "BlockBlob",
516
- },
517
- )
518
-
519
- unique_sdk.Content.upsert(
520
- user_id=userId,
521
- company_id=companyId,
522
- input={
523
- "key": displayed_filename,
524
- "title": displayed_filename,
525
- "mimeType": mimeType,
526
- "description": description,
527
- "byteSize": size,
528
- "ingestionConfig": ingestionConfig,
529
- "metadata": metadata,
530
- },
531
- scopeId=scope_or_unique_path,
532
- readUrl=createdContent.readUrl,
533
- )
534
-
535
- return createdContent
536
-
537
- ```
538
-
539
- #### `unique_sdk.Content.ingest_magic_table_sheets`
540
-
541
- Allows you to ingest a magic table sheet, each row is processed and converted into a content.
542
- ```python
543
- params = {
544
- "user_id": user_id,
545
- "company_id": company_id,
546
- "data": [
547
- {
548
- "rowId": "2",
549
- "columns": [
550
- {"columnId": "0", "columnName": "Section", "content": "Other"},
551
- {"columnId": "1", "columnName": "Question", "content": "What do you know?"},
552
- {
553
- "columnId": "2",
554
- "columnName": "Knowledge Base Answer",
555
- "content": "Lorem Ipsum is simply dummy texktop publishing software.",
556
- },
557
- ],
558
- },
559
- ],
560
- "ingestionConfiguration": {
561
- "columnIdsInMetadata": ["1", "2"],
562
- "columnIdsInChunkText": ["1", "2"],
563
- },
564
- "metadata": {
565
- "libraryName": "foo",
566
- },
567
- "scopeId": scope_id,
568
- "sheetName": "Sheet1",
569
- }
570
-
571
- unique_sdk.Content.ingest_magic_table_sheets(**params)
572
- ```
573
-
574
- #### `unique_sdk.Content.update` (Compatible with release >.36)
575
-
576
- Allows you to update a file specified by its `contentId` or by its `filePath`.
577
-
578
- - `contentId` optional if `filePath` is provided, the id of the file to be updated
579
- - `filePath` optional if `contentId` is provided, the absolute path of the file to be updated
580
-
581
- Currently, the following updates are supported:
582
-
583
- Title update:
584
- - `title` optional, allows updating the title of the file
585
-
586
- Move the file to a different folder. This can be done by specifying either the `ownerId` or the `parentFolderPath`.
587
- - `ownerId` optional, allows moving the file to a different folder. Represents the new folder for the file and it should be the id of a folder e.g.: `scope_dhjfieurfloakmdle`.
588
- - `parentFolderPath` optional, allows moving the file to a different folder. Represents the path new folder for the file.
589
-
590
- Metadata update:
591
- - `metadata` optional, allows updating the metadata of the file. Default metadata can not be overridden. (Available with release >.40)
592
-
593
- Example of updating the title of a file specified by its path.
594
-
595
- ```python
596
- unique_sdk.Content.update(
597
- user_id=user_id,
598
- company_id=company_id,
599
- filePath="/Company/finance/january.xls",
600
- title="Revision Deck"
601
- )
602
- ```
603
-
604
- Example of moving a file specified by its content id.
605
-
606
- ```python
607
- unique_sdk.Content.update(
608
- user_id=user_id,
609
- company_id=company_id,
610
- contentId="cont_ok2343q5owbce80w78hudawu5",
611
- ownerId="scope_e68yz5asho7glfh7c7d041el",
612
- metadata={
613
- "quarter": "q1",
614
- }
615
- )
616
- ```
617
-
618
- Example of moving a file and updating its title.
619
-
620
- ```python
621
- unique_sdk.Content.update(
622
- user_id=user_id,
623
- company_id=company_id,
624
- contentId="cont_ok2343q5owbce80w78hudawu5",
625
- ownerId="scope_e68yz5asho7glfh7c7d041el",
626
- title="Revision Deck (1)"
627
- )
628
- ```
629
-
630
- Example of moving a file to a folder specified by its path.
631
-
632
- ```python
633
- unique_sdk.Content.update(
634
- user_id=user_id,
635
- company_id=company_id,
636
- contentId="cont_ok2343q5owbce80w78hudawu5",
637
- ownerId="scope_e68yz5asho7glfh7c7d041el",
638
- parentFolderPath="/Company/Revisions"
639
- )
640
- ```
641
-
642
- #### `unique_sdk.Content.delete` (Compatible with release >.36)
643
-
644
- Allows you to delete a file by its `contentId`. If the file is part of a chat, the `chatId` also needs do be set.
645
-
646
- - `contentId` optional if `filePath` is provided, the id of the file to be deleted
647
- - `chatId` optional, the id of the chat where the file is. Only needed if the file is part of a chat
648
- - `filePath` optional if `contentId` is provided, the absolute path of the file to be deleted
649
-
650
- Example of deleting a file from a chat.
651
-
652
- ```python
653
- unique_sdk.Content.delete(
654
- user_id=user_id,
655
- company_id=company_id,
656
- contentId="cont_ok2343q5owbce80w78hudawu5",
657
- chatId="chat_v3xfa7liv876h89vuiibus1"
658
- )
659
- ```
660
-
661
- Example of deleting a file by its path.
662
-
663
- ```python
664
- unique_sdk.Content.delete(
665
- user_id=user_id,
666
- company_id=company_id,
667
- filePath="/Company/finance/january.xls",
668
- )
669
- ```
670
-
671
-
672
- ### Message
673
-
674
- #### `unique_sdk.Message.list`
675
-
676
- Retrieve a list of messages for a provided `chatId`.
677
-
678
- ```python
679
- messages = unique_sdk.Message.list(
680
- user_id=user_id,
681
- company_id=company_id,
682
- chatId=chat_id,
683
- )
684
- ```
685
-
686
- #### `unique_sdk.Message.retrieve`
687
-
688
- Get a single chat message.
689
-
690
- ```python
691
- message = unique_sdk.Message.retrieve(
692
- user_id=user_id,
693
- company_id=company_id,
694
- id=message_id,
695
- chatId=chat_id,
696
- )
697
- ```
698
-
699
- #### `unique_sdk.Message.create`
700
-
701
- Create a new message in a chat.
702
-
703
- ```python
704
- message = unique_sdk.Message.create(
705
- user_id=user_id,
706
- company_id=company_id,
707
- chatId=chat_id,
708
- assistantId=assistant_id,
709
- text="Hello.",
710
- role="ASSISTANT",
711
- )
712
- ```
713
-
714
- #### `unique_sdk.Message.create_event`
715
-
716
- Create a new message event in a chat. Updating the text of a message in the chat UI is possible by creating a message update event. This function can be used for custom streaming to the chat. (Compatible with release >.42)
717
-
718
- The event only changes the text in the UI, it *does not* update the database.
719
-
720
- ```python
721
- message = unique_sdk.Message.create_event(
722
- user_id=user_id,
723
- company_id=company_id,
724
- messageId="msg_l4ushn85yqbewpf6tllh2cl7",
725
- chatId="chat_kc8p3kgkn7393qhgmv5js5nt",
726
- text="Hello.", #optional
727
- originalText="Hello.", #optional
728
- references=[], #optional
729
- gptRequest={} #optional
730
- debugInfo={ "hello": "test" }, #optional
731
- )
732
- ```
733
-
734
- #### `unique_sdk.Message.modify`
735
-
736
- Modify an existing chat message.
737
-
738
- ℹ️ if you modify the debugInfo only do it on the user message as this is the only place that is displayed in the frontend.
739
-
740
- ```python
741
- message = unique_sdk.Message.modify(
742
- user_id=user_id,
743
- company_id=company_id,
744
- id=message_id,
745
- chatId=chat_id,
746
- text="Updated message text"
747
- )
748
- ```
749
-
750
- #### `unique_sdk.Message.delete`
751
-
752
- Delete a chat message.
753
-
754
- ```python
755
- message = unique_sdk.Message.delete(
756
- message_id,
757
- user_id=user_id,
758
- company_id=company_id,
759
- chatId=chat_id,
760
- )
761
- ```
762
-
763
- #### `unique_sdk.Integrated.stream`
764
-
765
- Streams the answer to the chat frontend. Given the messages.
766
-
767
- if the stream creates [source0] it is referenced with the references from the search context.
768
-
769
- E.g.
770
-
771
- ```
772
- Hello this information is from [srouce1]
773
- ```
774
-
775
- adds the reference at index 1 and then changes the text to:
776
-
777
- ```
778
- Hello this information is from <sub>0</sub>
779
- ```
780
-
781
- ```python
782
- unique_sdk.Integrated.chat_stream_completion(
783
- user_id=userId,
784
- company_id=companyId,
785
- assistantMessageId=assistantMessageId,
786
- userMessageId=userMessageId,
787
- messages=[
788
- {
789
- "role": "system",
790
- "content": "be friendly and helpful"
791
- },
792
- {
793
- "role": "user",
794
- "content": "hello"
795
- }
796
- ],
797
- chatId=chatId,
798
-
799
- searchContext= [
800
- {
801
- "id": "ref_qavsg0dcl5cbfwm1fvgogrvo",
802
- "chunkId": "0",
803
- "key": "some reference.pdf : 8,9,10,11",
804
- "sequenceNumber": 1,
805
- "url": "unique://content/cont_p8n339trfsf99oc9f36rn4wf"
806
- }
807
- ], # optional
808
- debugInfo={
809
- "hello": "test"
810
- }, # optional
811
- startText= "I want to tell you about: ", # optional
812
- model= "AZURE_GPT_4_32K_0613", # optional
813
- timeout=8000, # optional in ms
814
- options={
815
- "temperature": 0.5
816
- } # optional
817
- )
818
- ```
819
-
820
- **Warning:** Currently, the deletion of a chat message does not automatically sync with the user UI. Users must refresh the chat page to view the updated state. This issue will be addressed in a future update of our API.
821
-
822
-
823
- #### `unique_sdk.Integrated.responses_stream`
824
-
825
- Streams the answer to the chat frontend using the Responses API. Given the messages.
826
-
827
- if the stream creates [source0] it is referenced with the references from the search context.
828
-
829
- E.g.
830
-
831
- ```
832
- Hello this information is from [source1]
833
- ```
834
-
835
- adds the reference at index 1 and then changes the text to:
836
-
837
- ```
838
- Hello this information is from <sub>0</sub>
839
- ```
840
-
841
- ```python
842
- unique_sdk.Integrated.responses_stream(
843
- user_id=userId,
844
- company_id=companyId,
845
- model="AZURE_o3_2025_0416",
846
- assistantMessageId=assistantMessageId,
847
- userMessageId=userMessageId,
848
- input="Tell me about the curious case of neural text degeneration",
849
- chatId=chatId,
850
- )
851
- ```
852
-
853
- **Warning:** Currently, the deletion of a chat message does not automatically sync with the user UI. Users must refresh the chat page to view the updated state. This issue will be addressed in a future update of our API.
854
-
855
- ### Message Log
856
-
857
- #### `unique_sdk.MessageLog.create`
858
-
859
- Function to update the steps section of a message in the chat UI. This is possible by creating a message log record during a message execution.
860
-
861
- ```python
862
- msg_log = unique_sdk.MessageLog.create(
863
- user_id=user_id,
864
- company_id=company_id,
865
- messageId="msg_a0jgnt1jrqv1d3uzr450waxw",
866
- text="Create message log text",
867
- order=1,
868
- status="RUNNING", # one of "RUNNING", "COMPLETED", "FAILED"
869
- details={}, # optional, details dictionary
870
- uncitedReferences={}, # optional, references dictionary
871
- references=[], # optional, list of references
872
- )
873
- ```
874
-
875
- #### `unique_sdk.MessageLog.update`
876
-
877
- Update a message log for a provided `messageId`.
878
-
879
- ```python
880
- msg_log = unique_sdk.MessageLog.update(
881
- user_id=user_id,
882
- company_id=company_id,
883
- message_log_id="message_log_fd7z7gjljo1z2wu5g6l9q7r9",
884
- text="Update a message log text", # optional
885
- order=1, # optional
886
- status="RUNNING", # one of "RUNNING", "COMPLETED", "FAILED"
887
- details={}, # optional, details dictionary
888
- uncitedReferences={}, # optional, references dictionary
889
- references=[], # optional, list of references
890
- )
891
- ```
892
-
893
- ### Message Execution
894
-
895
- #### `unique_sdk.MessageExecution.create`
896
-
897
- Create a message execution for a provided `messageId` and `chatId`.
898
-
899
- ```python
900
- msg_execution = unique_sdk.MessageExecution.create(
901
- user_id=user_id,
902
- company_id=company_id,
903
- messageId="msg_a0jgnt1jrqv143uzr750waxw",
904
- type="DEEP_RESEARCH",
905
- )
906
- ```
907
-
908
- #### `unique_sdk.MessageExecution.get`
909
-
910
- Get a message execution for a provided `messageId`.
911
-
912
- ```python
913
- msg_execution = unique_sdk.MessageExecution.get(
914
- user_id=user_id,
915
- company_id=company_id,
916
- messageId="msg_a0jgnt1jrqv143uzr750waxw",
917
- )
918
- ```
919
-
920
- #### `unique_sdk.MessageExecution.update`
921
-
922
- Update a message execution for a provided `messageId`.
923
-
924
- ```python
925
- msg_execution = unique_sdk.MessageExecution.update(
926
- user_id=user_id,
927
- company_id=company_id,
928
- messageId="msg_a0jgnt1jrqv143uzr750waxw",
929
- status="COMPLETED", # optional, one of: COMPLETED, FAILED - not specifying the status will have no effect over the status
930
- secondsRemaining=55, # optional, number defining the seconds remaining
931
- percentageCompleted=10, # optional, number defining the percentage completed
932
- )
933
- ```
934
-
935
- ### Chat Completion
936
-
937
- #### `unique_sdk.ChatCompletion.create`
938
-
939
- Send a prompt to an AI model supported by Unique AI and receive a result. The `messages` attribute must follow the [OpenAI API format](https://platform.openai.com/docs/api-reference/chat).
940
-
941
- ```python
942
- chat_completion = unique_sdk.ChatCompletion.create(
943
- company_id=company_id,
944
- user_id=user_id
945
- model="AZURE_GPT_4o_2024_1120",
946
- messages=[
947
- {"role": "system", "content": "You are a helpful assistant."},
948
- {"role": "user", "content": "Hello!"},
949
- ],
950
- options={
951
- "temperature": 0.5, # optional
952
- } # optional
953
- )
954
- ```
955
-
956
- ### Embeddings
957
-
958
- #### `unique_sdk.Embeddings.create`
959
-
960
- Sends an array of `text` to the AI model for embedding. And retrieve a vector of embeddings.
961
-
962
- ```python
963
- result = unique_sdk.Embeddings.create(
964
- user_id=user_id,
965
- company_id=company_id,
966
- texts=["hello", "hello"],
967
- )
968
- print(result.embeddings[0][0])
969
- ```
970
-
971
- ### Acronyms
972
-
973
- #### `unique_sdk.Acronyms.get`
974
-
975
- Fetches the acronyms defined on the company. Often used to replace in user prompts, so the acronym is resolved to give better guidance to the LLM during completion.
976
-
977
- ```python
978
- result = unique_sdk.Acronyms.get(
979
- user_id=user_id,
980
- company_id=company_id,
981
- )
982
- print(result)
983
- ```
984
-
985
- ### Search
986
-
987
- #### `unique_sdk.Search.create`
988
-
989
- Search the Unique AI Knowledge database for RAG (Retrieval-Augmented Generation). The API supports vector search and a `searchType` that combines vector and full-text search, enhancing the precision of search results.
990
-
991
- These are the options are available for `searchType`:
992
-
993
- - `VECTOR`
994
- - `COMBINED`
995
-
996
- `limit` (max 1000) and `page` are optional for iterating over results.
997
- `chatOnly` Restricts the search exclusively to documents uploaded within the chat.
998
- `scopeIds` Specifies a collection of scope IDs to confine the search.
999
- `language` Optional. The language specification for full text search.
1000
- `reranker` Optional. The reranker service to be used for re-ranking the search results.
1001
- `chatId` Optional, adds the documents uploaded in this chat to the scope of searched documents.
1002
- `scoreThreshold` Optional, sets the minimum similarity score for search results to be considered. Using 0 is recommended.
1003
-
1004
- ```python
1005
- search = unique_sdk.Search.create(
1006
- user_id=user_id,
1007
- company_id=company_id,
1008
- chatId=chat_id
1009
- searchString="What is the meaning of life, the universe and everything?",
1010
- searchType="VECTOR",
1011
- chatOnly=false,
1012
- scopeIds=["scope_..."],
1013
- language="German",
1014
- reranker={"deploymentName": "my_deployment"},
1015
- limit=20,
1016
- page=1
1017
- scoreThreshold=0
1018
- )
1019
- ```
1020
-
1021
- ### Search String
1022
-
1023
- #### `unique_sdk.SearchString.create`
1024
-
1025
- User messages are sometimes suboptimal as input prompts for vector or full-text knowledge base searches. This is particularly true as a conversation progresses and a user question may lack crucial context for a successful search.
1026
-
1027
- This API transforms and translates (into English) the user's message into an ideal search string for use in the [Search.create](#unique_sdksearchcreate) API method.
1028
-
1029
- Adding a `chatId` or `messages` as arguments allows the message history to provide additional context to the search string. For example, "Who is the author?" will be expanded to "Who is the author of the book 'The Hitchhiker's Guide to the Galaxy'?" if previous messages referenced the book.
1030
-
1031
- ```python
1032
- search_string = unique_sdk.SearchString.create(
1033
- user_id=user_id,
1034
- company_id=company_id,
1035
- prompt="Was ist der Sinn des Lebens, des Universums und des ganzen Rests?",
1036
- chat_id=chat_id
1037
- )
1038
- ```
1039
-
1040
- ### Short Term Memory
1041
-
1042
- For saving data in between chats there is the Short Term Memory functionality to save small data in between rounds of chat e.g. language, search results and so on.
1043
- For this 10k chars can be used. You can save a short term memory for a chat `chatId` or for a message `messageId`.
1044
- you need to provide an `memoryName` as an identifier.
1045
-
1046
- you can then save it and retreive it live defined below.
1047
-
1048
-
1049
- #### `unique_sdk.ShortTermMemory.create`
1050
-
1051
- ```python
1052
- c = unique_sdk.ShortTermMemory.create(
1053
- user_id=user_id,
1054
- company_id=company_id,
1055
- data="hello",
1056
- chatId="chat_x0xxtj89f7drjp4vmued3q",
1057
- # messageId = "msg_id",
1058
- memoryName="your memory name",
1059
- )
1060
- print(c)
1061
- ```
1062
-
1063
- #### `unique_sdk.ShortTermMemory.find-latest`
1064
-
1065
- ```python
1066
- m = unique_sdk.ShortTermMemory.find_latest(
1067
- user_id=user_id,
1068
- company_id=company_id,
1069
- chatId="chat_x0xxtj89f7drjp4vmued3q",
1070
- # messageId = "msg_id",
1071
- memoryName="your memory name",
1072
- )
1073
- print(m)
1074
- ```
1075
-
1076
- ### Message Assessment
1077
-
1078
- Used to create and modify message assessments for tracking hallucinations and compliance evaluations of assistant messages.
1079
-
1080
- #### `unique_sdk.MessageAssessment.create`
1081
-
1082
- Create a new message assessment for an assistant message.
1083
-
1084
- ```python
1085
- assessment = unique_sdk.MessageAssessment.create(
1086
- user_id=user_id,
1087
- company_id=company_id,
1088
- assistant_message_id="msg_...",
1089
- status="DONE",
1090
- explanation="This response contains incorrect information about...",
1091
- label="RED",
1092
- type="HALLUCINATION",
1093
- title="Hallucination detected",
1094
- isVisible=True
1095
- )
1096
- ```
1097
-
1098
- #### `unique_sdk.MessageAssessment.modify`
1099
-
1100
- Modify an existing message assessment.
1101
-
1102
- ```python
1103
- assessment = unique_sdk.MessageAssessment.modify(
1104
- user_id=user_id,
1105
- company_id=company_id,
1106
- assistant_message_id="msg_...",
1107
- status="DONE",
1108
- explanation="Updated explanation...",
1109
- label="RED",
1110
- title="update title"
1111
- type="HALLUCINATION"
1112
- )
1113
- ```
1114
-
1115
- ### Folder
1116
-
1117
- #### `unique_sdk.Folder.get_info`
1118
-
1119
- Get a folder by scope id or by path.
1120
-
1121
- By scope id:
1122
-
1123
- ```python
1124
- unique_sdk.Folder.get_info(
1125
- user_id=user_id,
1126
- company_id=company_id,
1127
- scopeId="scope_w78wfn114va9o22s13r03yq",
1128
- )
1129
- ```
1130
-
1131
- By path:
1132
-
1133
- ```python
1134
- unique_sdk.Folder.get_info(
1135
- user_id=user_id,
1136
- company_id=company_id,
1137
- folderPath="/Company/Atlas/Due Dilligence/Arch,
1138
- )
1139
- ```
1140
-
1141
- #### `unique_sdk.Folder.get_folder_path` (Compatible with release >.48)
1142
-
1143
- Get the complete folder path for a given scope ID. Returns the full path string with folder names (e.g., "/company/subfolder1/subfolder2").
1144
-
1145
- ```python
1146
- folder_path = unique_sdk.Folder.get_folder_path(
1147
- user_id=user_id,
1148
- company_id=company_id,
1149
- scope_id="scope_w78wfn114va9o22s13r03yq",
1150
- )
1151
- ```
1152
-
1153
- #### `unique_sdl.Folder.get_infos`
1154
-
1155
- Get paginated folders info based on parentId. If the parentId is not defined, the root folders will be returned.
1156
-
1157
- ```python
1158
- unique_sdk.Folder.get_infos(
1159
- user_id=user_id,
1160
- company_id=company_id,
1161
- take=10, #optional
1162
- skip=5, #optional
1163
- parentId="scope_s18seqpnltf35niydg77xgyp" #optional
1164
- )
1165
- ```
1166
-
1167
- #### `unique_sdk.Folder.create_paths`
1168
-
1169
- Create each folder in the provided list of paths if it does not already exist.
1170
-
1171
- ```python
1172
- unique_sdk.Folder.create_paths(
1173
- user_id=user_id,
1174
- company_id=company_id,
1175
- paths=["/unique/path1", "/unique/path2"],
1176
- )
1177
- ```
1178
-
1179
- #### `unique_sdk.Folder.update_ingestion_config`
1180
-
1181
- Allows you to update the ingestion config of a folder and choose whether to apply to the subscopes or not: `
1182
-
1183
- - `ingestionConfig`
1184
- - `applyToSubScopes`
1185
-
1186
- The update can be done by referencing the folder by id or by path. If none of them are provided. the API will return an error. If both of them are provided, the scope id will take precedence.
1187
-
1188
- Example of updating the ingestion config of a folder and its subfolders using the id.
1189
-
1190
- ```python
1191
- unique_sdk.Folder.update_ingestion_config(
1192
- user_id=user_id,
1193
- company_id=company_id,
1194
- scopeId="scope_qbnkde820dbmuw2900,
1195
- ingestionConfig={
1196
- "chunkStrategy": "default",
1197
- "uniqueIngestionMode": "standard",
1198
- },
1199
- applyToSubScopes=True
1200
- )
1201
- ```
1202
-
1203
- Example of updating the ingestion config of a folder and its subfolders using the path.
1204
-
1205
- ```python
1206
- unique_sdk.Folder.update_ingestion_config(
1207
- user_id=user_id,
1208
- company_id=company_id,
1209
- folderPath="/Company/folder1/folder2",
1210
- ingestionConfig={
1211
- "chunkStrategy": "default",
1212
- "uniqueIngestionMode": "standard",
1213
- },
1214
- applyToSubScopes=True
1215
- )
1216
- ```
1217
-
1218
- #### `unique_sdk.Folder.add_access`
1219
-
1220
- Allows you to add access to a folder and apply to the subfolders or not: `
1221
-
1222
- - `scopeAccesses`
1223
- - `applyToSubScopes`
1224
-
1225
- The update can be done by referencing the folder by id or by path. If none of them are provided. the API will return an error. If both of them are provided, the scope id will take precedence.
1226
-
1227
- Example of adding access to a folder and its subfolders using the id.
1228
-
1229
- ```python
1230
- unique_sdk.Folder.add_access(
1231
- user_id=user_id,
1232
- company_id=company_id,
1233
- scopeId="scope_231e4kjn4foffww34",
1234
- scopeAccesses=[
1235
- {
1236
- "entityId": "group_id",
1237
- "type": "WRITE",
1238
- "entityType": "GROUP",
1239
- }
1240
- ],
1241
- applyToSubScopes=True,
1242
- )
1243
- ```
1244
-
1245
- Example of adding access to a folder and its subfolders using the folder path.
1246
-
1247
- ```python
1248
- unique_sdk.Folder.add_access(
1249
- user_id=user_id,
1250
- company_id=company_id,
1251
- folderPath="/Company/folder1/folder2"
1252
- scopeAccesses=[
1253
- {
1254
- "entityId": "group_id",
1255
- "type": "WRITE",
1256
- "entityType": "GROUP",
1257
- }
1258
- ],
1259
- applyToSubScopes=True,
1260
- )
1261
- ```
1262
-
1263
- #### `unique_sdk.Folder.remove_access`
1264
-
1265
- Allows you to delete access from a folder and apply to the subfolders or not:
1266
-
1267
- - `scopeAccesses`
1268
- - `applyToSubScopes`
1269
-
1270
- The update can be done by referencing the folder by id or by path. If none of them are provided. the API will return an error. If both of them are provided, the scope id will take precedence.
1271
-
1272
-
1273
- Example of deleting the access from a folder and its subfolders using the id.
1274
-
1275
- ```python
1276
- unique_sdk.Folder.remove_access(
1277
- user_id=user_id,
1278
- company_id=company_id,
1279
- scopeId="scope_dwekjnf3330woioppm,
1280
- scopeAccesses=[
1281
- {
1282
- "entityId": "group_id",
1283
- "type": "WRITE",
1284
- "entityType": "GROUP",
1285
- }
1286
- ],
1287
- applyToSubScopes=True,
1288
- )
1289
- ```
1290
-
1291
-
1292
- Example of deleting the access from a folder and its subfolders using the path.
1293
-
1294
- ```python
1295
- unique_sdk.Folder.remove_access(
1296
- user_id=user_id,
1297
- company_id=company_id,
1298
- folderPath="/Company/folder1/folder2"
1299
- scopeAccesses=[
1300
- {
1301
- "entityId": "group_id",
1302
- "type": "WRITE",
1303
- "entityType": "GROUP",
1304
- }
1305
- ],
1306
- applyToSubScopes=True,
1307
- )
1308
- ```
1309
-
1310
- #### `unique_sdk.Folder.update`
1311
- Uupdate a folder specified by its `scopeId` or path. The following properties can be updated:
1312
- - parent folder - move the folder to a new parent folder specified by its `scopeId` or path. If the new parent folder is the root folder, the `parentId` should be explicitly specificed by setting `newParentId` to `None`.
1313
- - name - update the name by setting the `name` field to the new name.
1314
-
1315
- Examples:
1316
-
1317
- Move the folder specified by its `scopeId` to a new parent folder specified by its path.
1318
-
1319
- ```python
1320
- unique_sdk.Folder.update(
1321
- user_id=user_id,
1322
- company_id=company_id,
1323
- scopeId="scope_dwekjnf3330woioppm",
1324
- parentFolderPath="/Company/folder1/folder2"
1325
- )
1326
- ```
1327
-
1328
- Move the parent of a folder specified by its path to a new parent folder specified by its `scopeId` and update the name to "January".
1329
-
1330
- ```python
1331
- unique_sdk.Folder.update(
1332
- user_id=user_id,
1333
- company_id=company_id,
1334
- folderPath="/Company/folder1",
1335
- parentId="scope_dweekjrfhirtuhgroppm",
1336
- name="January"
1337
- )
1338
- ```
1339
-
1340
- Move the parent of a folder specified by its path to the root folder and update the name to "January".
1341
-
1342
- ```python
1343
- unique_sdk.Folder.update(
1344
- user_id=user_id,
1345
- company_id=company_id,
1346
- folderPath="/Company/folder1",
1347
- parentId=None,
1348
- name="January"
1349
- )
1350
- ```
1351
-
1352
-
1353
- #### `unique_sdk.Folder.delete` (Compatible with release >.36)
1354
-
1355
- Given a `scopeId` or `folderPath`, the function deletes the folder. If the folder is not empty or if the user has no WRITE access, the delete will fail.
1356
-
1357
- If `recursive` is set to true, the function also deletes its subfolders and its contents, behaving exactly like the `rm -rf`. In case a subfolder has no write access, that folder is considered as failed to delete and the function continues with the other subfolders. At the end, the function returns a list of `successFolders` and `failedFolders`.
1358
-
1359
- Examples:
1360
- Deleting recursively by scope id:
1361
-
1362
- ```python
1363
- unique_sdk.Folder.delete(
1364
- user_id=user_id,
1365
- company_id=company_id,
1366
- scopeId="scope_w78wfn114va9o22s13r03yq",
1367
- recursive=True
1368
- )
1369
- ```
1370
-
1371
- Deleting by path (non-recursive):
1372
-
1373
- ```python
1374
- unique_sdk.Folder.delete(
1375
- user_id=user_id,
1376
- company_id=company_id,
1377
- folderPath="/Company/Atlas/Due Dilligence/Arch",
1378
- )
1379
- ```
1380
-
1381
- ### Space
1382
-
1383
- #### `unique_sdk.Space.create_message`
1384
-
1385
- Send a message in a space. You can optionally provide a chat ID to continue an existing conversation, or omit it to start a new chat.
1386
-
1387
- ```python
1388
- message = unique_sdk.Space.create_message(
1389
- user_id=user_id,
1390
- company_id=company_id,
1391
- chatId="chat_dejfhe729br398", # Optional - if not provided, a new chat will be created
1392
- assistantId="assistant_abc123",
1393
- text="Hello, how can you help me?",
1394
- toolChoices=["WebSearch"], # Optional - list of tools to use
1395
- scopeRules={ # Optional - scope rules for filtering
1396
- "or": [
1397
- {
1398
- "operator": "contains",
1399
- "path": ["folderIdPath"],
1400
- "value": "uniquepathid://scope_123"
1401
- }
1402
- ]
1403
- },
1404
- )
1405
- ```
1406
-
1407
- #### `unique_sdk.Space.get_chat_messages` (Compatible with release >.48)
1408
-
1409
- Get all messages in a space chat. Returns a list of paginated messages in the specified chat.
1410
-
1411
- ```python
1412
- messages = unique_sdk.Space.get_chat_messages(
1413
- user_id=user_id,
1414
- company_id=company_id,
1415
- chat_id="chat_dejfhe729br398",
1416
- skip=0, # Optional (defaults to 0) - number of messages to skip for pagination
1417
- take=50, # Optional (defaults to 10) - number of messages to return
1418
- )
1419
- ```
1420
-
1421
- #### `unique_sdk.Space.get_latest_message`
1422
-
1423
- Get the latest message in a space chat.
1424
-
1425
- ```python
1426
- message = unique_sdk.Space.get_latest_message(
1427
- user_id=user_id,
1428
- company_id=company_id,
1429
- chat_id="chat_dejfhe729br398",
1430
- )
1431
- ```
1432
-
1433
- #### `unique_sdk.Space.get_space` (Compatible with release >.48)
1434
-
1435
- Get detailed information about a space, including its configuration, modules and scope rules.
1436
-
1437
- ```python
1438
- space_info = unique_sdk.Space.get_space(
1439
- user_id=user_id,
1440
- company_id=company_id,
1441
- space_id="assistant_hjcdga64bkcjnhu4",
1442
- )
1443
- ```
1444
-
1445
- #### `unique_sdk.Space.delete_chat`
1446
-
1447
- Delete a space chat by id. If the chat does not exist, the function will return an error.
1448
-
1449
- ```python
1450
- unique_sdk.Space.delete_chat(
1451
- user_id=user_id,
1452
- company_id=company_id,
1453
- chat_id="chat_dejfhe729br398",
1454
- )
1455
- ```
1456
-
1457
- ### LLM Models
1458
-
1459
- #### `unique_sdk.LLMModels.get` (Compatible with release >.46)
1460
-
1461
- Get available LLM models. You can optionally filter by module and skip cache to fetch fresh data.
1462
-
1463
- ```python
1464
- models = unique_sdk.LLMModels.get(
1465
- user_id=user_id,
1466
- company_id=company_id,
1467
- module="UNIQUE_AI", # Optional - filter models by module, only UNIQUE_AI is supported right now
1468
- )
1469
- ```
1470
-
1471
- ### User
1472
-
1473
- #### `unique_sdk.User.get_users` (Compatible with release >.48)
1474
-
1475
- Get users in a company. You can filter by email, display name, and use pagination with skip and take parameters.
1476
-
1477
- ```python
1478
- users = unique_sdk.User.get_users(
1479
- user_id=user_id,
1480
- company_id=company_id,
1481
- skip=0, # Optional - number of records to skip for pagination
1482
- take=50, # Optional - number of records to return (max 1000)
1483
- email="user@example.com", # Optional - filter by email
1484
- displayName="John", # Optional - filter by display name
1485
- )
1486
- ```
1487
-
1488
- #### `unique_sdk.User.update_user_configuration` (Compatible with release >.48)
1489
-
1490
- Update the user configuration for the current user. The configuration is stored as a JSON object.
1491
-
1492
- ```python
1493
- updated_user = unique_sdk.User.update_user_configuration(
1494
- user_id=user_id,
1495
- company_id=company_id,
1496
- userConfiguration={ # Required - user configuration object (JSON)
1497
- {"location": "CH"}
1498
- }
1499
- )
1500
- ```
1501
-
1502
- ### Group
1503
-
1504
- #### `unique_sdk.Group.create_group` (Compatible with release >.48)
1505
-
1506
- Create a new group in a company. You can specify the group name (required), external ID and parent group ID.
1507
-
1508
- ```python
1509
- group = unique_sdk.Group.create_group(
1510
- user_id=user_id,
1511
- company_id=company_id,
1512
- name="New Group", # Required - the name of the group
1513
- externalId="ext_123", # Optional - external ID for the group
1514
- parentId="group_a9cs7wr2z1bg2sxczvltgjch", # Optional - parent group ID
1515
- )
1516
- ```
1517
-
1518
- #### `unique_sdk.Group.get_groups` (Compatible with release >.48)
1519
-
1520
- Get groups in a company. You can filter by name and use pagination with skip and take parameters.
1521
-
1522
- ```python
1523
- groups = unique_sdk.Group.get_groups(
1524
- user_id=user_id,
1525
- company_id=company_id,
1526
- skip=0, # Optional - number of records to skip for pagination
1527
- take=50, # Optional - number of records to return (max 1000)
1528
- name="Admin", # Optional - filter by group name
1529
- )
1530
- ```
1531
-
1532
- #### `unique_sdk.Group.update_group` (Compatible with release >.48)
1533
-
1534
- Update a group in a company. You can update the group's name.
1535
-
1536
- ```python
1537
- updated_group = unique_sdk.Group.update_group(
1538
- user_id=user_id,
1539
- company_id=company_id,
1540
- group_id="group_a9cs7wr2z1bg2sxczvltgjch",
1541
- name="New Group Name", # Optional - update the group name
1542
- )
1543
- ```
1544
-
1545
- #### `unique_sdk.Group.add_users_to_group` (Compatible with release >.48)
1546
-
1547
- Add users to a group. Provide an array of user IDs to add as members to the specified group.
1548
-
1549
- ```python
1550
- result = unique_sdk.Group.add_users_to_group(
1551
- user_id=user_id,
1552
- company_id=company_id,
1553
- group_id="group_a9cs7wr2z1bg2sxczvltgjch",
1554
- userIds=["299420877169688584", "325402458132058201", "299426678160031752"], # Required - array of user IDs to add
1555
- )
1556
- ```
1557
-
1558
- #### `unique_sdk.Group.remove_users_from_group` (Compatible with release >.48)
1559
-
1560
- Remove users from a group. Provide an array of user IDs to remove from the specified group.
1561
-
1562
- ```python
1563
- result = unique_sdk.Group.remove_users_from_group(
1564
- user_id=user_id,
1565
- company_id=company_id,
1566
- group_id="group_a9cs7wr2z1bg2sxczvltgjch",
1567
- userIds=["299426678160031752", "299426678160031752"], # Required - array of user IDs to remove
1568
- )
1569
- ```
1570
-
1571
- #### `unique_sdk.Group.update_group_configuration` (Compatible with release >.48)
1572
-
1573
- Update the group configuration for the specified group. The configuration is stored as a JSON object.
1574
-
1575
- ```python
1576
- updated_group = unique_sdk.Group.update_group_configuration(
1577
- user_id=user_id,
1578
- company_id=company_id,
1579
- group_id="group_abc123",
1580
- configuration={ # Required - group configuration object (JSON)
1581
- {"email": "team@unique.ai"}
1582
- }
1583
- )
1584
- ```
1585
-
1586
- #### `unique_sdk.Group.delete_group` (Compatible with release >.48)
1587
-
1588
- Delete a group in a company by its group ID.
1589
-
1590
- ```python
1591
- result = unique_sdk.Group.delete_group(
1592
- user_id=user_id,
1593
- company_id=company_id,
1594
- group_id="group_a9cs7wr2z1bg2sxczvltgjch",
1595
- )
1596
- ```
1597
-
1598
- ### Agentic Table
1599
-
1600
- The Agentic Table (Magic Table) API provides functionality for managing interactive tables with AI-powered cells, activity tracking, and metadata management.
1601
-
1602
- #### `unique_sdk.AgenticTable.set_cell`
1603
-
1604
- Set the content of a specific cell in the magic table. This method allows you to update cell text and optionally add log entries to track changes.
1605
-
1606
- ```python
1607
- cell = await unique_sdk.AgenticTable.set_cell(
1608
- user_id=user_id,
1609
- company_id=company_id,
1610
- tableId="sheet_abc123",
1611
- rowOrder=0,
1612
- columnOrder=1,
1613
- text="Updated cell content",
1614
- logEntries=[ # optional
1615
- {
1616
- "text": "Cell updated by automation",
1617
- "createdAt": "2024-01-01T00:00:00.000Z",
1618
- "actorType": "SYSTEM", # One of: "USER", "SYSTEM", "ASSISTANT", "TOOL"
1619
- "messageId": "msg_123", # optional
1620
- "details": [ # optional
1621
- {
1622
- "text": "Processing completed",
1623
- "messageId": "msg_456" # optional
1624
- }
1625
- ]
1626
- }
1627
- ]
1628
- )
1629
- ```
1630
-
1631
- #### `unique_sdk.AgenticTable.get_cell`
1632
-
1633
- Retrieve the content and metadata of a specific cell.
1634
-
1635
- ```python
1636
- cell = await unique_sdk.AgenticTable.get_cell(
1637
- user_id=user_id,
1638
- company_id=company_id,
1639
- tableId="sheet_abc123",
1640
- rowOrder=0,
1641
- columnOrder=1,
1642
- )
1643
- ```
1644
-
1645
- #### `unique_sdk.AgenticTable.set_multiple_cells`
1646
-
1647
- Bulk update multiple cells in a single operation for better performance.
1648
-
1649
- ```python
1650
- result = await unique_sdk.AgenticTable.set_multiple_cells(
1651
- user_id=user_id,
1652
- company_id=company_id,
1653
- tableId="sheet_abc123",
1654
- cells=[
1655
- {
1656
- "rowOrder": 0,
1657
- "columnOrder": 0,
1658
- "text": "Cell A1"
1659
- },
1660
- {
1661
- "rowOrder": 0,
1662
- "columnOrder": 1,
1663
- "text": "Cell B1"
1664
- },
1665
- {
1666
- "rowOrder": 1,
1667
- "columnOrder": 0,
1668
- "text": "Cell A2"
1669
- }
1670
- ]
1671
- )
1672
- ```
1673
-
1674
- #### `unique_sdk.AgenticTable.get_sheet_data`
1675
-
1676
- Retrieve comprehensive data about a magic table sheet, including cells, log history, and metadata.
1677
-
1678
- ```python
1679
- sheet = await unique_sdk.AgenticTable.get_sheet_data(
1680
- user_id=user_id,
1681
- company_id=company_id,
1682
- tableId="sheet_abc123",
1683
- includeCells=True, # optional
1684
- includeLogHistory=True, # optional
1685
- includeRowCount=True, # optional
1686
- includeCellMetaData=True, # optional
1687
- startRow=0, # optional: specify row range
1688
- endRow=10 # optional: specify row range
1689
- )
1690
- ```
1691
-
1692
- #### `unique_sdk.AgenticTable.get_sheet_state`
1693
-
1694
- Get the current state of a magic table sheet.
1695
-
1696
- ```python
1697
- state = await unique_sdk.AgenticTable.get_sheet_state(
1698
- user_id=user_id,
1699
- company_id=company_id,
1700
- tableId="sheet_abc123"
1701
- )
1702
- # Returns: "PROCESSING", "IDLE", or "STOPPED_BY_USER"
1703
- ```
1704
-
1705
- #### `unique_sdk.AgenticTable.update_sheet_state`
1706
-
1707
- Update the name or state of a magic table sheet.
1708
-
1709
- ```python
1710
- result = await unique_sdk.AgenticTable.update_sheet_state(
1711
- user_id=user_id,
1712
- company_id=company_id,
1713
- tableId="sheet_abc123",
1714
- name="Updated Sheet Name", # optional
1715
- state="IDLE" # optional, one of: "PROCESSING", "IDLE", "STOPPED_BY_USER"
1716
- )
1717
- ```
1718
-
1719
- #### `unique_sdk.AgenticTable.set_activity`
1720
-
1721
- Set the status of an activity on the magic table sheet. This is useful for tracking long-running operations.
1722
-
1723
- ```python
1724
- result = await unique_sdk.AgenticTable.set_activity(
1725
- user_id=user_id,
1726
- company_id=company_id,
1727
- tableId="sheet_abc123",
1728
- activity="UpdateCell",
1729
- # activity: one of "DeleteRow", "DeleteColumn", "UpdateCell", "AddQuestionText",
1730
- # "AddMetaData", "GenerateArtifact", "SheetCompleted", "LibrarySheetRowVerified"
1731
- status="IN_PROGRESS",
1732
- # status: one of "IN_PROGRESS", "COMPLETED", "FAILED"
1733
- text="Updating cells with AI-generated content"
1734
- )
1735
- ```
1736
-
1737
- #### `unique_sdk.AgenticTable.set_artifact`
1738
-
1739
- Attach an artifact (such as a generated document) to the magic table sheet.
1740
-
1741
- ```python
1742
- result = await unique_sdk.AgenticTable.set_artifact(
1743
- user_id=user_id,
1744
- company_id=company_id,
1745
- tableId="sheet_abc123",
1746
- name="Generated Report",
1747
- contentId="cont_xyz789",
1748
- mimeType="application/pdf",
1749
- artifactType="FULL_REPORT" # One of: "QUESTIONS", "FULL_REPORT"
1750
- )
1751
- ```
1752
-
1753
- #### `unique_sdk.AgenticTable.set_column_metadata`
1754
-
1755
- Configure metadata for a specific column, including width, filters, and cell renderers.
1756
-
1757
- ```python
1758
- result = await unique_sdk.AgenticTable.set_column_metadata(
1759
- user_id=user_id,
1760
- company_id=company_id,
1761
- tableId="sheet_abc123",
1762
- columnOrder=2,
1763
- columnWidth=200, # optional
1764
- filter="ValueMatchFilter", # optional
1765
- # filter: one of "ValueMatchFilter", "PartialMatchFilter", "ReferenceFilter",
1766
- # "HallucinationFilter", "ReviewStatusFilter", "AssigneeFilter"
1767
- cellRenderer="CheckboxLockCellRenderer", # optional
1768
- # cellRenderer: one of "CheckboxLockCellRenderer", "CollaboratorDropdown",
1769
- # "ReviewStatusDropdown", "CustomCellRenderer", "SelectableCellRenderer"
1770
- editable=True # optional
1771
- )
1772
- ```
1773
-
1774
- #### `unique_sdk.AgenticTable.set_cell_metadata`
1775
-
1776
- Set metadata for a specific cell, including selection status and agreement status.
1777
-
1778
- ```python
1779
- result = await unique_sdk.AgenticTable.set_cell_metadata(
1780
- user_id=user_id,
1781
- company_id=company_id,
1782
- tableId="sheet_abc123",
1783
- rowOrder=0,
1784
- columnOrder=1,
1785
- selected=True, # optional
1786
- selectionMethod="MANUAL", # optional, one of: "DEFAULT", "MANUAL"
1787
- agreementStatus="MATCH" # optional, one of: "MATCH", "NO_MATCH"
1788
- )
1789
- ```
1790
-
1791
- #### `unique_sdk.AgenticTable.bulk_update_status`
1792
-
1793
- Update the verification status of multiple rows at once.
1794
-
1795
- ```python
1796
- result = await unique_sdk.AgenticTable.bulk_update_status(
1797
- user_id=user_id,
1798
- company_id=company_id,
1799
- tableId="sheet_abc123",
1800
- rowOrders=[0, 1, 2, 3, 4],
1801
- status="VERIFIED"
1802
- # status: one of "NEED_REVIEW", "READY_FOR_VERIFICATION", "VERIFIED"
1803
- )
1804
- ```
1805
-
1806
- ## UniqueQL
1807
-
1808
- [UniqueQL](https://unique-ch.atlassian.net/wiki/x/coAXHQ) is an advanced query language designed to enhance search capabilities within various search modes such as Vector, Full-Text Search (FTS), and Combined. This query language enables users to perform detailed searches by filtering through metadata attributes like filenames, URLs, dates, and more. UniqueQL is versatile and can be translated into different query formats for various database systems, including PostgreSQL and Qdrant.
1809
-
1810
- ### UniqueQL Query Structure
1811
-
1812
- A UniqueQL query is composed of a path, an operator, and a value. The path specifies the metadata attribute to be filtered, the operator defines the type of comparison, and the value provides the criteria for the filter.
1813
-
1814
- A metadata filter can be designed with UniqueQL's `UQLOperator` and `UQLCombinator` as follows:
1815
-
1816
- ```python
1817
- metadata_filter = {
1818
- "path": ['diet', '*'],
1819
- "operator": UQLOperator.NESTED,
1820
- "value": {
1821
- UQLCombinator.OR : [
1822
- {
1823
- UQLCombinator.OR: [
1824
- {
1825
- "path": ['food'],
1826
- "operator": UQLOperator.EQUALS,
1827
- "value": "meat",
1828
- },
1829
- {
1830
- "path": ['food'],
1831
- "operator": UQLOperator.EQUALS,
1832
- "value": 'vegis',
1833
- },
1834
- ],
1835
- },
1836
- {
1837
- "path": ['likes'],
1838
- "operator": UQLOperator.EQUALS,
1839
- "value": true,
1840
- },
1841
- ],
1842
- },
1843
- }
1844
- ```
1845
-
1846
- ### Metadata Filtering
1847
-
1848
- A metadata filter such as the one designed above can be used in a `Search.create` call by passing it the `metaDataFilter` parameter.
1849
-
1850
- ```python
1851
- search_results = unique_sdk.Search.create(
1852
- user_id=user_id,
1853
- company_id=company_id,
1854
- chatId=chat_id,
1855
- searchString=search_string,
1856
- searchType="COMBINED",
1857
- # limit=2,
1858
- metaDataFilter=metadata_filter,
1859
- )
1860
- ```
1861
-
1862
- ## Utils
1863
-
1864
- - [Chat History](#chat-history)
1865
- - [File Io](#file-io)
1866
- - [Sources](#sources)
1867
- - [token](#token)
1868
- - [Chat In Space](#chat-in-space)
1869
-
1870
- ### Chat History
1871
-
1872
- #### `unique_sdk.utils.chat_history.load_history`
1873
-
1874
- A helper function that makes sure the chat history is fully loaded and cut to the size of the token window that it fits into the next round of chat interactions.
1875
-
1876
- - `maxTokens` max tokens of the model used
1877
- - `percentOfMaxTokens`=0.15 % max history in % of `maxTokens`
1878
- - `maxMessages`=4, maximal number of messages included in the history.
1879
-
1880
- this method also directly returns a correct formatted history that can be used in the next chat round.
1881
-
1882
- ```python
1883
- history = unique_sdk.utils.chat_history.load_history(
1884
- userId,
1885
- companyId,
1886
- chatId
1887
- )
1888
- ```
1889
-
1890
- #### `unique_sdk.utils.chat_history.convert_chat_history_to_injectable_string`
1891
-
1892
- convert history into a string that can be injected into a prompt. it als returns the token length of the converted history.
1893
-
1894
- ```
1895
- chat_history-string, chat_context_token_length = unique_sdk.utils.chat_history.convert_chat_history_to_injectable_string(
1896
- history
1897
- )
1898
- ```
1899
-
1900
- ### File Io
1901
-
1902
- Interacting with the knowledge-base.
1903
-
1904
- #### `unique_sdk.utils.file_io.download_content`
1905
-
1906
- download files and save them into a folder in `/tmp`
1907
-
1908
- for example using the readUrl from a content.
1909
-
1910
- ```python
1911
- pdfFile = download_content(
1912
- companyId=companyId,
1913
- userId=userId,
1914
- content_id="cont_12412",
1915
- filename="hello.pdf",
1916
- chat_id=None # If specified, it downloads it from the chat
1917
- )
1918
- ```
1919
-
1920
- #### `unique_sdk.utils.file_io.upload_file`
1921
-
1922
- Allows for uploading files that then get ingested in a scope or a chat.
1923
-
1924
- ```python
1925
- createdContent = upload_file(
1926
- companyId=companyId,
1927
- userId=userId,
1928
- path_to_file="/tmp/hello.pdf",
1929
- displayed_filename="hello.pdf",
1930
- mime_type="application/pdf",
1931
- scope_or_unique_path="scope_stcj2osgbl722m22jayidx0n",
1932
- chat_id=None,
1933
- )
1934
- ```
1935
-
1936
- ### Sources
1937
-
1938
- #### `unique_sdk.utils.sources.merge_sources`
1939
-
1940
- Merges multiple search results based on their 'id', removing redundant document and info markers.
1941
-
1942
- This function groups search results by their 'id' and then concatenates their texts,
1943
- cleaning up any document or info markers in subsequent chunks beyond the first one.
1944
-
1945
- Parameters:
1946
-
1947
- - searchContext (list): A list of dictionaries, each representing a search result with 'id' and 'text' keys.
1948
-
1949
- Returns:
1950
-
1951
- - list: A list of dictionaries with merged texts for each unique 'id'.
1952
-
1953
- `searchContext` is an list of search objects that are returned by the search.
1954
-
1955
- ```python
1956
- search = unique_sdk.Search.create(
1957
- user_id=userId,
1958
- company_id=companyId,
1959
- chatId=chatId,
1960
- searchString="Who is Harry P?",
1961
- searchType="COMBINED",
1962
- scopeIds="scope_dsf...",
1963
- limit=30,
1964
- chatOnly=False,
1965
- )
1966
-
1967
- searchContext = unique_sdk.utils.token.pick_search_results_for_token_window(
1968
- search["data"], config["maxTokens"] - historyLength
1969
- )
1970
-
1971
- searchContext = unique_sdk.utils.sources.merge_sources(search)
1972
-
1973
- ```
1974
-
1975
- #### `unique_sdk.utils.sources.sort_sources`
1976
-
1977
- Sort sources by order of appearance in documents
1978
-
1979
- ```python
1980
-
1981
- search = unique_sdk.Search.create(
1982
- user_id=userId,
1983
- company_id=companyId,
1984
- chatId=chatId,
1985
- searchString="Who is Harry P?",
1986
- searchType="COMBINED",
1987
- scopeIds="scope_dsf...",
1988
- limit=30,
1989
- chatOnly=False,
1990
- )
1991
-
1992
- searchContext = unique_sdk.utils.token.pick_search_results_for_token_window(
1993
- search["data"], config["maxTokens"] - historyLength
1994
- )
1995
-
1996
- searchContext = unique_sdk.utils.sources.sort_sources(search)
1997
- ```
1998
-
1999
- #### `unique_sdk.utils.sources.post_process_sources`
2000
-
2001
- Post-processes the provided text by converting source references into superscript numerals (required
2002
- format by backend to display sources in the chat window)
2003
-
2004
- This function searches the input text for patterns that represent source references (e.g., [source1])
2005
- and replaces them with superscript tags, incrementing the number by one.
2006
-
2007
- Parameters:
2008
-
2009
- - text (str): The text to be post-processed.
2010
-
2011
- Returns:
2012
-
2013
- - str: The text with source references replaced by superscript numerals.
2014
-
2015
- Examples:
2016
-
2017
- - postprocessSources("This is a reference [source0]") will return "This is a reference <sup>1</sup>".
2018
-
2019
- ```python
2020
-
2021
- text_with_sup = post_process_sources(text)
2022
- ```
2023
-
2024
- ### Token
2025
-
2026
- #### unique_sdk.utils.token.pick_search_results_for_token_window
2027
-
2028
- Selects and returns a list of search results that fit within a specified token limit.
2029
-
2030
- This function iterates over a list of search results, each with a 'text' field, and
2031
- encodes the text using a predefined encoding scheme. It accumulates search results
2032
- until the token limit is reached or exceeded.
2033
-
2034
- Parameters:
2035
-
2036
- - searchResults (list): A list of dictionaries, each containing a 'text' key with string value.
2037
- - tokenLimit (int): The maximum number of tokens to include in the output.
2038
-
2039
- Returns:
2040
-
2041
- - list: A list of dictionaries representing the search results that fit within the token limit.
2042
-
2043
- ```python
2044
- search = unique_sdk.Search.create(
2045
- user_id=userId,
2046
- company_id=companyId,
2047
- chatId=chatId,
2048
- searchString="Who is Harry P?",
2049
- searchType="COMBINED",
2050
- scopeIds="scope_dsf...",
2051
- limit=30,
2052
- chatOnly=False,
2053
- )
2054
-
2055
- searchContext = unique_sdk.utils.token.pick_search_results_for_token_window(
2056
- search["data"], config["maxTokens"] - historyLength
2057
- )
2058
- ```
2059
-
2060
- #### unique_sdk.utils.token.count_tokens
2061
-
2062
- Counts the number of tokens in the provided text.
2063
-
2064
- This function encodes the input text using a predefined encoding scheme
2065
- and returns the number of tokens in the encoded text.
2066
-
2067
- Parameters:
2068
-
2069
- - text (str): The text to count tokens for.
2070
-
2071
- Returns:
2072
-
2073
- - int: The number of tokens in the text.
2074
-
2075
- ```python
2076
- hello = "hello you!"
2077
- searchContext = unique_sdk.utils.token.count_tokens(hello)
2078
- ```
2079
-
2080
- ### Chat In Space
2081
-
2082
- #### `unique_sdk.utils.chat_in_space.send_message_and_wait_for_completion`
2083
-
2084
- The following script enables you to chat within a space using an assistant. You must provide an `assistantId` (e.g., `assistant_hjcdga64bkcjnhu4`) and the message `text` to initiate the conversation. You can send the message in an existing chat by specifying a `chat_id`, or omit the `chat_id` to automatically create a new chat session. Check the optional parameteres list for more configs.
2085
-
2086
- The script sends a prompt asynchronously and continuously polls for completion, which is determined when the `stoppedStreamingAt` field of the message becomes non-null.
2087
-
2088
- **Optional parameters:**
2089
- - `tool_choices`: A list of tool names to be used for the message (e.g., `["WebSearch"]`). If not provided, no tools will be used. The tools supported right now are `WebSearch` and `InternalSearch`.
2090
- - `scope_rules`: A filter to specify the scope rules for the message, allowing you to restrict the context or data sources available to the assistant. The filter is written in UniqueQL language. Find out more about the language in the UniqueQL section.
2091
- - `chat_id`: The ID of the chat where the message should be sent. If omitted, a new chat will be created.
2092
- - `poll_interval`: The number of seconds to wait between polling attempts (default: `1` second).
2093
- - `max_wait`: The maximum number of seconds to wait for the message to complete (default: `60` seconds).
2094
- - `stop_condition`: Defines when to expect a response back, when the assistant stop streaming or when it completes the message. (default: "stoppedStreamingAt")
2095
-
2096
- The script ensures you can flexibly interact with spaces in new or ongoing chats, with fine-grained control over tools, context, and polling behavior.
2097
-
2098
- ```python
2099
- from unique_sdk.utils.chat_in_space import send_message_and_wait_for_completion
2100
- latest_message = await send_message_and_wait_for_completion(
2101
- user_id=user_id,
2102
- company_id=company_id,
2103
- assistant_id=assistant_id,
2104
- text="Tell me a short story.",
2105
- chat_id=chat_id, # Optional - if no chat id is specified, a new chat will be created
2106
- tool_choices=["WebSearch"],
2107
- scope_rules={
2108
- "or": [
2109
- {
2110
- "operator": "in",
2111
- "path": [
2112
- "contentId"
2113
- ],
2114
- "value": [
2115
- "cont_u888z7cazxxm4lugfdjq7pks"
2116
- ]
2117
- },
2118
- {
2119
- "operator": "contains",
2120
- "path": [
2121
- "folderIdPath"
2122
- ],
2123
- "value": "uniquepathid://scope_btfo28b3eeelwh5obwgea71bl/scope_fn56ta67knd6w4medgq3028fx"
2124
- }
2125
- ]
2126
- },
2127
- stop_condition = "completedAt" # If not specified, stoppedStreamingAt will be set by default
2128
- )
2129
- ```
2130
-
2131
- #### `unique_sdk.utils.chat_in_space.chat_against_file`
2132
-
2133
- The following script enables you to chat against a file.
2134
-
2135
- You must provide the following parameters:
2136
- - `assistantId`: The assistant to be used for the chat.
2137
- - `path_to_file`: The local path of the file to be uploaded.
2138
- - `displayed_filename`: The name of the file to be displayed.
2139
- - `mime_type`: The mime type of the ifle to be uploaded.
2140
- - `text`: The text to be sent to the chat for chatting against the file.
2141
-
2142
- The script creates a chat and uploads the file to it. It then keeps polling the `ingestionState` field of the message, waiting for it to reach `FINISHED`, signaling the upload is complete. Once the file uploads successfully, the script sends the text, continues polling for completion, and finally retrieves the response message. The function deletes the chat at the end unless the `should_delete_chat` is set to false.
2143
-
2144
- **Optional parameters:**
2145
- - `poll_interval`: The number of seconds to wait between polling attempts (default: `1` second).
2146
- - `max_wait`: The maximum number of seconds to wait for the message to complete (default: `60` seconds).
2147
- - `should_delete_chat`: Setting this flag determines whether the chat should be deleted at the end or not. Default is True.
2148
-
2149
- Example of chatting against a PDF. (The usage can be extended to any supported file type)
2150
-
2151
- ```python
2152
- latest_message = await unique_sdk.utils.chat_in_space.chat_against_file(
2153
- user_id=user_id,
2154
- company_id=company_id,
2155
- assistant_id="assistant_hjcdga64bkcjnhu4",
2156
- path_to_file="/files/hello.pdf",
2157
- displayed_filename="hello.pdf",
2158
- mime_type="application/pdf",
2159
- text="Give me a bullet point summary of the file.",
2160
- )
2161
- ```
2162
-
2163
- #### `unique_sdk.utils.chat_in_space.wait_for_ingestion_completion`
2164
-
2165
- The following script enables you to wait for the ingestion of a file. This should be used carefully as it continuously polls for the status. In case of bigger files, adjust the `poll_interval` and `max_waits`.
2166
-
2167
- You must provide the following parameter:
2168
- - `content_id`: The id of the content to check.
2169
-
2170
- The script polls until the content ingestion is finished or the maximum wait time is reached and throws in case ingestion fails. The function assumes that the content exists.
2171
-
2172
- **Optional parameters:**
2173
- - `chat_id`: In case the content is uploaded to a chat, the `chat_id` must be provided.
2174
- - `poll_interval`: The number of seconds to wait between polling attempts (default: `1` second).
2175
- - `max_wait`: The maximum number of seconds to wait for the message to complete (default: `60` seconds).
2176
-
2177
- Example of waiting for the ingestion of a file in the Knowledge Base.
2178
-
2179
- ```python
2180
- await unique_sdk.utils.chat_in_space.wait_for_ingestion_completion(
2181
- user_id=user_id,
2182
- company_id=company_id,
2183
- content_id="cont_ddlezvag4kzxudfr24lrjc5mx",
2184
- )
2185
- ```
2186
-
2187
- ## Error Handling
2188
-
2189
- ## Examples
2190
-
2191
- An example Flask app demonstrating the usage of each API resource and how to interact with Webhooks is available in our repository at `/examples/custom-assistant`.
2192
-
2193
- ## Credits
2194
-
2195
- This is a _fork_ / inspired-by the fantastic Stripe Python SDK (https://github.com/stripe/stripe-python).
2196
-
2197
- # Changelog
2198
-
2199
- All notable changes to this project will be documented in this file.
2200
-
2201
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
2202
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
2203
-
2204
- ## [0.10.51] - 2025-11-21
2205
- - Add function to get a space.
2206
-
2207
- ## [0.10.50] - 2025-11-21
2208
- - Allow updating the configuration of a user and group.
2209
-
2210
- ## [0.10.49] - 2025-11-21
2211
- - Add get folder by scope id function
2212
-
2213
- ## [0.10.48] - 2025-11-20
2214
- - Update Agentic Table LogDetail and LogEntry types.
2215
-
2216
- ## [0.10.47] - 2025-11-19
2217
- - Add expired/s at fields on content search result.
2218
-
2219
- ## [0.10.46] - 2025-11-18
2220
- - chat_against_file function allows now a should_delete_chat flag.
2221
-
2222
- ## [0.10.45] - 2025-11-18
2223
- - Create group and manage users functions.
2224
-
2225
- ## [0.10.44] - 2025-11-18
2226
- - add function to get all messages in a chat.
2227
-
2228
- ## [0.10.43] - 2025-11-14
2229
- - Add get, delete and update groups functions.
2230
-
2231
- ## [0.10.42] - 2025-11-14
2232
- - Add get_users function.
2233
-
2234
- ## [0.10.41] - 2025-11-13
2235
- - Add create_message and get_latest_message.
2236
-
2237
- ## [0.10.40] - 2025-11-10
2238
- - Don't send description if not defined.
2239
-
2240
- ## [0.10.39] - 2025-11-07
2241
- - Add function to get llm models
2242
-
2243
- ## [0.10.38] - 2025-11-06
2244
- - Add description property to Reference and Content.
2245
-
2246
- ## [0.10.37] - 2025-11-04
2247
- - Introduce local integration tests for Content API Resource
2248
-
2249
- ## [0.10.36] - 2025-11-04
2250
- - Introduce local integration tests for Folder API Resource
2251
-
2252
- ## [0.10.35] - 2025-11-04
2253
- - Inmprove folder get infos types.
2254
-
2255
- ## [0.10.34] - 2025-10-29
2256
- - Add documentation for agentic table.
2257
-
2258
- ## [0.10.33] - 2025-10-27
2259
- - Improve messagelog and message execution types.
2260
-
2261
- ## [0.10.32] - 2025-10-14
2262
- - Add function to stream to chat frontend.
2263
-
2264
- ## [0.10.31] - 2025-10-13
2265
- - Add readme for message log and execution.
2266
-
2267
- ## [0.10.30] - 2025-10-07
2268
- - Improve types for content get infos.
2269
-
2270
- ## [0.10.29] - 2025-10-06
2271
- - Switch default model used from `GPT-3.5-turbo (0125)` to `GPT-4o (1120)`
2272
-
2273
- ## [0.10.28] - 2025-10-03
2274
- - Use non blocking versions of `Space.get_latest_message` and `Message.retrieve` in `send_message_and_wait_for_completion`.
2275
-
2276
- ## [0.10.27] - 2025-09-24
2277
- - Improve readme to use Unique AI.
2278
-
2279
- ## [0.10.26] - 2025-09-22
2280
- - Improve typing.
2281
-
2282
- ## [0.10.25] - 2025-09-18
2283
- - Add support for udpate and delete files by file or folder path.
2284
-
2285
- ## [0.10.24] - 2025-09-17
2286
- - Add function to update a folder.
2287
-
2288
- ## [0.10.23] - 2025-09-12
2289
- - Revert to using default reasoning effort.
2290
-
2291
- ## [0.10.22] - 2025-09-12
2292
- - Add support for metadata update of a file.
2293
-
2294
- ## [0.10.21] - 2025-09-04
2295
- - Update Chat Completions API types and add support for reasoning effort.
2296
-
2297
- ## [0.10.20] - 2025-09-04
2298
- - Update Responses API types
2299
-
2300
- ## [0.10.19] - 2025-09-02
2301
- - Improve `send_message_and_wait_for_completion`:
2302
- - Add option to select stop_condition `["stoppedStreamingAt", "completedAt"]`.
2303
- - Load `debugInfo` from `last_user_message` for better developer experience.
2304
-
2305
- ## [0.10.18] - 2025-09-02
2306
- - Temporarily remove support for update and delete files by filePath.
2307
-
2308
- ## [0.10.17] - 2025-09-01
2309
- - Add function to update a file
2310
-
2311
- ## [0.10.16] - 2025-08-31
2312
- - Add function to delete a content.
2313
-
2314
- ## [0.10.15] - 2025-08-28
2315
- - Add default values for message log types
2316
-
2317
- ## [0.10.14] - 2025-08-28
2318
- - Add function to delete folders and files recursively
2319
-
2320
- ## [0.10.13] - 2025-08-24
2321
- - Add functions to create, get and update a message eecution and create and update a message log.
2322
-
2323
- ## [0.10.12] - 2025-08-24
2324
- - Switch to using Content get info deprecated endpoint to make sure we support older release versions.
2325
-
2326
- ## [0.10.11] - 2025-08-24
2327
- - Enforce usage of ruff using pipeline
2328
-
2329
- ## [0.10.10] - 2025-08-18
2330
- - Fix wrong name of references in `Space.Message`.
2331
- - Fix wrong name of assessment in `Space.Message`.
2332
- - Remove default values for `text`, `originalText` and `debugInfo` in `Space.Message` as these don't have an effect.
2333
-
2334
- ## [0.10.9] - 2025-08-15
2335
- - Add script to wait for content ingestion finished.
2336
-
2337
- ## [0.10.8] - 2025-08-13
2338
- - Add support for Agentic Table.
2339
-
2340
- ## [0.10.7] - 2025-08-13
2341
- - Make metadata optional when uploading a file.
2342
-
2343
- ## [0.10.6] - 2025-08-06
2344
- - Make tools optional for running an agent.
2345
-
2346
- ## [0.10.5] - 2025-08-06
2347
- - Get paginated files and folders info.
2348
-
2349
- ## [0.10.4] - 2025-08-05
2350
- - Add support for reasoning API with streaming within a chat.
2351
-
2352
- ## [0.10.3] - 2025-08-05
2353
- - Expose scoreThreshold param for search.
2354
-
2355
- ## [0.10.2] - 2025-08-05
2356
- - Add script to chat against file.
2357
-
2358
- ## [0.10.1] - 2025-08-05
2359
- - Allow deletion of a space chat.
2360
-
2361
- ## [0.10.0] - 2025-08-04
2362
- - Add MCP support
2363
-
2364
- ## [0.9.42] - 2025-07-31
2365
- - Fix wrong chat in space example.
2366
-
2367
- ## [0.9.41] - 2025-07-31
2368
- - Fix double-slash error in open ai proxy script.
2369
-
2370
- ## [0.9.40] - 2025-07-22
2371
- - Fixed bug where get requests send body with the request. This is not allowed by WAF policies.
2372
-
2373
- ## [0.9.39] - 2025-07-18
2374
- - Add script to chat in a space.
2375
-
2376
- ## [0.9.38] - 2025-07-18
2377
- - [Experimental] Add support for Unique OpenAI proxy. You can now use the OpenAI SDK directly through Unique. Checkout how to do this and a few examples here: `tutorials/unique_basics/sdk_examples/openai_scripts.py`.
2378
-
2379
- ## [0.9.37] - 2025-07-10
2380
- - Add `sheetName` property to the `MagicTableSheetIngestParams` object used by function that ingests magic table sheets.
2381
-
2382
- ## [0.9.36] - 2025-06-23
2383
- - Allow passing a user id when creating chat completions. This is optional and it does not impact the current behaviour.
2384
-
2385
- ## [0.9.35] - 2025-06-18
2386
- - Allow scope access updates (add/remove) on folder based on scope id or path.
2387
-
2388
- ## [0.9.34] - 2025-06-17
2389
- - Allow ingestion config updates on folder based on scope id or path.
2390
-
2391
- ## [0.9.33] - 2025-06-11
2392
- - Add function to get a folder by id or by path.
2393
-
2394
- ## [0.9.32] - 2025-06-11
2395
- - Add function to ingest magic table sheets.
2396
-
2397
- ## [0.9.31] - 2025-05-21
2398
- - Add function to update folder access (add or remove).
2399
-
2400
- ## [0.9.30] - 2025-05-21
2401
- - Add function to update folder ingestion config.
2402
-
2403
- ## [0.9.29] - 2025-05-20
2404
- - Add function to create folder paths if they do not exist.
2405
-
2406
- ## [0.9.28] - 2025-05-20
2407
- - Add function to search content info. This also allows filtering content info by metadata info.
2408
-
2409
- ## [0.9.27] - 2025-05-14
2410
- - Add the possibility to specify metadata when creating or updating a Content.
2411
-
2412
- ## [0.9.26] - 2025-05-13
2413
- - Add the possibility to specify ingestionConfig when creating or updating a Content.
2414
-
2415
- ## [0.9.25] - 2025-05-02
2416
- - Fixed typos in `README.md`, including incorrect `sdk.utils` imports and code example errors.
2417
-
2418
- ## [0.9.24] - 2025-04-23
2419
- - Make `chatId` property in `Search.CreateParams` optional
2420
-
2421
- ## [0.9.23] - 2025-03-25
2422
- - Define programming language classifier explicitly for python 3.11
2423
-
2424
- ## [0.9.22] - 2025-02-25
2425
- - update the retry_on_error to only `APIError` and `APIConnectionError` update the `resp["error"]` to be `resp.get("error")` to avoid key error
2426
-
2427
- ## [0.9.21] - 2025-02-21
2428
- - Add title parameter and change labels in `MessageAssessment`
2429
-
2430
- ## [0.9.20] - 2025-02-01
2431
- - Add url parameter to `MessageAssessment.create_async` and `MessageAssessment.modify_async`
2432
-
2433
- ## [0.9.19] - 2025-01-31
2434
- - Add `MessageAssessment` resource
2435
-
2436
- ## [0.9.18] - 2025-01-22
2437
- - Removed `Invalid response body from API` from `retry_dict` as it's our own artificail error.
2438
-
2439
- ## [0.9.17] - 2025-01-03
2440
- - BREAKING CHANGE!! Removed unused `id` from `ShortTermMemory` create and find methods.
2441
-
2442
- ## [0.9.16] - 2024-12-19
2443
- - Corrected return type of `Search.create` and `Search.create_async` to `List[Search]`
2444
- - Retry on `Connection aborted` error
2445
-
2446
- ## [0.9.15] - 2024-12-06
2447
- - Add `Internal server error` and `You can retry your request` to the retry logic
2448
-
2449
- ## [0.9.14] - 2024-12-06
2450
- - Add `contentIds` to `Search.create` and `Search.create_async`
2451
-
2452
- ## [0.9.13] - 2024-10-23
2453
- - Add retry for `5xx` errors, add additional error message.
2454
-
2455
- ## [0.9.12] - 2024-11-21
2456
- - Include original error message in returned exceptions
2457
-
2458
- ## [0.9.11] - 2024-11-18
2459
- - Add `ingestionConfig` to `UpsertParams.Input` parameters
2460
-
2461
- ## [0.9.10] - 2024-10-23
2462
- - Remove `temperature` parameter from `Integrated.chat_stream_completion`, `Integrated.chat_stream_completion_async`, `ChatCompletion.create` and `ChatCompletion.create_async` methods. To use `temperature` parameter, set the attribute in `options` parameter instead.
2463
-
2464
- ## [0.9.9] - 2024-10-23
2465
- - Revert deletion of `Message.retrieve` method
2466
-
2467
- ## [0.9.8] - 2024-10-16
2468
- - Add `retries` for `_static_request` and `_static_request_async` in `APIResource` - When the error messages contains either `"problem proxying the request"`,
2469
- or `"Upstream service reached a hard timeout"`,
2470
- ## [0.9.7] - 2024-09-23
2471
- - Add `completedAt` to `CreateParams` of `Message`
2472
-
2473
- ## [0.9.6] - 2024-09-03
2474
- - Added `metaDataFilter` to `Search` parameters.
2475
-
2476
- ## [0.9.5] - 2024-08-07
2477
- - Add `completedAt` to `ModifyParams`
2478
-
2479
- ## [0.9.4] - 2024-07-31
2480
- - Add `close` and `close_async` to `http_client`
2481
- - Make `httpx` the default client for async requests
2482
-
2483
- ## [0.9.3] - 2024-07-31
2484
- - `Search.create`, `Message`, `ChatCompletion` parameters that were marked `NotRequired` are now also `Optional`
2485
-
2486
- ## [0.9.2] - 2024-07-30
2487
- - Bug fix in `Search.create`: langugage -> language
2488
-
2489
- ## [0.9.1] - 2024-07-30
2490
- - Added parameters to `Search.create` and `Search.create_async`
2491
- - `language` for full text search
2492
- - `reranker` to reranker search results
2493
-
2494
- ## [0.9.0] - 2024-07-29
2495
- - Added the possibility to make async requests to the unique APIs using either aiohttp or httpx as client
2496
-