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
15 changes: 15 additions & 0 deletions doc/source/user_guide/actions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,21 @@ The following actions can be performed using ``select_ai``:
Action methods
==============

Request-specific profile attributes can be supplied with the optional
``attributes`` mapping. For example, override ``additional_instructions`` for
a single chat request:

.. code-block:: python

response = profile.chat(
prompt="Write sample Python code to build and test a regression model",
attributes={
"additional_instructions": (
"Return executable code as plain text without Markdown fences."
)
},
)

.. list-table:: Action to method mapping
:header-rows: 1
:widths: 30 35 35
Expand Down
20 changes: 20 additions & 0 deletions doc/source/user_guide/profile_attributes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ Attribute groups
- Tunes model generation behavior.
* - ``conversation``
- Enables conversation history for context-aware chat workflows.
* - ``additional_instructions``
- Provides persistent guidance, business rules, or response constraints
for requests that use the profile.
* - ``source_language``, ``target_language``
- Set default languages for ``Profile.translate()`` and
``AsyncProfile.translate()``. If no source language is configured or
Expand Down Expand Up @@ -134,5 +137,22 @@ responses:
stop_tokens='[";"]',
)

Additional instructions
=======================

Use ``additional_instructions`` for guidance that should apply to every
request made with a profile:

.. code-block:: python

attributes = select_ai.ProfileAttributes(
provider=provider,
credential_name="my_oci_ai_profile_key",
additional_instructions="Return concise, executable Python code.",
)

For guidance that applies to only one request, pass an ``attributes`` mapping
to an action method instead of changing the saved profile.

.. autoclass:: select_ai.ProfileAttributes
:members:
4 changes: 4 additions & 0 deletions src/select_ai/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@
from .credential import (
async_create_credential,
async_delete_credential,
async_grant_credential_access,
async_revoke_credential_access,
create_credential,
delete_credential,
grant_credential_access,
revoke_credential_access,
)
from .db import (
async_connect,
Expand Down
10 changes: 10 additions & 0 deletions src/select_ai/_validations.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@
NoneType = type(None)


def validate_user_or_role_name(user_or_role_name: str) -> str:
"""Validate and normalize a sharing grantee name."""
if not isinstance(user_or_role_name, str):
raise TypeError("'user_or_role_name' must be a string")
user_or_role_name = user_or_role_name.strip()
if not user_or_role_name:
raise ValueError("'user_or_role_name' cannot be empty")
return user_or_role_name


def _match(value, annot) -> bool:
"""Recursively validate value against a typing annotation."""
if annot is Any:
Expand Down
49 changes: 49 additions & 0 deletions src/select_ai/agent/team.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import oracledb

from select_ai._abc import SelectAIDataClass
from select_ai._validations import validate_user_or_role_name
from select_ai.agent.sql import (
GET_USER_AI_AGENT_TEAM,
GET_USER_AI_AGENT_TEAM_ATTRIBUTES,
Expand Down Expand Up @@ -243,6 +244,30 @@ def enable(self):
},
)

def grant_access(self, user_or_role_name: str) -> None:
"""Grant a database user or role access to this agent team."""
user_or_role_name = validate_user_or_role_name(user_or_role_name)
with cursor() as cr:
cr.callproc(
"DBMS_CLOUD_AI_AGENT.GRANT_TEAM_ACCESS",
keyword_parameters={
"team_name": self.team_name,
"user_or_role_name": user_or_role_name,
},
)

def revoke_access(self, user_or_role_name: str) -> None:
"""Revoke a database user or role's access to this agent team."""
user_or_role_name = validate_user_or_role_name(user_or_role_name)
with cursor() as cr:
cr.callproc(
"DBMS_CLOUD_AI_AGENT.REVOKE_TEAM_ACCESS",
keyword_parameters={
"team_name": self.team_name,
"user_or_role_name": user_or_role_name,
},
)

@classmethod
def fetch(cls, team_name: str) -> "Team":
"""
Expand Down Expand Up @@ -704,6 +729,30 @@ async def enable(self):
},
)

async def grant_access(self, user_or_role_name: str) -> None:
"""Asynchronously grant a user or role access to this agent team."""
user_or_role_name = validate_user_or_role_name(user_or_role_name)
async with async_cursor() as cr:
await cr.callproc(
"DBMS_CLOUD_AI_AGENT.GRANT_TEAM_ACCESS",
keyword_parameters={
"team_name": self.team_name,
"user_or_role_name": user_or_role_name,
},
)

async def revoke_access(self, user_or_role_name: str) -> None:
"""Asynchronously revoke a user or role's agent team access."""
user_or_role_name = validate_user_or_role_name(user_or_role_name)
async with async_cursor() as cr:
await cr.callproc(
"DBMS_CLOUD_AI_AGENT.REVOKE_TEAM_ACCESS",
keyword_parameters={
"team_name": self.team_name,
"user_or_role_name": user_or_role_name,
},
)

@classmethod
async def fetch(cls, team_name: str) -> "AsyncTeam":
"""
Expand Down
Loading
Loading