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
4 changes: 4 additions & 0 deletions HISTORY.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
Changelog
==========

15.0.0 (2026-08-14)
-------------------

* Initial release for DSS 15.0.0

14.7.3 (2026-08-03)
-------------------
Expand Down
55 changes: 55 additions & 0 deletions dataikuapi/dss/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import warnings
import logging
from datetime import datetime

from .utils import DSSInfoMessages
from ..utils import _timestamp_ms_to_zoned_datetime

logger = logging.getLogger("dataikuapi.dss.admin")
Expand Down Expand Up @@ -2208,6 +2210,7 @@ def add_container_runtime_addition(self, container_runtime_addition):
* SYSTEM_LEVEL_CUDA_122_CUDNN_897
* CUDA_SUPPORT_FOR_TORCH2_WITH_PYPI_NVIDIA_PACKAGES
* BASIC_GPU_ENABLING
* HUGGING_FACE_LOCAL_CPU
* PYTHON36_SUPPORT
* PYTHON37_SUPPORT
* PYTHON38_SUPPORT
Expand Down Expand Up @@ -3305,6 +3308,58 @@ def build(self, disable_docker_cache=False):
params={"withNoCache": disable_docker_cache})
return DSSFuture(self.client, future_response.get('jobId', None), future_response)

def get_export_stream(self):
"""
Export the template as a zip archive.

:returns: the exported archive as a stream
:rtype: file-like object
"""
return self.client._perform_raw(
"GET", "/admin/code-studios/%s/export" % (self.template_id)
).raw

def export_to_file(self, path):
"""
Export the template to a file.

This produces a zip file with the template's definition and its resources, if any. The zip can be imported with
:meth:`dataikuapi.DSSClient.import_code_studio_template`

:param str path: the destination file path
"""
with open(path, 'wb') as f:
export_stream = self.client._perform_raw(
"GET", "/admin/code-studios/%s/export" % (self.template_id)
)
for chunk in export_stream.iter_content(chunk_size=32768):
if chunk:
f.write(chunk)
f.flush()

########################################################
# Template deletion
########################################################

def delete(self, delete_runtime=False, delete_images=False):
"""
Delete the template.

:param bool delete_runtime: if True, also delete the Code Studio runtimes created from this template
:param bool delete_images: if True, also delete the Docker images and build folders associated with this template

:return: backend info/warning/error messages about the deletion
:rtype: dict
"""
resp = self.client._perform_json(
"DELETE",
"/admin/code-studios/%s" % (self.template_id),
params={
"deleteRuntime": delete_runtime,
"deleteImages": delete_images
})
return DSSInfoMessages(resp)

class DSSCodeStudioTemplateSettings(object):
"""
The settings of a code studio template
Expand Down
237 changes: 237 additions & 0 deletions dataikuapi/dss/agent_skill.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
from requests import utils

from .utils import DSSTaggableObjectListItem, DSSTaggableObjectSettings


class DSSAgentSkillListItem(DSSTaggableObjectListItem):
"""
.. important::
Do not instantiate this class directly, instead use :meth:`dataikuapi.dss.project.DSSProject.list_agent_skills`.
"""

def __init__(self, client, project_key, data):
super(DSSAgentSkillListItem, self).__init__(data)
self.client = client
self.project_key = data.get("projectKey", project_key)

def to_agent_skill(self):
"""
Convert the current item.

:rtype: :class:`dataikuapi.dss.agent_skill.DSSAgentSkill`
"""
return DSSAgentSkill(self.client, self.project_key, self._data["id"])

@property
def id(self):
"""
:returns: The id of the skill.
:rtype: string
"""
return self._data["id"]

@property
def name(self):
"""
:returns: The name of the skill.
:rtype: string
"""
return self._data.get("name")


class DSSAgentSkill(object):
"""
.. important::
Do not instantiate this class directly, instead use :meth:`dataikuapi.dss.project.DSSProject.get_agent_skill`.
"""

def __init__(self, client, project_key, skill_id):
self.client = client
self.project_key = project_key
self.skill_id = skill_id

@property
def id(self):
"""
:returns: The id of the skill.
:rtype: string
"""
return self.skill_id

def get_settings(self):
"""
Get the DSS metadata settings of the agent skill.

The parsed ``SKILL.md`` fields are available through
:meth:`get_skill_content` and the raw file through :meth:`get_file`.

:return: a handle on the skill settings
:rtype: :class:`dataikuapi.dss.agent_skill.DSSAgentSkillSettings`
"""
settings = self.client._perform_json(
"GET",
"/projects/%s/agents/skills/%s" % (self.project_key, self.id),
)
return DSSAgentSkillSettings(self, settings)

def get_skill_content(self):
"""
Get the parsed contents of ``SKILL.md``.

:returns: A dictionary containing ``name``, ``description``,
``metadata``, and ``instructions``.
:rtype: dict
"""
return self.client._perform_json(
"GET",
"/projects/%s/agents/skills/%s/content"
% (self.project_key, self.id),
)

def delete(self):
"""
Delete the agent skill.
"""
return self.client._perform_empty("DELETE", "/projects/%s/agents/skills/%s" % (self.project_key, self.id))

def list_resources(self):
"""
List the files and folders attached to this skill as a recursive tree.

:rtype: list[dict]
"""
return self.client._perform_json(
"GET",
"/projects/%s/agents/skills/%s/resources/contents" % (self.project_key, self.id),
)

def get_file(self, path):
"""
Get a file's contents.

:param str path: Root-relative path of the file to download
:rtype: :class:`requests.models.Response`
"""
return self.client._perform_raw(
"GET",
"/projects/%s/agents/skills/%s/resources/contents/%s"
% (self.project_key, self.id, utils.quote(path)),
)

def get_file_details(self, path):
"""
Get a file's metadata without its content.

:param str path: Root-relative path of the file
:rtype: dict
"""
return self.client._perform_json(
"GET",
"/projects/%s/agents/skills/%s/resources/details/%s"
% (self.project_key, self.id, utils.quote(path)),
)

def put_file(self, path, data):
"""
Create or overwrite a file.

Strings are encoded as UTF-8 and bytes are stored unchanged. Parent
folders must already exist. Replacing the root ``SKILL.md`` validates
the supplied content and rejects an invalid skill file.

:param str path: Root-relative path of the file
:param data: String, bytes, or file-like content
:rtype: dict
"""
if isinstance(data, str):
data = data.encode("utf-8")
elif not isinstance(data, bytes) and not hasattr(data, "read"):
raise TypeError("data must be a string, bytes, or file-like object")
return self.client._perform_json(
"PUT",
"/projects/%s/agents/skills/%s/resources/contents/%s"
% (self.project_key, self.id, utils.quote(path)),
files={"file": (path.rsplit("/", 1)[-1], data)},
)

def rename_resource(self, path, new_name):
"""
Rename a resource.

:param str path: Root-relative path of the existing resource
:param str new_name: New file name, without a folder path
:rtype: str
"""
return self.client._perform_raw(
"POST",
"/projects/%s/agents/skills/%s/resources/contents-actions/rename"
% (self.project_key, self.id),
body={"oldPath": path, "newName": new_name},
).text

def move_resource(self, path, new_path):
"""
Move a resource to a destination folder.

:param str path: Root-relative path of the existing resource
:param str new_path: Root-relative path of the destination folder, or an empty string for the skill root
:rtype: str
"""
return self.client._perform_raw(
"POST",
"/projects/%s/agents/skills/%s/resources/contents-actions/move"
% (self.project_key, self.id),
body={"oldPath": path, "newPath": new_path},
).text

def create_folder(self, path):
"""
Create a resource folder in the skill.

Missing parent folders are created as needed.

:param str path: Root-relative path of the folder to create
"""
return self.client._perform_empty(
"POST",
"/projects/%s/agents/skills/%s/resources/folders/%s"
% (self.project_key, self.id, utils.quote(path)),
)

def delete_resource(self, path):
"""
Delete a resource from the skill.

:param str path: Root-relative path of the resource to delete
"""
return self.client._perform_empty(
"DELETE",
"/projects/%s/agents/skills/%s/resources/contents/%s"
% (self.project_key, self.id, utils.quote(path)),
)

class DSSAgentSkillSettings(DSSTaggableObjectSettings):
def __init__(self, agent_skill, settings):
super(DSSAgentSkillSettings, self).__init__(settings)
self.agent_skill = agent_skill

def get_raw(self):
"""
Get the raw settings of the skill.

:rtype: dict
"""
return self._tod

def save(self):
"""
Saves the DSS metadata settings of the agent skill.

This does not modify ``SKILL.md``. Use :meth:`DSSAgentSkill.put_file`
to replace the skill file.
"""
self.agent_skill.client._perform_empty(
"PUT",
"/projects/%s/agents/skills/%s" % (self.agent_skill.project_key, self.agent_skill.id),
body=self._tod,
)
Loading