Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions HISTORY.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ Changelog
==========


14.7.4 (2026-09-14)
-------------------

* Initial release for DSS 14.7.4

14.7.3 (2026-08-03)
-------------------

Expand Down
8 changes: 7 additions & 1 deletion dataikuapi/dss/cobuild.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ def answer_confirmation(self, choice, options=None):
self._messages.append(response)
return response

def answer_question(self, answers=None, rejected=False, used_custom_answer=False):
def answer_question(self, answers=None, rejected=False, used_custom_answer=False, selected_objects=None):
"""
Answer a pending question request and wait for the assistant's next response.

Expand All @@ -448,6 +448,9 @@ def answer_question(self, answers=None, rejected=False, used_custom_answer=False
``rejected=True``. Defaults to ``[]``.
:param bool rejected: whether to decline answering the question
:param bool used_custom_answer: whether one of the answers came from the custom free-text input
:param selected_objects: object selection the assistant should focus on. It is reused for
subsequent messages and question answers, unless overwritten
:type selected_objects: list[:class:`.DSSDataset`, :class:`.DSSRecipe`, :class:`.DSSLabelingTask`, :class:`.DSSManagedFolder`, :class:`.DSSSavedModel`, :class:`.DSSKnowledgeBank`, :class:`.DSSModelEvaluationStore` or :class:`.DSSStreamingEndpoint`]

:returns: the assistant's response after the question answer
:rtype: :class:`CobuildAssistantResponse`
Expand All @@ -458,6 +461,8 @@ def answer_question(self, answers=None, rejected=False, used_custom_answer=False
raise ValueError("answers must be a list of strings")
if self._pending_question_id is None:
raise ValueError("No pending question request. Call send_message first and check is_question_request.")
if selected_objects is not None:
self._selected_objects = _DSS_objects_to_selected(self.project_key, selected_objects)

question_id = self._pending_question_id
self._pending_question_id = None
Expand All @@ -472,6 +477,7 @@ def answer_question(self, answers=None, rejected=False, used_custom_answer=False
"rejected": rejected,
"answers": answers,
"usedCustomAnswer": used_custom_answer,
"selectedObjects": self._selected_objects or [],
},
)
response = CobuildAssistantResponse(raw)
Expand Down
12 changes: 8 additions & 4 deletions dataikuapi/dss/llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -966,14 +966,14 @@ def _read(self):
"""Reads the raw source and yields events. Reassembles events
that may span multiple HTTP chunks"""
#logging.debug("SSEClient._read")
data = b''
data = bytearray()
for chunk in self.raw_source:
#logging.info("SSEClient._read: got chunk (len=%s): %s" % (len(chunk), chunk))
for line in chunk.splitlines(True):
data += line
data.extend(line)
if data.endswith(b'\r\r') or data.endswith(b'\n\n') or data.endswith(b'\r\n\r\n'):
yield data
data = b''
data = bytearray()
#logging.info("SSEClient._read: no more chunk")
if data:
yield data
Expand All @@ -983,6 +983,7 @@ def iterevents(self):
#logging.info("SSEClient._iterevents: got event")
evt = _SSEEvent()

data_lines = []
for line in event_chunk.splitlines():
line = line.decode("utf8")

Expand All @@ -999,10 +1000,13 @@ def iterevents(self):
value = ''

if field == 'data':
evt.__dict__[field] += value + '\n'
data_lines.append(value)
else:
evt.__dict__[field] = value

if data_lines:
evt.data = '\n'.join(data_lines) + '\n'

if evt.event is not None:
#logging.info("Yielding event: %s" % evt.__dict__)
yield evt
Expand Down
20 changes: 17 additions & 3 deletions dataikuapi/dssclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -1550,7 +1550,8 @@ class PermissionsPropagationPolicy(Enum):
READ_ONLY = "READ_ONLY"
ALL = "ALL"

def create_project_from_bundle_local_archive(self, archive_path, project_folder=None, permissions_propagation_policy=PermissionsPropagationPolicy.NONE):
def create_project_from_bundle_local_archive(self, archive_path, project_folder=None, permissions_propagation_policy=PermissionsPropagationPolicy.NONE,
fail_on_missing_users_or_groups=True):
"""
Create a project from a bundle archive.
Warning: this method can only be used on an automation node.
Expand All @@ -1560,27 +1561,40 @@ def create_project_from_bundle_local_archive(self, archive_path, project_folder=
:type project_folder: A :class:`dataikuapi.dss.projectfolder.DSSProjectFolder`
:param permissions_propagation_policy: propagate the permissions that were set in the design node to the new project on the automation node (default: False)
:type permissions_propagation_policy: A :class:`PermissionsPropagationPolicy`
:param fail_on_missing_users_or_groups: fail the project creation when a propagated user or group is missing on the automation node (default: True)
:type fail_on_missing_users_or_groups: bool
"""
if isinstance(permissions_propagation_policy, DSSClient.PermissionsPropagationPolicy):
permissions_propagation_policy = permissions_propagation_policy.value
params = {
"archivePath": osp.abspath(archive_path),
"permissionsPropagationPolicy": permissions_propagation_policy,
"failOnMissingUsersOrGroups": fail_on_missing_users_or_groups,
}
if project_folder is not None:
params["projectFolderId"] = project_folder.project_folder_id
return self._perform_json("POST", "/projectsFromBundle/fromArchive", params=params)

def create_project_from_bundle_archive(self, fp, project_folder=None):
def create_project_from_bundle_archive(self, fp, project_folder=None, permissions_propagation_policy=PermissionsPropagationPolicy.NONE,
fail_on_missing_users_or_groups=True):
"""
Create a project from a bundle archive (as a file object)
Warning: this method can only be used on an automation node.

:param string fp: A file-like object pointing to a bundle archive zip
:param project_folder: the project folder in which the project will be created or None for root project folder
:type project_folder: A :class:`dataikuapi.dss.projectfolder.DSSProjectFolder`
:param permissions_propagation_policy: propagate the permissions that were set in the design node to the new project on the automation node (default: False)
:type permissions_propagation_policy: A :class:`PermissionsPropagationPolicy`
:param fail_on_missing_users_or_groups: fail the project creation when a propagated user or group is missing on the automation node (default: True)
:type fail_on_missing_users_or_groups: bool
"""
params = {}
if isinstance(permissions_propagation_policy, DSSClient.PermissionsPropagationPolicy):
permissions_propagation_policy = permissions_propagation_policy.value
params = {
"permissionsPropagationPolicy": permissions_propagation_policy,
"failOnMissingUsersOrGroups": fail_on_missing_users_or_groups,
}
if project_folder is not None:
params['projectFolderId'] = project_folder.project_folder_id
files = {'file': fp }
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from setuptools import setup

VERSION = "14.7.3"
VERSION = "14.7.4"

long_description = (open('README').read() + '\n\n' +
open('HISTORY.txt').read())
Expand Down