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
53 changes: 53 additions & 0 deletions src/gradient_labs/_resource_type_create.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from typing import Optional
from dataclasses import dataclass
from dataclasses_json import dataclass_json

from ._http_client import HttpClient
from .resource_type import ResourceType, Scope, RefreshStrategy, SourceConfig


@dataclass_json
@dataclass(frozen=True)
class CreateResourceTypeParams:
"""CreateResourceTypeParams contains the parameters for creating a resource type."""

# DisplayName is a human-readable name for the resource type.
display_name: str

# Scope determines when in the conversation the resource is fetched and used.
scope: Scope

# RefreshStrategy determines how often the resource is re-fetched.
refresh_strategy: RefreshStrategy

# Description is an optional human-readable description of the resource type.
description: Optional[str] = None

# SourceConfig defines how the resource is fetched.
source_config: Optional[SourceConfig] = None

# IsEnabled indicates whether the resource type should be enabled.
is_enabled: Optional[bool] = None


def create_resource_type(
*, client: HttpClient, params: CreateResourceTypeParams
) -> ResourceType:
"""create_resource_type creates a new resource type.

Note: requires a Management API key.
"""
body = {
"display_name": params.display_name,
"scope": params.scope.value,
"refresh_strategy": params.refresh_strategy.value,
}
if params.description is not None:
body["description"] = params.description
if params.source_config is not None:
body["source_config"] = params.source_config.to_dict()
if params.is_enabled is not None:
body["is_enabled"] = params.is_enabled

rsp = client.post(path="resource-types", body=body)
return ResourceType.from_dict(rsp)
9 changes: 9 additions & 0 deletions src/gradient_labs/_resource_type_delete.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from ._http_client import HttpClient


def delete_resource_type(*, client: HttpClient, id: str) -> None:
"""delete_resource_type deletes a resource type by ID.

Note: requires a Management API key.
"""
_ = client.delete(path=f"resource-types/{id}", body={})
23 changes: 23 additions & 0 deletions src/gradient_labs/_resource_type_list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from typing import List
from dataclasses import dataclass
from dataclasses_json import dataclass_json

from ._http_client import HttpClient
from .resource_type import ResourceType


@dataclass_json
@dataclass(frozen=True)
class ResourceTypesList:
"""ResourceTypesList contains the list of resource types."""

resource_types: List[ResourceType]


def list_resource_types(*, client: HttpClient) -> ResourceTypesList:
"""list_resource_types lists all resource types.

Note: requires a Management API key.
"""
rsp = client.get(path="resource-types", body={})
return ResourceTypesList.from_dict(rsp)
11 changes: 11 additions & 0 deletions src/gradient_labs/_resource_type_read.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from ._http_client import HttpClient
from .resource_type import ResourceType


def read_resource_type(*, client: HttpClient, id: str) -> ResourceType:
"""read_resource_type retrieves a specific resource type by ID.

Note: requires a Management API key.
"""
rsp = client.get(path=f"resource-types/{id}", body={})
return ResourceType.from_dict(rsp)
55 changes: 55 additions & 0 deletions src/gradient_labs/_resource_type_update.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from typing import Optional
from dataclasses import dataclass
from dataclasses_json import dataclass_json

from ._http_client import HttpClient
from .resource_type import ResourceType, Scope, RefreshStrategy, SourceConfig


@dataclass_json
@dataclass(frozen=True)
class UpdateResourceTypeParams:
"""UpdateResourceTypeParams contains the parameters for updating a resource type."""

# DisplayName is a human-readable name for the resource type.
display_name: Optional[str] = None

# Description is an optional human-readable description of the resource type.
description: Optional[str] = None

# Scope determines when in the conversation the resource is fetched and used.
scope: Optional[Scope] = None

# RefreshStrategy determines how often the resource is re-fetched.
refresh_strategy: Optional[RefreshStrategy] = None

# SourceConfig defines how the resource is fetched.
source_config: Optional[SourceConfig] = None

# IsEnabled indicates whether the resource type should be enabled.
is_enabled: Optional[bool] = None


def update_resource_type(
*, client: HttpClient, id: str, params: UpdateResourceTypeParams
) -> ResourceType:
"""update_resource_type updates an existing resource type.

Note: requires a Management API key.
"""
body = {}
if params.display_name is not None:
body["display_name"] = params.display_name
if params.description is not None:
body["description"] = params.description
if params.scope is not None:
body["scope"] = params.scope.value
if params.refresh_strategy is not None:
body["refresh_strategy"] = params.refresh_strategy.value
if params.source_config is not None:
body["source_config"] = params.source_config.to_dict()
if params.is_enabled is not None:
body["is_enabled"] = params.is_enabled

rsp = client.put(path=f"resource-types/{id}", body=body)
return ResourceType.from_dict(rsp)
54 changes: 54 additions & 0 deletions src/gradient_labs/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,17 @@
from ._secrets_list import list_secrets, SecretsList
from ._secret_revoke import revoke_secret

from ._resource_type_create import create_resource_type, CreateResourceTypeParams
from ._resource_type_list import list_resource_types, ResourceTypesList
from ._resource_type_read import read_resource_type
from ._resource_type_update import update_resource_type, UpdateResourceTypeParams
from ._resource_type_delete import delete_resource_type

from ._http_client import HttpClient, API_BASE_URL
from .tool import *
from .note import Note
from .secret import Secret
from .resource_type import ResourceType, Scope, RefreshStrategy, SourceConfig
from .webhook import Webhook, WebhookEvent


Expand Down Expand Up @@ -583,3 +590,50 @@ def revoke_secret(self, *, name: str) -> None:
client=self.http_client,
name=name,
)

# Resource Type Operations

def create_resource_type(self, *, params: CreateResourceTypeParams) -> ResourceType:
"""create_resource_type creates a new resource type.

Note: requires a `Management` API key."""
return create_resource_type(
client=self.http_client,
params=params,
)

def list_resource_types(self) -> ResourceTypesList:
"""list_resource_types returns all of your resource types.

Note: requires a `Management` API key."""
return list_resource_types(client=self.http_client)

def read_resource_type(self, *, id: str) -> ResourceType:
"""read_resource_type retrieves a specific resource type by ID.

Note: requires a `Management` API key."""
return read_resource_type(
client=self.http_client,
id=id,
)

def update_resource_type(
self, *, id: str, params: UpdateResourceTypeParams
) -> ResourceType:
"""update_resource_type updates an existing resource type.

Note: requires a `Management` API key."""
return update_resource_type(
client=self.http_client,
id=id,
params=params,
)

def delete_resource_type(self, *, id: str) -> None:
"""delete_resource_type permanently deletes a resource type. This action cannot be undone.

Note: requires a `Management` API key."""
delete_resource_type(
client=self.http_client,
id=id,
)
114 changes: 114 additions & 0 deletions src/gradient_labs/resource_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
from typing import Optional, List, Any
from enum import Enum
from dataclasses import dataclass
from dataclasses_json import dataclass_json
from datetime import datetime


class Scope(str, Enum):
"""Scope determines when in the conversation the resource is fetched and used."""

# GLOBAL means the resource is available throughout the conversation and in all procedures.
GLOBAL: str = "global"

# LOCAL means the resource is available only in procedures that explicitly use it, only fetched when it's used.
LOCAL: str = "local"


class RefreshStrategy(str, Enum):
"""RefreshStrategy determines how often the resource is re-fetched."""

# DYNAMIC means the resource value can change, so this is re-fetched throughout the conversation.
DYNAMIC: str = "dynamic"

# STATIC means the resource is fetched once at the start of the conversation (global) or when it's first used in a procedure (local).
STATIC: str = "static"


@dataclass_json
@dataclass(frozen=True)
class SourceConfig:
"""SourceConfig defines how the resource is fetched."""

# SourceID identifies the source which should be used to fetch the resource data.
source_id: str

# Attributes defines the top-level field names to be used from the source data.
attributes: Optional[List[str]] = None

# Cache determines how long we'll consider data from the source be valid before refreshing it.
# It's either a duration string (e.g. "5m") or "never" if the resource is refreshed on every turn.
# The default is 1 minute.
cache: Optional[str] = None


@dataclass_json
@dataclass(frozen=True)
class Attribute:
"""Attribute describes a single attribute in the resource schema."""

# Path is the JSON path to the attribute (e.g., "user.name", "orderDetails[0].item").
path: str

# Type is the data type of the attribute (e.g., "string", "number", "integer", "boolean", "object", "array").
type: str

# Cardinality is whether the attribute can have one value ("one") or multiple values ("many").
cardinality: str

# Name is the name of the attribute (the last part of the path).
name: str

# Description is an optional description of the attribute.
description: Optional[str] = None

# IsRoot indicates whether the attribute is a top-level field in the resource data.
is_root: Optional[bool] = None


@dataclass_json
@dataclass(frozen=True)
class Schema:
"""Schema describes the structure of the resource data."""

# Raw is the raw JSON schema for the resource data.
raw: Optional[Any] = None

# Attributes is an array of attribute descriptors for the resource data.
attributes: Optional[List[Attribute]] = None


@dataclass_json
@dataclass
class ResourceType:
"""ResourceType represents a resource type configuration."""

# ID is the unique identifier for the resource type.
id: str

# DisplayName is a human-readable name for the resource type.
display_name: str

# Description is an optional human-readable description of the resource type.
description: Optional[str] = None

# Scope determines when in the conversation the resource is fetched and used.
scope: Scope = Scope.GLOBAL

# RefreshStrategy determines how often the resource is re-fetched.
refresh_strategy: RefreshStrategy = RefreshStrategy.DYNAMIC

# SourceConfig defines how the resource is fetched.
source_config: Optional[SourceConfig] = None

# Schema describes the structure of the data returned by the resource source.
schema: Optional[Schema] = None

# IsEnabled indicates whether the resource type is enabled.
is_enabled: bool = False

# Created is when the resource type was created.
created: Optional[datetime] = None

# Updated is when the resource type was last updated.
updated: Optional[datetime] = None