An AsyncProfile object can be created with select_ai.AsyncProfile(). AsyncProfile supports concurrent programming with asyncio. Unless explicitly noted as synchronous, the AsyncProfile methods should be used with await.

Use AsyncProfile in applications that already use select_ai.async_connect() or select_ai.create_pool_async(). The async profile object uses the same database profile objects as Profile; only the Python API style changes.

Because AsyncProfile initializes itself from the database, create or fetch instances with await:

async_profile = await select_ai.AsyncProfile(
    profile_name="async_oci_ai_profile",
)

Before creating an async profile, make sure the database user has the required privileges, a credential for the AI provider, network access to the provider endpoint, and access to the database objects included in the profile. See Privileges, Credential, Provider, and ProfileAttributes.

1. Async profile lifecycle

The usual async profile lifecycle is:

  • Create or reuse an async database connection or async pool.

  • Create a provider object.

  • Create ProfileAttributes with the provider, credential name, and object list.

  • Create the profile with await select_ai.AsyncProfile(...).

  • Reuse the profile later by name.

  • Enable or disable the profile without deleting it.

  • Update profile attributes when provider settings or object scope changes.

  • Delete profiles that are no longer needed.

replace=True recreates a profile when a profile with the same name already exists. merge=True fetches the existing profile and updates it with the non-null attributes passed by the caller.

2. Async profile actions

Common async profile actions

Method

Description

show_sql()

Generates SQL for a natural language prompt without executing it.

run_sql()

Generates SQL, executes it, and returns a pandas.DataFrame.

narrate()

Generates SQL, executes it, and returns a natural language answer.

explain_sql()

Explains the generated SQL for a prompt.

show_prompt()

Shows the prompt sent to the model.

chat()

Sends a general chat prompt to the model.

summarize()

Summarizes inline content or content referenced by a URI.

translate()

Translates text from one language to another.

2.1. AsyncProfile API

class select_ai.AsyncProfile(*args, **kwargs)

AsyncProfile defines methods to interact with the underlying AI Provider asynchronously.

async add_negative_feedback(prompt_spec: Tuple[str, Action] | None = None, sql_id: str | None = None, response: str | None = None, feedback_content: str | None = None)

Give negative feedback to the LLM

Parameters:
  • prompt_spec (Tuple[str, select_ai.action.Action]) – First element is the prompt; second is the corresponding action

  • sql_id (str) – SQL identifier from V$MAPPED_SQL view

  • response (str) – Expected SQL from LLM

  • feedback_content (str) – Actual feedback in natural language

async add_positive_feedback(prompt_spec: Tuple[str, Action] | None = None, sql_id: str | None = None)

Give positive feedback to the LLM

Parameters:
  • prompt_spec (Tuple[str, select_ai.action.Action]) – First element is the prompt; second is the corresponding action

  • sql_id (str) – SQL identifier from V$MAPPED_SQL view

async chat(prompt, params: Mapping = None, stream: bool = False, chunk_size: int = 8192, *, attributes: Mapping = None) → str | AsyncGenerator[str, None]

Asynchronously chat with the LLM

Parameters:
  • prompt (str) – Natural language prompt

  • params – Parameters to include in the LLM request

  • attributes (Mapping) – Profile attributes to override for this request

  • stream (bool) – Return an async iterator of response chunks

  • chunk_size (int) – Number of characters to read per stream chunk

Returns:

str

chat_session(conversation: AsyncConversation, delete: bool = False)

Starts a new chat session for context-aware conversations

Parameters:
  • conversation (AsyncConversation) – Conversation object to use for this chat session

  • delete (bool) – Delete conversation after session ends

async create(replace: int | None = False) → None

Asynchronously create an AI Profile in the Database

Parameters:

replace (bool) – Set True to replace else False

Returns:

None

Raises:

oracledb.DatabaseError

async delete(force=False) → None

Asynchronously deletes an AI profile from the database

Parameters:

force (bool) – Ignores errors if AI profile does not exist.

Returns:

None

Raises:

oracledb.DatabaseError

async delete_feedback(prompt_spec: Tuple[str, Action] = None, sql_id: str | None = None)

Delete feedback from the database

Parameters:
  • prompt_spec (Tuple[str, select_ai.action.Action]) – First element is the prompt; second is the corresponding action

  • sql_id (str) – SQL identifier from V$MAPPED_SQL view

async classmethod delete_profile(profile_name: str, force: bool = False)

Asynchronously deletes an AI profile from the database

Parameters:
  • profile_name (str) – Name of the AI profile

  • force (bool) – Ignores errors if AI profile does not exist.

Returns:

None

Raises:

oracledb.DatabaseError

async disable() → None

Asynchronously disable this AI profile in the database.

Returns:

None

Raises:

oracledb.DatabaseError

async enable() → None

Asynchronously enable this AI profile in the database.

Returns:

None

Raises:

oracledb.DatabaseError

async explain_sql(prompt: str, params: Mapping = None, stream: bool = False, chunk_size: int = 8192, *, attributes: Mapping = None)

Explain the generated SQL

Parameters:
  • prompt (str) – Natural language prompt

  • params – Parameters to include in the LLM request

  • attributes (Mapping) – Profile attributes to override for this request

  • stream (bool) – Return an async iterator of response chunks

  • chunk_size (int) – Number of characters to read per stream chunk

Returns:

str

async classmethod fetch(profile_name: str, owner: str | None = None) → AsyncProfile

Asynchronously create an AI Profile object from attributes saved in the database

Parameters:
  • profile_name (str) – Name of the AI profile.

  • owner (str) – Owner of a shared profile. Defaults to current schema.

Returns:

select_ai.Profile

Raises:

ProfileNotFoundError

async generate(prompt: str, action=Action.SHOWSQL, params: Mapping = None, stream: bool = False, chunk_size: int = 8192, *, attributes: Mapping = None) → DataFrame | str | AsyncGenerator[str, None] | None

Asynchronously perform AI translation using this profile

Parameters:
  • prompt (str) – Natural language prompt to translate

  • action (select_ai.action.Action)

  • params – Parameters to include in the LLM request. For e.g. conversation_id for context-aware chats

  • attributes (Mapping) – Profile attributes to override for this request

  • stream (bool) – Return an async iterator of response chunks

  • chunk_size (int) – Number of characters to read per stream chunk

Returns:

Union[pandas.DataFrame, str]

async generate_synthetic_data(synthetic_data_attributes: SyntheticDataAttributes) → None

Generate synthetic data for a single table, multiple tables or a full schema.

Parameters:

synthetic_data_attributes (select_ai.SyntheticDataAttributes)

Returns:

None

Raises:

oracledb.DatabaseError

async get_attributes() → ProfileAttributes

Asynchronously gets AI profile attributes from the Database

Returns:

select_ai.ProfileAttributes

Raises:

ProfileNotFoundError

async grant_access(user_or_role_name: str) → None

Asynchronously grant a user or role access to this AI profile.

classmethod list(profile_name_pattern: str = '.*', owner: str | None = None) → AsyncGenerator[AsyncProfile, None]

Asynchronously list AI Profiles saved in the database.

Parameters:
  • profile_name_pattern (str) – Regular expressions can be used to specify a pattern. Function REGEXP_LIKE is used to perform the match. Default value is “.*” i.e. match all AI profiles.

  • owner (str) – Owner of shared profiles. Defaults to current schema.

Returns:

Iterator[Profile]

async narrate(prompt, params: Mapping = None, stream: bool = False, chunk_size: int = 8192, *, attributes: Mapping = None) → str | AsyncGenerator[str, None]

Narrate the result of the SQL

Parameters:
  • prompt (str) – Natural language prompt

  • params – Parameters to include in the LLM request

  • attributes (Mapping) – Profile attributes to override for this request

  • stream (bool) – Return an async iterator of response chunks

  • chunk_size (int) – Number of characters to read per stream chunk

Returns:

str

property qualified_name: str | None

Return the owner-qualified profile name when owner is known.

async revoke_access(user_or_role_name: str) → None

Asynchronously revoke a user or role’s profile access.

async run_pipeline(prompt_specifications: List[Tuple[str, Action]], continue_on_error: bool = False, *, attributes: Mapping = None) → List[object]

Submit prompt/action pairs as a database pipeline

Parameters:
  • prompt_specifications (List[Tuple[str, select_ai.action.Action]]) – List of 2-element tuples. First element is the prompt and second is the corresponding action

  • continue_on_error (bool) – True to continue on error else False

  • attributes (Mapping) – Profile attributes to override for every request in the pipeline

Returns:

Ordered list of strings for successful operations and driver error objects for failures when continue_on_error=True. RUNSQL results remain JSON strings; they are not converted to DataFrames.

Operations execute sequentially. Round-trip reduction requires a supporting database version; reading returned CLOBs adds calls. With continue_on_error=False, an operation failure raises an exception.

async run_sql(prompt, params: Mapping = None, *, attributes: Mapping = None) → DataFrame

Explain the generated SQL

Parameters:
  • prompt (str) – Natural language prompt

  • params – Parameters to include in the LLM request

  • attributes (Mapping) – Profile attributes to override for this request

Returns:

pandas.DataFrame

async set_attribute(attribute_name: str, attribute_value: bool | str | int | float | Provider)

Updates AI profile attribute on the Python object and also saves it in the database

Parameters:
  • attribute_name (str) – Name of the AI profile attribute

  • attribute_value (Union[bool, str, int, float]) – Value of the profile attribute

Returns:

None

async set_attributes(attributes: ProfileAttributes)

Updates AI profile attributes on the Python object and also saves it in the database

Parameters:

attributes (ProfileAttributes) – Object specifying AI profile attributes

Returns:

None

async show_prompt(prompt: str, params: Mapping = None, stream: bool = False, chunk_size: int = 8192, *, attributes: Mapping = None)

Show the prompt sent to LLM

Parameters:
  • prompt (str) – Natural language prompt

  • params – Parameters to include in the LLM request

  • attributes (Mapping) – Profile attributes to override for this request

  • stream (bool) – Return an async iterator of response chunks

  • chunk_size (int) – Number of characters to read per stream chunk

Returns:

str

async show_sql(prompt, params: Mapping = None, stream: bool = False, chunk_size: int = 8192, *, attributes: Mapping = None)

Show the generated SQL

Parameters:
  • prompt (str) – Natural language prompt

  • params – Parameters to include in the LLM request

  • attributes (Mapping) – Profile attributes to override for this request

  • stream (bool) – Return an async iterator of response chunks

  • chunk_size (int) – Number of characters to read per stream chunk

Returns:

str

async summarize(content: str = None, prompt: str = None, location_uri: str = None, credential_name: str = None, params: SummaryParams = None) → str

Generate summary

Parameters:
  • prompt (str) – Natural language prompt to guide the summary generation

  • content (str) – Specifies the text you want to summarize

  • location_uri (str) – Provides the URI where the text is stored or the path to a local file stored

  • credential_name (str) – Identifies the credential object used to authenticate with the object store

  • params (select_ai.summary.SummaryParams) – Parameters to include in the LLM request

async translate(text: str, source_language: str | None = None, target_language: str | None = None) → str | None

Translate text using the supplied languages or the profile defaults.

Parameters:
  • text (str) – Text to translate

  • source_language (str) – Source language. When omitted, the profile value is used; if the profile does not define one, the provider detects the source language.

  • target_language (str) – Target language. When omitted, the profile value is used.

Returns:

str

2.2. Async Profile creation

The following example creates an OCI Gen AI profile that can generate SQL over objects in the SH schema.

import asyncio
import os
from pprint import pformat

import select_ai

user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")


# This example shows how to asynchronously generate SQLs nad run SQLs
async def main():
    await select_ai.async_connect(user=user, password=password, dsn=dsn)
    provider = select_ai.OCIGenAIProvider(
        region="us-chicago-1", oci_apiformat="GENERIC"
    )
    profile_attributes = select_ai.ProfileAttributes(
        credential_name="my_oci_ai_profile_key",
        object_list=[{"owner": "SH"}],
        provider=provider,
    )
    async_profile = await select_ai.AsyncProfile(
        profile_name="async_oci_ai_profile",
        attributes=profile_attributes,
        description="MY OCI AI Profile",
        replace=True,
    )
    print("Created async profile ", async_profile.profile_name)
    profile_attributes = await async_profile.get_attributes()
    print(
        "Profile attributes: ",
        pformat(profile_attributes.dict(exclude_null=False)),
    )


asyncio.run(main())

output:

Created async profile  async_oci_ai_profile
Profile attributes:  {'annotations': None,
 'case_sensitive_values': None,
 'comments': None,
 'constraints': None,
 'conversation': None,
 'credential_name': 'my_oci_ai_profile_key',
 'enable_source_offsets': None,
 'enable_sources': None,
 'enforce_object_list': None,
 'max_tokens': '1024',
 'object_list': '[{"owner":"SH"}]',
 'object_list_mode': None,
 'provider': OCIGenAIProvider(embedding_model=None,
                              model=None,
                              provider_name='oci',
                              provider_endpoint=None,
                              region='us-chicago-1',
                              oci_apiformat='GENERIC',
                              oci_compartment_id=None,
                              oci_endpoint_id=None,
                              oci_runtimetype=None),
 'seed': None,
 'stop_tokens': None,
 'streaming': None,
 'temperature': None,
 'vector_index_name': None}

2.3. Reuse Async Profile

After a profile has been created, instantiate AsyncProfile with only the profile name to reuse the database profile:

async_profile = await select_ai.AsyncProfile(
    profile_name="async_oci_ai_profile",
)
sql = await async_profile.show_sql(prompt="How many promotions?")

Use AsyncProfile.fetch(...) when you want to create a proxy object from a saved database profile and raise an error if the profile does not exist:

async_profile = await select_ai.AsyncProfile.fetch(
    "async_oci_ai_profile"
)

2.4. Enable and disable AsyncProfile

Use await AsyncProfile.disable() to make an existing profile unavailable without deleting it. Call await AsyncProfile.enable() to make it available again. These methods change the database profile status and return None.

import asyncio
import os

import select_ai

user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")
profile_name = os.getenv("SELECT_AI_PROFILE_NAME", "oci_ai_profile")


async def main():
    await select_ai.async_connect(user=user, password=password, dsn=dsn)
    profile = await select_ai.AsyncProfile(profile_name=profile_name)

    await profile.disable()
    try:
        print("Disabled profile:", profile.profile_name)
    finally:
        await profile.enable()
        print("Enabled profile:", profile.profile_name)


asyncio.run(main())

The sample uses SELECT_AI_PROFILE_NAME when set, otherwise it operates on oci_ai_profile. It always re-enables the profile during cleanup:

output:

Disabled profile: oci_ai_profile
Enabled profile: oci_ai_profile

2.5. Update Async Profile

Use set_attribute(...) to update one profile attribute or set_attributes(...) to update several attributes. Updates are saved to the database profile.

async_profile = await select_ai.AsyncProfile(
    profile_name="async_oci_ai_profile",
)
await async_profile.set_attribute("temperature", 0.1)

await async_profile.set_attributes(
    select_ai.ProfileAttributes(
        max_tokens=2048,
        enforce_object_list=True,
    )
)

2.6. Delete Async Profile

Use delete(...) or AsyncProfile.delete_profile(...) to remove a profile from the database. Pass force=True when cleanup should succeed even if the profile does not exist.

async_profile = await select_ai.AsyncProfile(
    profile_name="async_oci_ai_profile",
)
await async_profile.delete(force=True)

await select_ai.AsyncProfile.delete_profile(
    "async_oci_ai_profile",
    force=True,
)

2.7. Async explain SQL

import asyncio
import os

import select_ai

user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")


async def main():
    await select_ai.async_connect(user=user, password=password, dsn=dsn)
    async_profile = await select_ai.AsyncProfile(
        profile_name="async_oci_ai_profile",
    )
    response = await async_profile.explain_sql("How many promotions ?")
    print(response)


asyncio.run(main())

output:

To answer the question "How many promotions", we need to write a SQL query that counts the number of rows in the "PROMOTIONS" table. Here is the query:

```sql
SELECT
  COUNT("p"."PROMO_ID") AS "Number of Promotions"
FROM
  "SH"."PROMOTIONS" "p";
```

Explanation:

* We use the `COUNT` function to count the number of rows in the table.
* We use the table alias `"p"` to refer to the `"PROMOTIONS"` table.
* We enclose the table name and column name in double quotes to make them case-sensitive.
* We use the `AS` keyword to give an alias to the count column, making it easier to read.

This query will return the total number of promotions in the `"PROMOTIONS"` table.

2.8. Async run SQL

import asyncio
import os

import select_ai

user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")


# This example shows how to asynchronously run sql
async def main():
    await select_ai.async_connect(user=user, password=password, dsn=dsn)
    async_profile = await select_ai.AsyncProfile(
        profile_name="async_oci_ai_profile",
    )
    # run_sql returns a pandas df
    df = await async_profile.run_sql("How many promotions?")
    print(df)


asyncio.run(main())

output:

   PROMOTION_COUNT
0              503

2.9. Async show SQL

import asyncio
import os

import select_ai

user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")


async def main():
    await select_ai.async_connect(user=user, password=password, dsn=dsn)
    async_profile = await select_ai.AsyncProfile(
        profile_name="async_oci_ai_profile",
    )
    response = await async_profile.show_sql("How many promotions?")
    print(response)


asyncio.run(main())

output:

SELECT COUNT("p"."PROMO_ID") AS "PROMOTION_COUNT" FROM "SH"."PROMOTIONS" "p"

2.10. Async show prompt

Use show_prompt(...) to inspect the prompt that Select AI sends to the model. This is useful when tuning profile attributes, object lists, comments, constraints, and provider settings.

async_profile = await select_ai.AsyncProfile(
    profile_name="async_oci_ai_profile",
)
prompt = await async_profile.show_prompt(prompt="How many promotions?")
print(prompt)

2.11. Async concurrent SQL

import asyncio
import os

import select_ai

user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")


async def main():
    select_ai.create_pool_async(
        user=user, password=password, dsn=dsn,
        min_size=1, max_size=3, increment=1,
    )
    tasks = []
    try:
        async_profile = await select_ai.AsyncProfile(
            profile_name="async_oci_ai_profile",
        )
        # Each operation acquires its own connection from the pool.
        tasks = [
            asyncio.create_task(async_profile.show_sql("How many customers?")),
            asyncio.create_task(async_profile.run_sql("How many promotions?")),
            asyncio.create_task(async_profile.explain_sql("How many promotions?")),
        ]
        for task in asyncio.as_completed(tasks):
            print(await task)
    finally:
        # Finish cancellation before closing connections, including on errors.
        for task in tasks:
            if not task.done():
                task.cancel()
        await asyncio.gather(*tasks, return_exceptions=True)
        await select_ai.async_disconnect()


asyncio.run(main())

output:

SELECT COUNT("c"."CUST_ID") AS "customer_count" FROM "SH"."CUSTOMERS" "c"

To answer the question "How many promotions", we need to write a SQL query that counts the number of rows in the "PROMOTIONS" table. Here is the query:

```sql
SELECT
  COUNT("p"."PROMO_ID") AS "number_of_promotions"
FROM
  "SH"."PROMOTIONS" "p";
```

Explanation:

* We use the `COUNT` function to count the number of rows in the table.
* We use the table alias `"p"` to refer to the `"PROMOTIONS"` table.
* We specify the schema name `"SH"` to ensure that we are accessing the correct table.
* We enclose the table name, schema name, and column name in double quotes to make them case-sensitive.
* The `AS` keyword is used to give an alias to the calculated column, in this case, `"number_of_promotions"`.

This query will return the total number of promotions in the `"PROMOTIONS"` table.

   PROMOTION_COUNT
0              503

2.12. Async chat

import asyncio
import os

import select_ai

user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")


async def main():
    await select_ai.async_connect(user=user, password=password, dsn=dsn)
    async_profile = await select_ai.AsyncProfile(
        profile_name="async_oci_ai_profile"
    )

    # Asynchronously send multiple chat prompts
    chat_tasks = [
        async_profile.chat(prompt="What is OCI ?"),
        async_profile.chat(prompt="What is OML4PY?"),
        async_profile.chat(prompt="What is Autonomous Database ?"),
    ]
    for chat_task in asyncio.as_completed(chat_tasks):
        result = await chat_task
        print(result)


asyncio.run(main())

output:

OCI stands for several things depending on the context:

1. **Oracle Cloud Infrastructure (OCI)**: This is a cloud computing service offered by Oracle Corporation. It provides a range of services including computing, storage, networking, database, and more, allowing businesses to build, deploy, and manage applications and services in a secure and scalable manner.

...
..
OML4PY provides a Python interface to OML, allowing users to create, manipulate, and analyze models using Python scripts. It enables users to leverage the power of OML and OMF from within Python, making it easier to integrate modeling and simulation into larger workflows and applications.
...
...

An Autonomous Database is a type of database that uses artificial intelligence (AI) and machine learning (ML) to automate many of the tasks typically performed by a database administrator (DBA)
...
...

2.13. Async streaming chat

import asyncio
import os

import select_ai

user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")


async def main():
    await select_ai.async_connect(user=user, password=password, dsn=dsn)
    async_profile = await select_ai.AsyncProfile(
        profile_name="async_oci_ai_profile"
    )

    chunks = await async_profile.chat(
        prompt="What is OCI ?", stream=True, chunk_size=4096
    )
    async for chunk in chunks:
        print(chunk, end="")
    print()


asyncio.run(main())

stream=True lets callers consume generated CLOB responses chunk by chunk, reducing memory pressure and making it easier to progressively forward output to files, services, or user interfaces. Async streaming text APIs return an async iterator of str chunks after the awaited method call. The chunk_size parameter controls the number of CLOB characters read per chunk; it is not a byte count.

Streaming is supported by generate(), chat(), narrate(), explain_sql(), show_sql(), and show_prompt(). It is not supported for run_sql(), which returns a pandas.DataFrame.

The SDK awaits the database function before reading its returned CLOB in chunks. The first chunk is available after that function returns; this does not guarantee token delivery while the model is generating. A partially consumed iterator retains its cursor and connection. Use aclosing() when iteration can stop early, and consume session streams before leaving the chat_session() context:

from contextlib import aclosing

chunks = await async_profile.chat("Explain connection pooling.", stream=True)
async with aclosing(chunks):
    async for chunk in chunks:
        print(chunk, end="")

2.14. Async request-level profile attribute overrides

The attributes keyword accepts a mapping of profile attributes to apply to one async request. These values override the corresponding saved profile attributes for that request only; they do not update the profile in the database. The mapping must contain JSON-serializable values.

Request-level attributes are available on the following asynchronous APIs:

  • AsyncProfile.generate(), chat(), and narrate().

  • SQL helpers: explain_sql(), run_sql(), show_sql(), and show_prompt().

  • AsyncSession.chat(), narrate(), explain_sql(), run_sql(), show_sql(), and show_prompt().

  • AsyncProfile.run_pipeline(), which applies the same mapping to every prompt/action request in the pipeline.

  • Streaming calls to the text-producing methods, by combining stream=True with attributes=.... run_sql() does not support streaming.

The mapping can include attributes such as additional_instructions, the integer seed, and source_language or target_language. Use ProfileAttributes for profile-wide defaults; use this mapping when an override should apply only to the current request.

For translate(), pass language values through its named source_language and target_language arguments. The attributes mapping described here applies to the generate/action APIs.

request_attributes = {
    "additional_instructions": "Answer in one sentence.",
    "seed": 42,
    "source_language": "en",
    "target_language": "de",
}

response = await async_profile.chat(
    prompt="What is Oracle Cloud Infrastructure?",
    attributes=request_attributes,
)

For async streaming, await the method call first and then iterate over the returned async iterator. The same mapping can be used with an async session:

chunks = await async_profile.chat(
    prompt="Summarize Oracle Cloud Infrastructure.",
    stream=True,
    attributes=request_attributes,
)
async for chunk in chunks:
    print(chunk, end="")

async with async_profile.chat_session(conversation) as session:
    response = await session.chat(
        prompt="Give one more detail.",
        attributes=request_attributes,
    )

The following sample uses show_prompt() to verify that the request-only additional_instructions value reached the generated prompt:


import asyncio
import os

import select_ai

user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")
profile_name = os.getenv("SELECT_AI_PROFILE_NAME", "async_oci_ai_profile")


async def main():
    await select_ai.async_connect(user=user, password=password, dsn=dsn)
    async_profile = await select_ai.AsyncProfile(profile_name=profile_name)

    instruction = "Include the exact marker PYSAI_REQUEST_ATTRIBUTES_SAMPLE."
    request_attributes = {
        "additional_instructions": instruction,
        "seed": 42,
        "source_language": "en",
        "target_language": "de",
    }

    prompt = await async_profile.show_prompt(
        prompt="Tell me about Oracle Cloud Infrastructure.",
        attributes=request_attributes,
    )
    print("Request attributes applied:", instruction in prompt)


asyncio.run(main())

output:

Request attributes applied: True

2.15. Summarize

Summarize inline content

import asyncio
import os

import select_ai

user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")

content = """
A gas cloud in our galaxy, Sagittarius B2, contains enough alcohol to brew 400
trillion pints of beer, and some stars are so cool that you could touch them
without being burned. Meanwhile, on the exoplanet 55 Cancri e, a form of
"hot ice" exists where high pressure prevents water from becoming gas even at
high temperatures. Additionally, some ancient stars found in the Milky Way's
halo are much older than the Sun, providing clues about the early universe and
its composition
"""


async def main():
    await select_ai.async_connect(user=user, password=password, dsn=dsn)
    async_profile = await select_ai.AsyncProfile(
        profile_name="async_oci_ai_profile",
    )
    summary = await async_profile.summarize(content=content)
    print(summary)


asyncio.run(main())

output:

A gas cloud in the Sagittarius B2 galaxy contains a large amount of alcohol,
while some stars are cool enough to touch without being burned. The exoplanet
55 Cancri e has a unique form of "hot ice" where water remains solid despite
high temperatures due to high pressure. Ancient stars in the Milky Way's halo
are older than the Sun, providing insights into the early universe and its composition,
offering clues about the universe's formation and evolution.

Summarize content accessible via a URL

import asyncio
import os

import select_ai

user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")


async def main():
    await select_ai.async_connect(user=user, password=password, dsn=dsn)
    async_profile = await select_ai.AsyncProfile(
        profile_name="async_oci_ai_profile",
    )
    summary = await async_profile.summarize(
        location_uri="https://en.wikipedia.org/wiki/Astronomy"
    )
    print(summary)


asyncio.run(main())

output:

Astronomy is a natural science that studies celestial objects and phenomena,
using mathematics, physics, and chemistry to explain their origin and evolution.
The field has a long history, with early civilizations making methodical
observations of the night sky, and has since split into observational and
theoretical branches. Observational astronomy focuses on acquiring data
from observations, while theoretical astronomy develops computer or
analytical models to describe astronomical objects and phenomena. The study
of astronomy has led to numerous discoveries, including the existence of
galaxies, the expansion of the universe, and the detection of gravitational
waves. Astronomers use various methods, such as radio, infrared, optical,
ultraviolet, X-ray, and gamma-ray astronomy, to study objects and events in
the universe. The field has also led to the development of new technologies and
has inspired new areas of research, such as astrobiology and the search for
extraterrestrial life. Overall, astronomy is a dynamic and constantly evolving
field that seeks to understand the universe and its many mysteries.

2.16. Translate

AsyncProfile.translate() accepts optional source_language and target_language arguments. Per-call values take precedence over the profile’s source_language and target_language defaults.

If source_language is omitted for both the call and the profile, source language detection is delegated to the translation provider. If target_language is omitted, the profile’s default is used; a target language must be supplied in one of those two places.

Configure profile-level defaults with ProfileAttributes when creating or updating a profile:

language_defaults = select_ai.ProfileAttributes(
    source_language="en",
    target_language="de",
)

await async_profile.set_attributes(language_defaults)
print(await async_profile.translate(text="Thank you"))

When only the target is supplied at the call site, the provider can detect the source language:

print(await async_profile.translate(text="Thank you", target_language="de"))
import asyncio
import os

import select_ai

user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")
profile_name = os.getenv("SELECT_AI_PROFILE_NAME", "async_oci_ai_profile")


async def main():
    await select_ai.async_connect(user=user, password=password, dsn=dsn)
    async_profile = await select_ai.AsyncProfile(
        profile_name=profile_name,
    )
    response = await async_profile.translate(
        text="Thank you",
        target_language="de",
    )
    print(response)


asyncio.run(main())

output:

Danke

2.17. Async pipeline

2.17.1. Pipeline compatibility and results

run_pipeline() requires python-oracledb>=2.4.0, which provides create_pipeline() and AsyncConnection.run_pipeline(). If an older driver lacks these APIs, upgrade it with python -m pip install --upgrade oracledb. Async operations use Thin mode.

The driver documents true pipelining for Oracle AI Database 26ai and later. On older databases it executes operations individually, without reducing round trips. Pipeline operations execute sequentially, even when true pipelining is available. Select AI returns CLOBs, and reading these adds database calls; do not assume the complete SDK operation uses one round trip. See python-oracledb pipelining.

Results preserve input order. Successful results are strings read from CLOBs. For Action.RUNSQL, this is the database’s JSON response, rather than the pandas.DataFrame returned by AsyncProfile.run_sql(). With continue_on_error=False (the default), an operation error raises an exception. With continue_on_error=True, failed entries contain driver error objects; check their type before using them as text:

results = await async_profile.run_pipeline(
    [("How many promotions?", select_ai.Action.SHOWSQL)],
    continue_on_error=True,
)
for result in results:
    if isinstance(result, str):
        print(result)
    else:
        print(f"Pipeline operation failed: {result}")

AsyncProfile.run_pipeline() also accepts attributes=.... The mapping is applied to every prompt/action request in the pipeline, while the saved profile remains unchanged.

results = await async_profile.run_pipeline(
    prompt_specifications,
    attributes={
        "additional_instructions": "Keep each answer concise.",
        "seed": 42,
    },
)
import asyncio
import os

import select_ai

user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")


async def main():
    await select_ai.async_connect(user=user, password=password, dsn=dsn)
    async_profile = await select_ai.AsyncProfile(
        profile_name="async_oci_ai_profile"
    )
    prompt_specifications = [
        ("What is Oracle Autonomous Database?", select_ai.Action.CHAT),
        ("Generate SQL to list all customers?", select_ai.Action.SHOWSQL),
        (
            "Explain the query: SELECT * FROM sh.products",
            select_ai.Action.EXPLAINSQL,
        ),
        ("Explain the query: SELECT * FROM sh.products", "INVALID ACTION"),
    ]

    # Operations execute sequentially; round-trip savings depend on the
    # database version. Successful results are strings, including RUNSQL JSON.
    results = await async_profile.run_pipeline(
        prompt_specifications, continue_on_error=True
    )
    for i, result in enumerate(results):
        print(
            f"Result {i} for prompt '{prompt_specifications[i][0]}' is: {result}"
        )


asyncio.run(main())

output:

Result 0 for prompt 'What is Oracle Autonomous Database?' is: Oracle Autonomous Database is a cloud-based database service that uses artificial intelligence (AI) and machine learning (ML) to automate many of the tasks associated with managing a database. It is a self-driving, self-securing, and self-repairing database that eliminates the need for manual database administration, allowing users to focus on higher-level tasks.


Result 1 for prompt 'Generate SQL to list all customers?' is: SELECT "c"."CUST_ID" AS "Customer ID", "c"."CUST_FIRST_NAME" AS "First Name", "c"."CUST_LAST_NAME" AS "Last Name", "c"."CUST_EMAIL" AS "Email" FROM "SH"."CUSTOMERS" "c"

Result 2 for prompt 'Explain the query: SELECT * FROM sh.products' is: ```sql
SELECT
  p.*
FROM
  "SH"."PRODUCTS" p;
```

**Explanation:**

This query is designed to retrieve all columns (`*`) from the `"SH"."PRODUCTS"` table.

Here's a breakdown of the query components:


Result 3 for prompt 'Explain the query: SELECT * FROM sh.products' is: ORA-20000: Invalid action - INVALID ACTION

2.18. Share a profile asynchronously

While connected as the profile owner, grant access to an existing profile:

profile = await select_ai.AsyncProfile.fetch("OCI_AI_PROFILE")
await profile.grant_access("APP_USER")

The recipient can fetch the profile with owner="APP_OWNER" in a separate connection. When access should end, run await profile.revoke_access("APP_USER") as the owner. See Sharing and ownership for the complete owner and recipient sequence.

2.19. Give async feedback on generated SQL

Use feedback after reviewing the SQL produced for a prompt. Identify the request with a (prompt, Action) tuple or a sql_id from V$MAPPED_SQL. The example below assumes an open async connection and an existing profile over the SH schema:

profile = await select_ai.AsyncProfile.fetch("OCI_AI_PROFILE")
prompt = "How many promotions?"
sql = await profile.show_sql(prompt=prompt)
print(sql)

After inspecting the SQL, record positive feedback if it answers the question:

await profile.add_positive_feedback(
    prompt_spec=(prompt, select_ai.Action.SHOWSQL)
)

For an incorrect answer, use add_negative_feedback() with the same request identifier, response containing the expected SQL, and feedback_content explaining the correction. Remove obsolete feedback with delete_feedback() and the same request identifier. Await these methods when using AsyncProfile.

2.20. List profiles asynchronously

Use AsyncProfile.list() to discover saved profiles in the current schema. Call it on the class; you do not need to create an empty profile first. Each returned object includes profile_name, owner, and the owner-qualified qualified_name.

2.20.1. Connect and list your profiles

Set SELECT_AI_USER, SELECT_AI_PASSWORD, and SELECT_AI_DB_CONNECT_STRING before running this complete script. It prints one qualified name per profile and closes the connection afterward:

import asyncio
import os

import select_ai


async def main():
    await select_ai.async_connect(
        user=os.environ["SELECT_AI_USER"],
        password=os.environ["SELECT_AI_PASSWORD"],
        dsn=os.environ["SELECT_AI_DB_CONNECT_STRING"],
    )
    try:
        async for profile in select_ai.AsyncProfile.list():
            print(profile.qualified_name)
    finally:
        await select_ai.async_disconnect()


asyncio.run(main())

For a schema named APP_OWNER containing two profiles, the output could be:

APP_OWNER.OCI_AI_PROFILE
APP_OWNER.OCI_VECTOR_AI_PROFILE

Your results depend on the profiles visible in your schema; result order is not guaranteed. An empty result means no profiles match the requested scope.

2.20.2. Filter by name

With a connection open, use profile_name_pattern to match names with a regular expression. This example lists names starting with OCI_:

async for profile in select_ai.AsyncProfile.list(profile_name_pattern="^OCI_"):
    print(profile.qualified_name)

AsyncProfile.list() returns an async iterator. Use async for directly; do not await the iterator. Put these snippets inside your async function before disconnecting.

2.20.3. Find and reuse a shared profile

Pass owner to list profiles in another schema. The connected user must have access to those profiles; specifying an owner does not grant access. While connected as the recipient, list the profiles shared by APP_OWNER:

async for profile in select_ai.AsyncProfile.list(owner="APP_OWNER"):
    print(profile.qualified_name)

Once you know the profile name, fetch that profile with the same owner and use the returned object directly:

profile = await select_ai.AsyncProfile.fetch(
    "OCI_AI_PROFILE", owner="APP_OWNER"
)
print(profile.qualified_name)  # APP_OWNER.OCI_AI_PROFILE
response = await profile.chat(prompt="What is retrieval augmented generation?")
print(response)

See Sharing and ownership for the owner’s grant and revoke steps.