unique_sdk 0.10.17__tar.gz → 0.10.19__tar.gz

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.
Files changed (43) hide show
  1. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/CHANGELOG.md +8 -0
  2. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/PKG-INFO +18 -43
  3. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/README.md +9 -42
  4. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/pyproject.toml +1 -1
  5. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/api_resources/_content.py +4 -58
  6. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/utils/chat_in_space.py +15 -2
  7. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/LICENSE +0 -0
  8. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/__init__.py +0 -0
  9. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/_api_requestor.py +0 -0
  10. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/_api_resource.py +0 -0
  11. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/_api_version.py +0 -0
  12. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/_error.py +0 -0
  13. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/_http_client.py +0 -0
  14. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/_list_object.py +0 -0
  15. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/_object_classes.py +0 -0
  16. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/_request_options.py +0 -0
  17. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/_unique_object.py +0 -0
  18. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/_unique_ql.py +0 -0
  19. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/_unique_response.py +0 -0
  20. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/_util.py +0 -0
  21. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/_version.py +0 -0
  22. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/_webhook.py +0 -0
  23. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/api_resources/__init__.py +0 -0
  24. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/api_resources/_acronyms.py +0 -0
  25. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/api_resources/_agentic_table.py +0 -0
  26. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/api_resources/_chat_completion.py +0 -0
  27. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/api_resources/_embedding.py +0 -0
  28. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/api_resources/_event.py +0 -0
  29. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/api_resources/_folder.py +0 -0
  30. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/api_resources/_integrated.py +0 -0
  31. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/api_resources/_mcp.py +0 -0
  32. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/api_resources/_message.py +0 -0
  33. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/api_resources/_message_assessment.py +0 -0
  34. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/api_resources/_message_execution.py +0 -0
  35. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/api_resources/_message_log.py +0 -0
  36. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/api_resources/_search.py +0 -0
  37. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/api_resources/_search_string.py +0 -0
  38. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/api_resources/_short_term_memory.py +0 -0
  39. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/api_resources/_space.py +0 -0
  40. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/utils/chat_history.py +0 -0
  41. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/utils/file_io.py +0 -0
  42. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/utils/sources.py +0 -0
  43. {unique_sdk-0.10.17 → unique_sdk-0.10.19}/unique_sdk/utils/token.py +0 -0
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.10.19] - 2025-09-02
9
+ - Improve `send_message_and_wait_for_completion`:
10
+ - Add option to select stop_condition `["stoppedStreamingAt", "completedAt"]`.
11
+ - Load `debugInfo` from `last_user_message` for better developer experience.
12
+
13
+ ## [0.10.18] - 2025-09-02
14
+ - Temporarily remove support for update and delete files by filePath.
15
+
8
16
  ## [0.10.17] - 2025-09-01
9
17
  - Add function to update a file
10
18
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unique_sdk
3
- Version: 0.10.17
3
+ Version: 0.10.19
4
4
  Summary:
5
5
  License: MIT
6
6
  Author: Martin Fadler
@@ -556,32 +556,19 @@ Allows you to ingest a magic table sheet, each row is processed and converted in
556
556
 
557
557
  #### `unique_sdk.Content.update` (Compatible with release >.36)
558
558
 
559
- Allows you to update a file specified by its `contentId` or by its `filePath`.
559
+ Allows you to update a file specified by its `contentId`.
560
560
 
561
- - `contentId` optional if `filePath` is provided, the id of the file to be updated
562
- - `filePath` optional if `contentId` is provided, the absolute path of the file to be updated
561
+ - `contentId` the id of the file to be updated
563
562
 
564
563
  Currently, the following updates are supported:
565
564
 
566
565
  Title update:
567
566
  - `title` optional, allows updating the title of the folder
568
567
 
569
- Move the file to a different folder. this can be done by specifying either the `ownerId` or the `parentFolderPath`.
568
+ Move the file to a different folder. this can be done by specifying either the `ownerId`.
570
569
  - `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`.
571
- - `parentFolderPath` optional, allows moving the file to a different folder. Represents the path new folder for the file.
572
570
 
573
571
 
574
- Example of updating the title of a file specified by its path.
575
-
576
- ```python
577
- unique_sdk.Content.update(
578
- user_id=user_id,
579
- company_id=company_id,
580
- filePath="/Company/finance/january.xls",
581
- title="Revision Deck"
582
- )
583
- ```
584
-
585
572
  Example of moving a file specified by its content id.
586
573
 
587
574
  ```python
@@ -605,25 +592,12 @@ unique_sdk.Content.update(
605
592
  )
606
593
  ```
607
594
 
608
- Example of moving a file to a folder specified by its path.
609
-
610
- ```python
611
- unique_sdk.Content.update(
612
- user_id=user_id,
613
- company_id=company_id,
614
- contentId="cont_ok2343q5owbce80w78hudawu5",
615
- ownerId="scope_e68yz5asho7glfh7c7d041el",
616
- parentFolderPath="/Company/Revisions"
617
- )
618
- ```
619
-
620
595
  #### `unique_sdk.Content.delete` (Compatible with release >.36)
621
596
 
622
- Allows you to delete a file by its `contentId` or by its `filePath`. When deleting by `id`, if the file is part of a chat, the `chatId` also needs do be set. If both `contentId` and `filePath` are provided, `filePath` is ignored.
597
+ Allows you to delete a file by its `contentId`. If the file is part of a chat, the `chatId` also needs do be set.
623
598
 
624
- - `contentId` optional if `filePath` is provided, the id of the file to be deleted
599
+ - `contentId` the id of the file to be deleted
625
600
  - `chatId` optional, the id of the chat where the file is. Only needed if the file is part of a chat
626
- - `filePath` optional if `contentId` is provided, the absolute path of the file to be deleted
627
601
 
628
602
  Example of deleting a file from a chat.
629
603
 
@@ -636,16 +610,6 @@ unique_sdk.Content.delete(
636
610
  )
637
611
  ```
638
612
 
639
- Example of deleting a file by its path.
640
-
641
- ```python
642
- unique_sdk.Content.delete(
643
- user_id=user_id,
644
- company_id=company_id,
645
- filePath="/Company/finance/january.xls",
646
- )
647
- ```
648
-
649
613
  ### Message
650
614
 
651
615
  #### `unique_sdk.Message.list`
@@ -1502,11 +1466,13 @@ The script sends a prompt asynchronously and continuously polls for completion,
1502
1466
  - `chat_id`: The ID of the chat where the message should be sent. If omitted, a new chat will be created.
1503
1467
  - `poll_interval`: The number of seconds to wait between polling attempts (default: `1` second).
1504
1468
  - `max_wait`: The maximum number of seconds to wait for the message to complete (default: `60` seconds).
1469
+ - `stop_condition`: Defines when to expect a response back, when the assistant stop streaming or when it completes the message. (default: "stoppedStreamingAt")
1505
1470
 
1506
1471
  The script ensures you can flexibly interact with spaces in new or ongoing chats, with fine-grained control over tools, context, and polling behavior.
1507
1472
 
1508
1473
  ```python
1509
- latest_message = await unique_sdk.utils.chat_in_space.send_message_and_wait_for_completion(
1474
+ from unique_sdk.utils.chat_in_space import send_message_and_wait_for_completion
1475
+ latest_message = await send_message_and_wait_for_completion(
1510
1476
  user_id=user_id,
1511
1477
  company_id=company_id,
1512
1478
  assistant_id=assistant_id,
@@ -1533,6 +1499,7 @@ latest_message = await unique_sdk.utils.chat_in_space.send_message_and_wait_for_
1533
1499
  }
1534
1500
  ]
1535
1501
  },
1502
+ stop_condition = "completedAt" # If not specified, stoppedStreamingAt will be set by default
1536
1503
  )
1537
1504
  ```
1538
1505
 
@@ -1608,6 +1575,14 @@ All notable changes to this project will be documented in this file.
1608
1575
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
1609
1576
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
1610
1577
 
1578
+ ## [0.10.19] - 2025-09-02
1579
+ - Improve `send_message_and_wait_for_completion`:
1580
+ - Add option to select stop_condition `["stoppedStreamingAt", "completedAt"]`.
1581
+ - Load `debugInfo` from `last_user_message` for better developer experience.
1582
+
1583
+ ## [0.10.18] - 2025-09-02
1584
+ - Temporarily remove support for update and delete files by filePath.
1585
+
1611
1586
  ## [0.10.17] - 2025-09-01
1612
1587
  - Add function to update a file
1613
1588
 
@@ -540,32 +540,19 @@ Allows you to ingest a magic table sheet, each row is processed and converted in
540
540
 
541
541
  #### `unique_sdk.Content.update` (Compatible with release >.36)
542
542
 
543
- Allows you to update a file specified by its `contentId` or by its `filePath`.
543
+ Allows you to update a file specified by its `contentId`.
544
544
 
545
- - `contentId` optional if `filePath` is provided, the id of the file to be updated
546
- - `filePath` optional if `contentId` is provided, the absolute path of the file to be updated
545
+ - `contentId` the id of the file to be updated
547
546
 
548
547
  Currently, the following updates are supported:
549
548
 
550
549
  Title update:
551
550
  - `title` optional, allows updating the title of the folder
552
551
 
553
- Move the file to a different folder. this can be done by specifying either the `ownerId` or the `parentFolderPath`.
552
+ Move the file to a different folder. this can be done by specifying either the `ownerId`.
554
553
  - `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`.
555
- - `parentFolderPath` optional, allows moving the file to a different folder. Represents the path new folder for the file.
556
554
 
557
555
 
558
- Example of updating the title of a file specified by its path.
559
-
560
- ```python
561
- unique_sdk.Content.update(
562
- user_id=user_id,
563
- company_id=company_id,
564
- filePath="/Company/finance/january.xls",
565
- title="Revision Deck"
566
- )
567
- ```
568
-
569
556
  Example of moving a file specified by its content id.
570
557
 
571
558
  ```python
@@ -589,25 +576,12 @@ unique_sdk.Content.update(
589
576
  )
590
577
  ```
591
578
 
592
- Example of moving a file to a folder specified by its path.
593
-
594
- ```python
595
- unique_sdk.Content.update(
596
- user_id=user_id,
597
- company_id=company_id,
598
- contentId="cont_ok2343q5owbce80w78hudawu5",
599
- ownerId="scope_e68yz5asho7glfh7c7d041el",
600
- parentFolderPath="/Company/Revisions"
601
- )
602
- ```
603
-
604
579
  #### `unique_sdk.Content.delete` (Compatible with release >.36)
605
580
 
606
- Allows you to delete a file by its `contentId` or by its `filePath`. When deleting by `id`, if the file is part of a chat, the `chatId` also needs do be set. If both `contentId` and `filePath` are provided, `filePath` is ignored.
581
+ Allows you to delete a file by its `contentId`. If the file is part of a chat, the `chatId` also needs do be set.
607
582
 
608
- - `contentId` optional if `filePath` is provided, the id of the file to be deleted
583
+ - `contentId` the id of the file to be deleted
609
584
  - `chatId` optional, the id of the chat where the file is. Only needed if the file is part of a chat
610
- - `filePath` optional if `contentId` is provided, the absolute path of the file to be deleted
611
585
 
612
586
  Example of deleting a file from a chat.
613
587
 
@@ -620,16 +594,6 @@ unique_sdk.Content.delete(
620
594
  )
621
595
  ```
622
596
 
623
- Example of deleting a file by its path.
624
-
625
- ```python
626
- unique_sdk.Content.delete(
627
- user_id=user_id,
628
- company_id=company_id,
629
- filePath="/Company/finance/january.xls",
630
- )
631
- ```
632
-
633
597
  ### Message
634
598
 
635
599
  #### `unique_sdk.Message.list`
@@ -1486,11 +1450,13 @@ The script sends a prompt asynchronously and continuously polls for completion,
1486
1450
  - `chat_id`: The ID of the chat where the message should be sent. If omitted, a new chat will be created.
1487
1451
  - `poll_interval`: The number of seconds to wait between polling attempts (default: `1` second).
1488
1452
  - `max_wait`: The maximum number of seconds to wait for the message to complete (default: `60` seconds).
1453
+ - `stop_condition`: Defines when to expect a response back, when the assistant stop streaming or when it completes the message. (default: "stoppedStreamingAt")
1489
1454
 
1490
1455
  The script ensures you can flexibly interact with spaces in new or ongoing chats, with fine-grained control over tools, context, and polling behavior.
1491
1456
 
1492
1457
  ```python
1493
- latest_message = await unique_sdk.utils.chat_in_space.send_message_and_wait_for_completion(
1458
+ from unique_sdk.utils.chat_in_space import send_message_and_wait_for_completion
1459
+ latest_message = await send_message_and_wait_for_completion(
1494
1460
  user_id=user_id,
1495
1461
  company_id=company_id,
1496
1462
  assistant_id=assistant_id,
@@ -1517,6 +1483,7 @@ latest_message = await unique_sdk.utils.chat_in_space.send_message_and_wait_for_
1517
1483
  }
1518
1484
  ]
1519
1485
  },
1486
+ stop_condition = "completedAt" # If not specified, stoppedStreamingAt will be set by default
1520
1487
  )
1521
1488
  ```
1522
1489
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "unique_sdk"
3
- version = "0.10.17"
3
+ version = "0.10.19"
4
4
  description = ""
5
5
  authors = [
6
6
  "Martin Fadler <martin.fadler@unique.ch>",
@@ -12,7 +12,6 @@ from typing import (
12
12
 
13
13
  from typing_extensions import NotRequired, Unpack
14
14
 
15
- import unique_sdk
16
15
  from unique_sdk._api_resource import APIResource
17
16
  from unique_sdk._request_options import RequestOptions
18
17
 
@@ -130,9 +129,7 @@ class Content(APIResource["Content"]):
130
129
 
131
130
  class UpdateParams(RequestOptions):
132
131
  contentId: str | None = None
133
- filePath: str | None = None
134
132
  ownerId: str | None = None
135
- parentFolderPath: str | None = None
136
133
  title: str | None = None
137
134
 
138
135
  class Chunk(TypedDict):
@@ -168,7 +165,6 @@ class Content(APIResource["Content"]):
168
165
 
169
166
  class DeleteParams(RequestOptions):
170
167
  contentId: NotRequired[str]
171
- filePath: NotRequired[str]
172
168
  chatId: NotRequired[str]
173
169
 
174
170
  class DeleteResponse(TypedDict):
@@ -406,28 +402,11 @@ class Content(APIResource["Content"]):
406
402
  company_id: str,
407
403
  **params: Unpack["Content.UpdateParams"],
408
404
  ) -> "Content.ContentInfo":
409
- content_id = cls.resolve_content_id_from_file_path(
410
- user_id,
411
- company_id,
412
- params.get("contentId"),
413
- params.get("filePath"),
414
- )
415
- owner_id = unique_sdk.Folder.resolve_scope_id_from_folder_path(
416
- user_id,
417
- company_id,
418
- params.get("ownerId"),
419
- params.get("parentFolderPath"),
420
- )
421
- params.pop("contentId", None)
422
- params.pop("filePath", None)
423
- params.pop("parentFolderPath", None)
424
- params["ownerId"] = owner_id
425
-
426
405
  return cast(
427
406
  "Content.ContentInfo",
428
407
  cls._static_request(
429
408
  "patch",
430
- f"/content/{content_id}",
409
+ f"/content/{params.get('contentId')}",
431
410
  user_id,
432
411
  company_id,
433
412
  params=params,
@@ -441,28 +420,11 @@ class Content(APIResource["Content"]):
441
420
  company_id: str,
442
421
  **params: Unpack["Content.UpdateParams"],
443
422
  ) -> "Content.ContentInfo":
444
- content_id = cls.resolve_content_id_from_file_path(
445
- user_id,
446
- company_id,
447
- params.get("contentId"),
448
- params.get("filePath"),
449
- )
450
- owner_id = unique_sdk.Folder.resolve_scope_id_from_folder_path(
451
- user_id,
452
- company_id,
453
- params.get("ownerId"),
454
- params.get("parentFolderPath"),
455
- )
456
- params.pop("contentId", None)
457
- params.pop("filePath", None)
458
- params.pop("parentFolderPath", None)
459
- params["ownerId"] = owner_id
460
-
461
423
  return cast(
462
424
  "Content.ContentInfo",
463
425
  await cls._static_request_async(
464
426
  "patch",
465
- f"/content/{content_id}",
427
+ f"/content/{params.get('contentId')}",
466
428
  user_id,
467
429
  company_id,
468
430
  params=params,
@@ -479,20 +441,12 @@ class Content(APIResource["Content"]):
479
441
  """
480
442
  Deletes a content by its id or file path.
481
443
  """
482
- content_id = cls.resolve_content_id_from_file_path(
483
- user_id,
484
- company_id,
485
- params.get("contentId"),
486
- params.get("filePath"),
487
- )
488
- params.pop("contentId", None)
489
- params.pop("filePath", None)
490
444
 
491
445
  return cast(
492
446
  "Content.DeleteResponse",
493
447
  cls._static_request(
494
448
  "delete",
495
- f"/content/{content_id}",
449
+ f"/content/{params.get('contentId')}",
496
450
  user_id,
497
451
  company_id,
498
452
  params=params,
@@ -509,20 +463,12 @@ class Content(APIResource["Content"]):
509
463
  """
510
464
  Async deletes a content by its id or file path.
511
465
  """
512
- content_id = cls.resolve_content_id_from_file_path(
513
- user_id,
514
- company_id,
515
- params.get("contentId"),
516
- params.get("filePath"),
517
- )
518
- params.pop("contentId", None)
519
- params.pop("filePath", None)
520
466
 
521
467
  return cast(
522
468
  "Content.DeleteResponse",
523
469
  await cls._static_request_async(
524
470
  "delete",
525
- f"/content/{content_id}",
471
+ f"/content/{params.get('contentId')}",
526
472
  user_id,
527
473
  company_id,
528
474
  params=params,
@@ -1,7 +1,8 @@
1
1
  import asyncio
2
- from typing import List
2
+ from typing import List, Literal
3
3
 
4
4
  from unique_sdk.api_resources._content import Content
5
+ from unique_sdk.api_resources._message import Message
5
6
  from unique_sdk.api_resources._space import Space
6
7
  from unique_sdk.utils.file_io import upload_file
7
8
 
@@ -16,6 +17,7 @@ async def send_message_and_wait_for_completion(
16
17
  chat_id: str = None,
17
18
  poll_interval: float = 1.0,
18
19
  max_wait: float = 60.0,
20
+ stop_condition: Literal["stoppedStreamingAt", "completedAt"] = "stoppedStreamingAt",
19
21
  ) -> "Space.Message":
20
22
  """
21
23
  Sends a prompt asynchronously and polls for completion. (until stoppedStreamingAt is not None)
@@ -27,6 +29,7 @@ async def send_message_and_wait_for_completion(
27
29
  text: The prompt text.
28
30
  poll_interval: Seconds between polls.
29
31
  max_wait: Maximum seconds to wait for completion.
32
+ stop_condition: Defines when to expect a response back, when the assistant stop streaming or when it completes the message. (default: "stoppedStreamingAt")
30
33
  **kwargs: Additional parameters for the prompt.
31
34
 
32
35
  Returns:
@@ -42,11 +45,21 @@ async def send_message_and_wait_for_completion(
42
45
  scopeRules=scope_rules,
43
46
  )
44
47
  chat_id = response.get("chatId")
48
+ message_id = response.get("id")
45
49
 
46
50
  max_attempts = int(max_wait // poll_interval)
47
51
  for _ in range(max_attempts):
48
52
  answer = Space.get_latest_message(user_id, company_id, chat_id)
49
- if answer.get("stoppedStreamingAt") is not None:
53
+ if answer.get(stop_condition) is not None:
54
+ try:
55
+ user_message = Message.retrieve(
56
+ user_id, company_id, message_id, chatId=chat_id
57
+ )
58
+ debug_info = user_message.get("debugInfo")
59
+ answer["debugInfo"] = debug_info
60
+ except Exception as e:
61
+ print(f"Failed to load debug info from user message: {e}")
62
+
50
63
  return answer
51
64
  await asyncio.sleep(poll_interval)
52
65
 
File without changes