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

from ._http_client import HttpClient


@dataclass_json
@dataclass(frozen=True)
class SetProcedureExperimentVersionParams:
"""Parameters for setting an experimental version of a procedure.

Experimental versions allow gradual rollout of new procedure versions
with daily conversation limits."""

# max_daily_conversations limits how many conversations per day can use this version.
# Allows gradual rollout of a new procedure version.
max_daily_conversations: int

# replace: if True, an existing experiment (if any) will be replaced with a new one.
# Otherwise, if another experiment already exists, an error will be returned.
replace: bool = False


def set_procedure_experiment_version(
*,
client: HttpClient,
procedure_id: str,
version: int,
params: SetProcedureExperimentVersionParams,
) -> None:
"""set_procedure_experiment_version marks the specified procedure version as experimental.

Experimental versions are used for A/B testing and are served to a limited number
of conversations per day. If an experiment already exists, it will only be replaced
if the 'replace' flag is set to True.

Note: requires a `Management` API key."""
body = {
"max_daily_conversations": params.max_daily_conversations,
"replace": params.replace,
}
client.post(
path=f"procedures/{procedure_id}/versions/{version}/set-experiment",
body=body,
)
16 changes: 16 additions & 0 deletions src/gradient_labs/_procedure_version_experiment_unset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from ._http_client import HttpClient


def unset_procedure_experiment_version(
*, client: HttpClient, procedure_id: str, version: int
) -> None:
"""unset_procedure_experiment_version removes the specified version of a procedure from being
marked as experimental.

Once unset, the version will no longer be used for A/B testing or served as an experiment.

Note: requires a `Management` API key."""
client.post(
path=f"procedures/{procedure_id}/versions/{version}/unset-experiment",
body={},
)
27 changes: 27 additions & 0 deletions src/gradient_labs/_procedure_version_list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from dataclasses import dataclass
from typing import List
from dataclasses_json import dataclass_json

from ._http_client import HttpClient
from .procedure import ProcedureVersion


@dataclass_json
@dataclass(frozen=True)
class ListProcedureVersionsResponse:
"""Response containing list of procedure versions."""

versions: List[ProcedureVersion]


def list_procedure_versions(
*, client: HttpClient, procedure_id: str
) -> ListProcedureVersionsResponse:
"""list_procedure_versions lists existing non-ephemeral versions of a procedure.

Note: requires a `Management` API key."""
body = client.get(
path=f"procedures/{procedure_id}/versions",
body={},
)
return ListProcedureVersionsResponse.from_dict(body)
22 changes: 22 additions & 0 deletions src/gradient_labs/_procedure_version_live_set.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from ._http_client import HttpClient


def set_procedure_live_version(
*, client: HttpClient, procedure_id: str, version: int
) -> None:
"""set_procedure_live_version promotes a specific version of a procedure to be the
live (production) version that the AI agent will use for new conversations.

The live version is the default version used by the agent when no experimental
versions are active. If the specified version is currently marked as experimental,
it will be promoted to live and will no longer be considered experimental.

This is typically used after testing a procedure version in experimental mode
and confirming it works correctly. Once live, the procedure version will be
used for all new conversations that match the procedure's criteria.

Note: requires a `Management` API key."""
client.post(
path=f"procedures/{procedure_id}/versions/{version}/set-live",
body={},
)
16 changes: 16 additions & 0 deletions src/gradient_labs/_procedure_version_live_unset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from ._http_client import HttpClient


def unset_procedure_live_version(
*, client: HttpClient, procedure_id: str, version: int
) -> None:
"""unset_procedure_live_version removes the specified version of a procedure from being the live revision.

Once unset, the version will no longer be used by default by the agent.
This does not delete the version or affect its experimental status (if any).

Note: requires a `Management` API key."""
client.post(
path=f"procedures/{procedure_id}/versions/{version}/unset-live",
body={},
)
87 changes: 87 additions & 0 deletions src/gradient_labs/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,17 @@
from ._procedure_read import read_procedure
from ._procedure_list import list_procedures, ProcedureListParams, ProcedureListResponse
from ._procedure_set_limit import set_procedure_limit, ProcedureLimitParams
from ._procedure_version_list import (
list_procedure_versions,
ListProcedureVersionsResponse,
)
from ._procedure_version_live_set import set_procedure_live_version
from ._procedure_version_live_unset import unset_procedure_live_version
from ._procedure_version_experiment_set import (
set_procedure_experiment_version,
SetProcedureExperimentVersionParams,
)
from ._procedure_version_experiment_unset import unset_procedure_experiment_version

from ._tool_create import create_tool
from ._tool_delete import delete_tool
Expand Down Expand Up @@ -329,6 +340,82 @@ def set_procedure_limit(
params=params,
)

def list_procedure_versions(
self, *, procedure_id: str
) -> ListProcedureVersionsResponse:
"""list_procedure_versions lists existing non-ephemeral versions of a procedure.

Each procedure can have multiple versions, with one marked as "live" (production)
and optionally one marked as "experimental" for controlled testing.

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

def set_procedure_live_version(self, *, procedure_id: str, version: int) -> None:
"""set_procedure_live_version promotes a specific version to be the live (production) version.

The live version is the default version used by the agent when no experimental
versions are active. If the specified version is currently marked as experimental,
it will be promoted to live and will no longer be considered experimental.

Note: requires a `Management` API key."""
set_procedure_live_version(
client=self.http_client,
procedure_id=procedure_id,
version=version,
)

def unset_procedure_live_version(self, *, procedure_id: str, version: int) -> None:
"""unset_procedure_live_version removes the specified version from being the live revision.

Once unset, the version will no longer be used by default by the agent.
This does not delete the version or affect its experimental status (if any).

Note: requires a `Management` API key."""
unset_procedure_live_version(
client=self.http_client,
procedure_id=procedure_id,
version=version,
)

def set_procedure_experiment_version(
self,
*,
procedure_id: str,
version: int,
params: SetProcedureExperimentVersionParams,
) -> None:
"""set_procedure_experiment_version marks a version as experimental for A/B testing.

Experimental versions are served to a limited number of conversations per day.
If an experiment already exists, it will only be replaced if the 'replace'
flag is set to True.

Note: requires a `Management` API key."""
set_procedure_experiment_version(
client=self.http_client,
procedure_id=procedure_id,
version=version,
params=params,
)

def unset_procedure_experiment_version(
self, *, procedure_id: str, version: int
) -> None:
"""unset_procedure_experiment_version removes experimental status from a version.

Once unset, the version will no longer be used for A/B testing or served as an experiment.

Note: requires a `Management` API key."""
unset_procedure_experiment_version(
client=self.http_client,
procedure_id=procedure_id,
version=version,
)

def create_tool(self, *, tool: Tool) -> Tool:
"""create_tool creates a new tool.

Expand Down
50 changes: 50 additions & 0 deletions src/gradient_labs/procedure.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,53 @@ class Procedure:
# max_daily_conversations is the maximum number of conversations that a procedure
# can be used in on a given day, when it is rate limited.
max_daily_conversations: int


@dataclass_json
@dataclass(frozen=True)
class ExperimentalConfig:
"""Configuration for experimental procedure versions."""

# max_daily_conversations is the maximum number of conversations per day
# that can use this experimental version.
max_daily_conversations: int


@dataclass_json
@dataclass(frozen=True)
class ProcedureVersion:
"""A specific version of a procedure."""

# name is the user-given name of the procedure at the time of this version.
name: str

# description of the procedure at the time of this version.
description: str

# version is a numeric identifier for the version. It is incremented every
# time a new version of the procedure is saved.
version: int

# author is the ID of the user who created this version of the procedure.
author: str

# created is the time at which this version of the procedure was created.
created: datetime = field(
metadata=config(
encoder=datetime.isoformat,
decoder=datetime.fromisoformat,
mm_field=fields.DateTime(format="iso"),
)
)

# experimental indicates whether this is an experimental version that is used before "live",
# within the daily limit defined in experimental_config.
experimental: bool

# experimental_config defines how the experimental version is limited.
# Relevant only if experimental == True.
experimental_config: ExperimentalConfig | None

# live indicates whether this is the "production" version that is used by the agent by default,
# if there are no experimental versions or all of them have exceeded their limit.
live: bool