SQL Plugin

Technical References

A PLugin that uses a remote SQL database server to retrieve its return data

Note

This is a complex AI resource that exists within the following class hierarchy

  1. Smarter Secret: The authentication credential for the remote SQL database connection.

  2. Smarter SQL Connection: The complete connection configuration to the remote SQL database server (host, port, secret, ssh key, username, etc.).

  3. Smarter SQL Plugin: The plugin that defines the SQL query and it’s parameters to run against the remote SQL database server.

  4. Smarter Chatbot: The prompting resource (Chatbot, Agent, Workflow unit, etcetera) that includes the SQL Plugin:

1.) Example Smarter Secret Manifest
apiVersion: smarter.sh/v1
kind: Secret
metadata:
  description: |
    An example secret manifest. This is a real credential used for authenticating to
    the Smarter Remote SQL test database. This is a public-access test database
    used for development and testing purposes only.  Do not use this credential
    for production purposes. Password value is the same as the user.
    See the annotations below for connection details.
  name: smarter_test_user
  version: 1.1.0
  tags:
    - example
    - test
    - stackademy
  annotations:
    - smarter.sh/test-db/host: sql.lawrencemcdaniel.com
    - smarter.sh/test-db/port: "3306"
    - smarter.sh/test-db/db: smarter_test_db
    - smarter.sh/test-db/user: smarter_test_user
    - smarter.sh/test-db/pwd: smarter_test_user
    - smarter.sh/test-db/access: anyone can access this test database
spec:
  config:
    description: smarter_test_user password. Password value is the same as the user.
    value: smarter_test_user
2.) Example Smarter SQL Connection Manifest
apiVersion: smarter.sh/v1
kind: SqlConnection
metadata:
  description: Sql database connection pwd for smarter_test_db at sql.lawrencemcdaniel.com:3306
  name: smarter_test_db
  tags:
    - test
    - sample
    - smarter
  annotations:
    - smarter.sh/smarter-test-db/owner: smarter-test-user
    - smarter.sh/smarter-test-db/creator: QA Team
    - smarter.sh/smarter-test-db/purpose: unit testing
    - smarter.sh/smarter-test-db/release-date: 2024-06-15
    - smarter.sh/smarter-test-db/backward-compatibility: true
  version: 0.1.0
spec:
  connection:
    authenticationMethod: tcpip
    database: smarter_test_db
    dbEngine: django.db.backends.mysql
    username: smarter_test_user
    hostname: sql.lawrencemcdaniel.com
    maxOverflow: 10
    password: smarter_test_user
    poolSize: 5
    port: 3306
    timeout: 30
    useSsl: false
3.) Example Stackademy SQL Plugin Manifest
apiVersion: smarter.sh/v1
kind: SqlPlugin
metadata:
  description: Online course catalogue inquiries for fictional Stackademy University that only offers computer science degrees programs.
  name: stackademy_sql
  pluginClass: sql
  version: 0.1.0
  tags:
    - db
    - sql
    - database
  annotations:
    - smarter.sh/stackademy-sql/display-name: Stackademy SQL
    - smarter.sh/stackademy-sql/icon: https://example.com/stackademy-sql-icon.png
    - smarter.sh/stackademy-sql/documentation-url: https://docs.stackademy.com/sql
    - smarter.sh/stackademy-sql/contact-email: no-reply@example.com
spec:
  selector:
    directive: always
  prompt:
    provider: openai
    systemRole: >
      You are a helpful student advisor at the fictional Stackademy University that only offers computer science
      degrees programs. Whenever possible you should defer to the tool calls provided for additional information
      about the courses offered by Stackademy University. Questions unrelated to the courses or Stackademy University
      should be answered with "I am sorry, but I can only provide information about the courses offered by Stackademy University."
    model: gpt-4o-mini
    temperature: 0.5
    maxTokens: 2048
  connection: smarter_test_db
  sqlData:
    description: >
      returns up to 10 rows of course detail data, filtered by the maximum cost a student is willing
      to pay for a course and the area of specialization.
    limit: 10
    sqlQuery: SELECT c.course_code, c.course_name, c.description, c.cost, prerequisite.course_code AS prerequisite_course_code, prerequisite.course_name AS prerequisite_course_name
      FROM courses c
      LEFT JOIN courses prerequisite ON c.prerequisite_id = prerequisite.course_id
      WHERE ((c.description LIKE CONCAT('%', {description}, '%')) OR ({description} IS NULL))
        AND (c.cost <= {max_cost} OR {max_cost} IS NULL)
      ORDER BY c.prerequisite_id;
    parameters:
    - description: the maximum cost that a student is willing to pay for a course.
      enum: null
      name: max_cost
      required: false
      type: number
    - description: areas of specialization for courses in the catalogue.
      enum:
      - AI
      - mobile
      - web
      - database
      - network
      - neural networks
      name: description
      required: false
      type: string
    testValues:
    - name: description
      value: AI
    - name: max_cost
      value: 500
4.) Example Stackademy Chatbot Manifest
apiVersion: smarter.sh/v1
kind: Chatbot
metadata:
  name: stackademy_sql
  description: Stackademy University course catalogue inquiries using the Stackademy SQL plugin.
  version: 1.0.0
  tags:
    - stackademy
    - sql
    - chatbot
  annotations:
    - smarter.sh/chatbot/stackademy-sql/creator: QA Team
    - smarter.sh/chatbot/stackademy-sql/purpose: chatbot for Stackademy course catalogue inquiries
    - smarter.sh/chatbot/stackademy-sql/release-date: 2024-06-15
    - smarter.sh/chatbot/stackademy-sql/backward-compatibility: true
    - smarter.sh/chatbot/stackademy-sql/note: |
        Uses SQL plugin to answer course catalogue questions.
        Very fast and accurate when the database is well-structured.
        Leverages cache for improved performance.
spec:
  config:
    deployed: false
    provider: openai
    defaultModel: gpt-4o-mini
    defaultSystemRole: >
      You are a helpful assistant. When given the opportunity to utilize
      function calling, you should always do so. This will allow you to
      provide the best possible responses to the user. DO NOT GUESS. IF
        YOU DON'T KNOW THE ANSWER, RESPOND THAT YOU DON'T KNOW.
    defaultTemperature: 0.5
    defaultMaxTokens: 1024
    appName: Stackademy SQL Chatbot
    appAssistant: Stanley
    appWelcomeMessage: Welcome to Stackademy SQL Chatbot! How can I help you today?
    appExamplePrompts:
      - "Do you offer any courses on AI?"
      - "My budget is $1,000. What courses can I take?"
      - "I want to study programming. What do you suggest?"
    appPlaceholder: "Ask me anything about Stackademy courses..."
    appInfoUrl: https://stackademy.edu/online-courses
  plugins:
    - stackademy_sql
  functions: []
exception smarter.apps.plugin.plugin.sql.SmarterSqlPluginError(message='')[source]

Bases: SmarterPluginError

Base class for all SQL plugin errors.

__init__(message='')
add_note(object, /)

Exception.add_note(note) – add a note to the exception

args
property get_formatted_err_message
with_traceback(object, /)

Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.

class smarter.apps.plugin.plugin.sql.SqlPlugin(*args, manifest=None, **kwargs)[source]

Bases: PluginBase

Implements a plugin that executes SQL queries on a remote SQL database server to retrieve data.

This class provides the logic for integrating SQL-based plugins into the Smarter platform. It supports manifest-driven configuration, parameter validation, and secure query execution. The plugin can be instantiated from either a manifest (Pydantic model) or an existing Django ORM instance.

Key Features:

  • Accepts plugin configuration via manifest or ORM model.

  • Validates and recasts parameter definitions to conform to OpenAI function calling schema.

  • Interpolates user-provided arguments into SQL queries, with basic escaping for safety.

  • Executes queries using a remote SQL connection and returns results in JSON format.

  • Handles errors related to configuration, connection, and query execution.

  • Provides example manifest generation for testing and documentation.

Usage:

  • Instantiate with a manifest or ORM model.

  • Use tool_call_fetch_plugin_response() to execute SQL queries with arguments from OpenAI tool calls.

  • Use plugin_data_django_model to convert manifest data to a Django ORM-compatible dictionary.

  • Use example_manifest() to generate a sample manifest for this plugin type.

Note

  • SQL queries are interpolated using simple string replacement; ensure queries are safe and parameterized.

  • The maximum query length is limited to prevent excessive database load.

  • Logging is controlled via feature switches and log level settings.

See also

SAMPluginType

alias of SAMSqlPlugin

__init__(*args, manifest=None, **kwargs)[source]

Initialize a PluginBase instance.

Key features:

  • Lazy instantiation of class properties.

  • Supports multiple initialization methods including manifest, database model, and YAML/JSON.

  • Integrates with Django ORM for plugin metadata management.

  • Utilizes Pydantic models for manifest validation and serialization.

  • Provides hooks for plugin selection and prompt customization.

  • Ensures plugin readiness and validation before use.

  • Sends signals upon plugin creation or update.

This constructor supports several ways to create a plugin object:

  • Manifest-based initialization:

    Pass a Pydantic model instance via the manifest argument. This is the preferred method and is typically used when loading plugins from a manifest broker.

  • Database model initialization:

    Provide a Django model plugin ID via plugin_id or a PluginMeta instance via plugin_meta to load an existing plugin from the database.

  • YAML/JSON manifest initialization:

    Supply a YAML or JSON string (or dictionary) via the data argument to create a plugin from a manifest representation.

See ./data/sample-plugins/everlasting-gobstopper.yaml for an example manifest.

The constructor sets up internal state, initializes plugin properties, and triggers plugin creation or update logic as needed. It also sends signals when the plugin is ready.

Parameters:
  • user_profile (Optional[UserProfile]) – The user profile associated with the plugin.

  • selected (bool) – Whether the plugin is initially selected.

  • api_version (Optional[str]) – The API version for the plugin manifest.

  • manifest (Optional[SAMPluginCommon]) – A Pydantic model representing the plugin manifest.

  • plugin_id (Optional[int]) – The Django ORM plugin ID.

  • plugin_meta (Optional[PluginMeta]) – The Django ORM PluginMeta instance.

  • data (Union[dict[str, Any], str, None]) – YAML/JSON manifest as a string or dictionary.

  • name (Optional[str]) – The name of the plugin.

  • kwargs – Additional keyword arguments.

property account: Account | None

Returns the account for the current user. Handle lazy instantiation from user or user_profile.

Returns:

The account for the current user.

Return type:

Account or None

property account_mixin_logger_prefix: str

Returns the logger prefix for the class.

property account_number: str | None

A helper function to get the account number from the account.

Returns:

The account number for the current account.

Return type:

str or None

property accountmixin_ready_state: str

Returns a string representation of the AccountMixin ready state.

Returns:

String representation of the AccountMixin ready state.

Return type:

str

property amnesty_urls: list[str]

Returns a list of URLs that are exempt from certain checks.

This is a placeholder and should be overridden in subclasses.

Returns:

List of URL path strings that are exempt.

Return type:

list[str]

property api_version: str

Return the api version of the plugin.

Returns:

The api version of the plugin.

Return type:

str

Raises:

SAMValidationError – If the api version is not valid.

See also

  • smarter.common.api.SmarterApiVersions

  • SMARTER_API_MANIFEST_COMPATIBILITY

authenticate(api_token)

Authenticate the user using the provided API token. The api_token will have been generated by the SmarterTokenAuthentication class and passed by the caller in the Authorization header of the request.

Example

Authorization: Token <api_token>

Parameters:

api_token (bytes) – The API token to authenticate with.

Returns:

True if authentication was successful, False otherwise.

Return type:

bool

cache_invalidations()

Invalidate cached properties related to the plugin.

This method is used to clear any cached data associated with the plugin instance, such as cached Django ORM model instances or serializers. It ensures that subsequent accesses to these properties will fetch fresh data from the database or re-instantiate serializers as needed.

The following properties are invalidated:

  • user_profile

  • plugin_meta

  • plugin_selector

  • plugin_prompt

  • plugin_data

Return type:

None

camel_to_snake(data)

Converts camelCase strings, dictionary keys, or lists of such, to snake_case format.

Parameters:

data (str, dict, or list) – The input to convert. Can be a string, a dictionary (with camelCase keys), or a list containing strings or dictionaries.

Returns:

The converted data in snake_case format. Returns a string, dictionary, or list, matching the input type.

Return type:

Optional[Union[str, dict, list]]

Note

  • For dictionaries, only keys are converted. Values are preserved as-is, except for nested dictionaries, which are also converted.

  • Spaces in keys are replaced with underscores.

  • Multiple consecutive underscores are collapsed into a single underscore.

  • Nested dictionaries and lists are processed recursively.

Warning

If the input is not a string, dictionary, or list, a SmarterValueError is raised.

Example usage:

from smarter.common.utils import camel_to_snake

# Convert a string
print(camel_to_snake("userName"))  # Output: user_name

# Convert a dictionary
data = {
    "userName": "alice",
    "userProfile": {
        "firstName": "Alice",
        "lastName": "Smith"
    }
}
print(camel_to_snake(data))
# Output: {'user_name': 'alice', 'user_profile': {'first_name': 'Alice', 'last_name': 'Smith'}}

# Convert a list of strings
print(camel_to_snake(["firstName", "lastName"]))
# Output: ['first_name', 'last_name']
clone(new_name=None)

Clone a plugin.

Parameters:

new_name (Optional[str]) – The new name for the cloned plugin. If None, a name will be generated.

Returns:

The id of the cloned plugin if successful, False otherwise.

Return type:

Optional[int]

Raises:

SmarterPluginError – If the plugin is not ready.

create()[source]

Create the plugin in the database.

This method handles the creation of the SQL plugin in the database by invoking the superclass’s create method. It ensures that all necessary data is properly initialized and stored according to the plugin’s configuration.

Note

This method currently does not implement any additional logic beyond calling the superclass’s create method.

Returns:

None

Return type:

None

property custom_tool: dict[str, Any]

Return the plugin tool definition for OpenAI function calling.

See the OpenAI documentation: https://platform.openai.com/docs/assistants/tools/function-calling/quickstart

Example:

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_current_temperature",
            "description": "Get the current temperature for a specific location",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "The city and state, e.g., San Francisco, CA"
                    },
                    "unit": {
                        "type": "string",
                        "enum": ["Celsius", "Fahrenheit"],
                        "description": "The temperature unit to use. Infer this from the user's location."
                    }
                },
                "required": ["location", "unit"]
            }
        }
    }
]

See also

  • smarter.lib.openai.enum.OpenAIToolCall

  • smarter.lib.openai.enum.OpenAIToolTypes

customize_prompt(messages)

Modify the system prompt based on the plugin object.

Parameters:

messages (list[dict]) – The list of messages to customize.

Returns:

The customized list of messages.

Return type:

list[dict]

property data: dict | None

Return the plugin as a dictionary.

Returns:

The plugin as a dictionary if ready, None otherwise.

Return type:

Optional[dict]

data_to_dict(data)

Converts data to a dictionary, handling different types of input.

This method accepts either a dictionary or a string. If a string is provided, it will attempt to parse it as JSON first, and if that fails, as YAML. If parsing fails or the data type is unsupported, a SmarterValueError is raised.

Parameters:

data (dict or str) – The data to convert, either a dict or a JSON/YAML string.

Returns:

The data as a dictionary.

Return type:

dict

Raises:

SmarterValueError – If the data cannot be converted to a dictionary.

delete()

Delete a plugin.

Returns:

True if the plugin was deleted successfully, False otherwise.

Return type:

bool

Raises:

SmarterPluginError – If the plugin is not ready.

classmethod example_manifest(kwargs=None)[source]

Use Pydantic models to generate an example manifest for SqlPlugin.

This class method creates a sample manifest dictionary for the SqlPlugin, illustrating the required structure and fields. The example manifest includes metadata, specification, and SQL query details, demonstrating how to configure the plugin for use within the Smarter platform.

Parameters:

kwargs (Optional[dict]) – Optional dictionary of additional fields to include in the manifest.

Returns:

A dictionary representing the example manifest for the SqlPlugin.

Return type:

dict

See Also:

  • smarter.lib.manifest.enum.SAMKeys

  • smarter.lib.manifest.enum.SAMMetadataKeys

  • smarter.apps.plugin.manifest.models.sql_plugin.model.SAMSqlPlugin

  • smarter.apps.plugin.manifest.models.common.plugin.enum.SAMPluginCommonMetadataClassValues

  • smarter.apps.plugin.manifest.models.common.plugin.enum.SAMPluginCommonSpecSelectorKeyDirectiveValues

  • smarter.apps.plugin.manifest.models.common.plugin.enum.SAMPluginCommonSpecPromptKeys

property formatted_class_name: str

Returns the class name in a formatted string along with the name of this mixin.

property formatted_pluginbase_class_name: str

Return the formatted class name for logging.

Returns:

The formatted class name.

Return type:

str

property formatted_state_not_ready: str

Returns the not-ready state formatted for logging.

Returns:

The formatted not-ready state as a string.

Return type:

str

property formatted_state_ready: str

Returns the readiness state formatted for logging.

Returns:

The formatted readiness state as a string.

Return type:

str

property function_calling_identifier: str

Return the function calling plugin.

Returns:

The function calling plugin identifier.

Return type:

str

Raises:

SmarterPluginError – If the plugin is not ready.

property function_parameters: dict[str, Any] | None

Fetch the function parameters from the Django model. Return the function parameters in a dictionary formatted according to the OpenAI function calling schema.

Returns:

The function parameters as a dictionary.

Return type:

Optional[dict[str, Any]]

property id: int | None

Return the Django ORM PluginMeta id.

Returns:

The id of the plugin.

Return type:

Optional[int]

property is_accountmixin_ready: bool

Returns True if the AccountMixin is ready to be used. This is a convenience property that checks if the account and user are initialized. AccountMixin is considered ready if: - self.user is an instance of User - self.user_profile is an instance of UserProfile - self.account is an instance of Account

Returns:

True if the AccountMixin is ready to be used.

Return type:

bool

property is_authenticated: bool

Returns True if the user is authenticated and is associated with an Account.

is_valid_yaml(data)

Validate a yaml string.

Parameters:

data (str) – The yaml string to validate.

Returns:

True if the yaml string is valid, False otherwise.

Return type:

bool

property kind: str

Returns the kind identifier for this plugin.

This property provides the canonical string used to distinguish the plugin type within the Smarter platform. The value is derived from the plugin manifest constant and is used for registration, serialization, and manifest validation.

The kind is typically referenced in plugin manifests and API payloads to ensure the correct plugin logic is invoked for SQL-based plugins.

Returns:

The string identifier representing the plugin kind.

Return type:

str

Example:
>>> plugin = SqlPlugin()
>>> plugin.kind
'sql'
log_account_mixin_ready_status()

Logs the ready status of the AccountMixin.

property manifest: SAMSqlPlugin | None

Retrieve the manifest for this plugin as a Pydantic model.

This property returns the plugin’s manifest, which contains the configuration and specification for the SQL plugin in the form of a validated Pydantic model. If the manifest is not already set and the plugin is ready, it will be constructed from the current plugin data using the appropriate Pydantic model class.

The manifest is essential for validating plugin configuration, generating OpenAI-compatible schemas, and ensuring the plugin operates with the correct parameters and metadata.

Returns:

The manifest as a SAMSqlPlugin Pydantic model instance, or None if unavailable.

Return type:

Optional[SAMSqlPlugin]

Note

If the manifest is not present but the plugin is ready, this property will attempt to reconstruct the manifest from the plugin’s JSON representation.

Example:
>>> plugin = SqlPlugin()
>>> manifest = plugin.manifest
>>> print(manifest.spec.sqlData.sql_query)
SELECT * FROM auth_user WHERE username = '{username}';
mask_string(string='', mask_char='*', mask_length=4, string_length=8)

Masks a string for secure logging.

This utility function masks all but the last unmasked_chars characters of the input string, replacing them with asterisks. It is useful for logging sensitive information like API keys or passwords.

Parameters:
  • string (str) – The string to be masked.

  • mask_char (str) – The character used for masking.

  • mask_length (int) – The number of characters to mask.

  • string_length (int) – The length of the string to consider for masking.

Returns:

The masked string.

Return type:

str

property metadata_class: str | None

Return the metadata class, PluginMeta.plugin_class

Returns:

The metadata class name.

Return type:

Optional[str]

See also:

  • smarter.apps.plugin.models.PluginMeta

property name: str | None

Return the name of the plugin.

Returns:

The name of the plugin.

Return type:

Optional[str]

Raises:

SmarterPluginError – If the PluginMeta is not of the expected type.

classmethod parameter_factory(name, data_type, description, enum=None, required=False, default=None)

Factory method to create a parameter dictionary for the SQL plugin.

Parameters:
  • name (str) – The name of the parameter.

  • data_type (str) – The data type of the parameter.

  • description (str) – The description of the parameter.

  • enum (Optional[list]) – An optional list of enumerated values for the parameter.

  • required (Optional[bool]) – Whether the parameter is required. Default is False.

  • default (Optional[Any]) – The default value of the parameter. Default is None.

Returns:

A dictionary representing the parameter.

Return type:

dict[str, Any]

property params: dict[str, Any] | None

Return the plugin parameters.

Returns:

The plugin parameters.

Return type:

Optional[dict[str, Any]]

Example:

`python foo = MyPlugin() print(foo.params) {"key": "value"} `

pascal_to_snake(name)

Converts a PascalCase string to pascal_case snake_case format.

Parameters:

name (str) – The PascalCase string to convert.

Returns:

The converted string in snake_case format.

Return type:

str

Note

  • Spaces in the input string are replaced with underscores.

  • Multiple consecutive underscores are collapsed into a single underscore.

Example usage:

from smarter.common.utils import pascal_to_snake

print(pascal_to_snake("UserProfile"))  # Output: user_profile
print(pascal_to_snake("FirstName LastName"))  # Output: first_name_last_name
property plugin_data: PluginDataSql | None

Return the plugin data as a Django ORM instance.

This property provides access to the plugin’s data in the form of a Django ORM model instance. It handles multiple scenarios for retrieving or constructing the plugin data:

  • If the plugin data has already been set, it is returned directly.

  • If both a manifest and plugin metadata are present, the plugin data is constructed from the manifest and metadata.

  • If only plugin metadata is present, the plugin data is retrieved from the database using the metadata.

  • If neither is available, the property returns None.

This logic ensures that the plugin data is always consistent with the current manifest and database state, supporting both creation and update workflows.

Returns:

The plugin data as a PluginDataSql Django ORM instance, or None if unavailable.

Return type:

Optional[PluginDataSql]

Raises:

PluginDataSql.DoesNotExist – If the plugin metadata is present but no corresponding database entry exists.

Note

This property does not create new database entries; it only retrieves or constructs plugin data based on existing manifest and metadata.

Example:
>>> plugin = SqlPlugin()
>>> data = plugin.plugin_data
>>> print(data.sql_query)
SELECT * FROM auth_user WHERE username = '{username}';
property plugin_data_class: Type[PluginDataSql]

Return the Django ORM model class used for plugin data.

This property provides the class reference for the Django model that stores SQL plugin data in the Smarter platform. It is useful for type checking, serialization, and for constructing new instances of plugin data objects.

The returned class can be used to create, query, or update plugin data records in the database. This is especially relevant when integrating with Django’s ORM or when performing migrations and schema validation.

Returns:

The Django ORM model class for SQL plugin data.

Return type:

Type[PluginDataSql]

Example:
>>> plugin = SqlPlugin()
>>> model_cls = plugin.plugin_data_class
>>> isinstance(model_cls(), PluginDataSql)
True
property plugin_data_django_model: dict[str, Any] | None

Transform the Pydantic model to the PluginDataSql Django ORM model and return the plugin data definition as a JSON object.

See the OpenAI documentation: https://platform.openai.com/docs/guides/function-calling?api-mode=chat

The Pydantic ‘Parameters’ model is not directly compatible with OpenAI’s function calling schema, and our Django ORM model expects a dictionary format for the parameters. This method converts the Pydantic model to a dictionary suitable for creating a Django ORM model instance.

Raises:
  • SmarterSqlPluginError – If the plugin manifest or SQL data is missing or invalid.

  • SmarterConfigurationError – If the parameters are not in the expected format.

Returns:

A dictionary representing the PluginDataSql Django ORM model.

Return type:

Optional[dict[str, Any]]

Example of a correctly formatted dictionary:

{
    "properties": {
        "location": {
            "type": "string",
            "description": "The city and state, e.g., San Francisco, CA"
        },
        "unit": {
            "type": "string",
            "enum": ["Celsius", "Fahrenheit"],
            "description": "The temperature unit to use. Infer this from the user's location."
        }
    },
    "required": ["location", "unit"]
}

Example of a Pydantic model:

[
    {
        "name": "max_cost",
        "type": "float",
        "description": "the maximum cost that a student is willing to pay for a course.",
        "required": False,
        "enum": None,
        "default": None
    },
    {
        "name": "description",
        "type": "string",
        "description": "areas of specialization for courses in the catalogue.",
        "required": False,
        "enum": ["AI", "mobile", "web", "database", "network", "neural networks"],
        "default": None
    }
]
spec:
    selector:
        directive: search_terms
        searchTerms:
        - admin
        - Smarter platform
        - admin account
    prompt:
        provider: openai
        systemRole: >
        You are a helpful assistant for Smarter platform. You can provide information about the admin account of the Smarter platform.
        model: gpt-4o-mini
        temperature: 0.0
        maxTokens: 256
    connection: test_sql_connection
    sqlData:
        sqlQuery: >
        SELECT * FROM auth_user WHERE username = '{username}';
        parameters:
        - name: username
            type: string
            description: The username to query.
            required: true
            default: admin
        - name: unit
            type: string
            enum:
            - Celsius
            - Fahrenheit
            description: The temperature unit to use.
            required: false
            default: Celsius
        testValues:
        - name: username
            value: admin
        - name: unit
            value: Celsius
        limit: 10
property plugin_data_serializer: PluginSqlSerializer | None

Return the serializer instance for plugin data.

This property provides a serializer object for the SQL plugin’s data, allowing conversion between Django ORM model instances and JSON-compatible representations. The serializer is used for validating, serializing, and deserializing plugin data, especially when preparing data for API responses or manifest generation.

If the serializer has not yet been instantiated, it will be created using the current plugin data. This ensures that the serializer always reflects the latest state of the plugin’s data.

Returns:

An instance of PluginSqlSerializer for the plugin data, or None if plugin data is unavailable.

Return type:

Optional[PluginSqlSerializer]

Example:
>>> plugin = SqlPlugin()
>>> serializer = plugin.plugin_data_serializer
>>> print(serializer.data)
{'sql_query': "SELECT * FROM auth_user WHERE username = '{username}';", ...}
property plugin_data_serializer_class: Type[PluginSqlSerializer]

Return the serializer class used for SQL plugin data.

This property provides the class reference for the serializer that is responsible for converting SQL plugin data between Django ORM model instances and JSON-compatible representations. The serializer class is essential for validation, serialization, and deserialization of plugin data, especially when integrating with APIs or generating manifests.

Use this property when you need to instantiate a new serializer for SQL plugin data, perform type checks, or access serializer-specific methods and attributes.

Returns:

The serializer class for SQL plugin data.

Return type:

Type[PluginSqlSerializer]

Example:
>>> plugin = SqlPlugin()
>>> serializer_cls = plugin.plugin_data_serializer_class
>>> serializer = serializer_cls(plugin.plugin_data)
>>> isinstance(serializer, PluginSqlSerializer)
True
property plugin_meta: PluginMeta | None

Return the plugin meta.

Returns:

The plugin meta.

Return type:

Optional[PluginMeta]

Note

This property will attempt to load the PluginMeta from the database if it has not already been set and if the UserProfile and manifest are available.

property plugin_meta_django_model: dict[str, Any] | None

Return a dict for loading the plugin meta Django ORM model.

Returns:

The plugin meta definition as a json object.

Return type:

Optional[dict[str, Any]]

property plugin_meta_serializer: PluginMetaSerializer | None

Return the plugin meta serializer.

Returns:

The plugin meta serializer.

Return type:

Optional[PluginMetaSerializer]

property plugin_prompt: PluginPrompt | None

Return the plugin prompt.

Returns:

The plugin prompt.

Return type:

PluginPrompt

Raises:

SmarterPluginError – If the PluginPrompt does not exist.

property plugin_prompt_django_model: dict[str, Any] | None

Return the plugin prompt definition as a json object that can be used to load the Django ORM model.

Returns:

The plugin prompt definition as a dictionary.

Return type:

Optional[dict[str, Any]]

property plugin_prompt_serializer: PluginPromptSerializer | None

Return the plugin prompt serializer.

Returns:

The plugin prompt serializer.

Return type:

Optional[PluginPromptSerializer]

property plugin_selector: PluginSelector | None

Return the plugin selector.

Returns:

The plugin selector.

Return type:

Optional[PluginSelector]

property plugin_selector_django_model: dict[str, Any] | None

Return the plugin selector definition as a json object.

Returns:

The plugin selector definition as a dictionary.

Return type:

Optional[dict[str, Any]]

property plugin_selector_history: QuerySet | None

Return the plugin selector history serializer.

Returns:

The plugin selector history queryset.

Return type:

Optional[QuerySet]

property plugin_selector_serializer: PluginSelectorSerializer | None

Return the plugin selector serializer.

Returns:

The plugin selector serializer.

Return type:

Optional[PluginSelectorSerializer]

property ready: bool

Return whether the plugin is ready.

Returns:

True if the plugin is ready, False otherwise.

Return type:

bool

Raises:

SmarterPluginError – If the UserProfile is not set or if any of the plugin components are not of the expected type.

property ready_state: str

Returns a string representation of the ready state.

refresh()

Refresh the plugin.

Returns:

True if the plugin is ready after refresh, False otherwise.

Return type:

bool

reinitialize_plugin()

Reset all plugin-related properties to None.

This method is used to clear the internal state of the plugin instance, including all cached references to Django ORM models, serializers, and other plugin-specific objects. It is typically called during initialization or when reloading a plugin to ensure that no stale data remains.

The following attributes are reset:

  • _plugin_meta: The plugin metadata model instance.

  • _plugin_selector: The plugin selector model instance.

  • _plugin_prompt: The plugin prompt model instance.

  • _plugin_selector_history: The queryset for selector history.

  • _plugin_data: The plugin data model instance.

  • _plugin_prompt_serializer: The serializer for the plugin prompt.

  • _plugin_selector_serializer: The serializer for the plugin selector.

  • _plugin_meta_serializer: The serializer for the plugin metadata.

This ensures that subsequent operations on the plugin will re-fetch or re-create these objects as needed, avoiding issues with outdated or invalid references.

rfc1034_compliant_str(val)

Generates a RFC 1034-compliant name string suitable for use as a DNS label or resource identifier.

Parameters:

val (str) – The input string to convert to RFC 1034-compliant format.

Returns:

A string that is: - lower case - contains only alphanumeric characters and hyphens - starts and ends with an alphanumeric character - has a maximum length of 63 characters

Return type:

str

Raises:

SmarterValueError – If the input is not a string or is empty after conversion.

Note

  • Underscores in the input are replaced with hyphens.

  • Invalid characters (anything other than a-z, 0-9, or ‘-’) are removed.

  • Leading and trailing hyphens are stripped.

  • The result is truncated to 63 characters if necessary.

Warning

This function is intended for generating DNS-safe names. It does not guarantee uniqueness or suitability for all RFC 1034 use cases.

Example usage:

from smarter.common.utils import rfc1034_compliant_str

# Basic usage
print(rfc1034_compliant_str("My_ChatBot_2025"))  # Output: my-chatbot-2025

# With special characters
print(rfc1034_compliant_str("My@Bot!_Name"))  # Output: my-bot-name

# With long input
long_name = "ThisIsAReallyLongChatBotNameThatShouldBeTruncatedToSixtyThreeCharacters_Extra"
print(rfc1034_compliant_str(long_name))  # Output: thisisareallylongchatbotnamethatshouldbetruncatedtosixtythreecharacters
rfc1034_compliant_to_snake(val)

Converts a RFC 1034-compliant name (typically used for DNS labels or resource identifiers) to a more human-readable snake_case name.

This function is useful for translating machine-friendly names (which use hyphens as word separators) into Pythonic identifiers (which use underscores).

Parameters:

val (str) – The RFC 1034-compliant name to convert. This should be a string containing only lowercase letters, numbers, and hyphens.

Returns:

The converted name in snake_case format, with hyphens replaced by underscores.

Return type:

str

Raises:

SmarterValueError – If the input is not a string.

Note

  • Only hyphens are replaced; other characters are preserved.

  • The function does not validate that the input is strictly RFC 1034-compliant. It assumes the input is already sanitized.

Warning

This function does not handle conversion of other non-alphanumeric characters. If the input contains characters other than hyphens, underscores, letters, or numbers, they will remain unchanged.

Example usage:

from smarter.common.utils import rfc1034_compliant_to_snake

# Basic conversion
print(rfc1034_compliant_to_snake("my-chatbot-2025"))
# Output: my_chatbot_2025

# Input with no hyphens
print(rfc1034_compliant_to_snake("simplelabel"))
# Output: simplelabel

# Input with multiple hyphens
print(rfc1034_compliant_to_snake("this-is-a-test-label"))
# Output: this_is_a_test_label

# Input with invalid type
try:
    rfc1034_compliant_to_snake(12345)
except SmarterValueError as e:
    print(e)
# Output: Could not convert RFC 1034 compliant name from <class 'int'>
save()

Save a plugin.

Returns:

True if the plugin was saved successfully, False otherwise.

Return type:

bool

Raises:

SmarterPluginError – If the plugin meta, selector, prompt, or data is not set or is not the correct instance.

selected(user, input_text=None, messages=None)

Determine whether the plugin should be selected for a given user and input context.

This method evaluates plugin selection logic based on the plugin’s selector directive, search terms, and optionally provided input text or message history. It supports both direct text matching and message-based matching, using the plugin’s configured search terms.

Selection is performed as follows:

  • If the plugin selector directive is set to ALWAYS, the plugin is automatically selected.

  • If input_text is provided, the method checks if any search term matches the input using the NLP utility does_refer_to. If a match is found, the plugin is selected and a signal is sent.

  • If messages are provided, the method iterates through user messages and checks for matches against the search terms. If a match is found, the plugin is selected and a signal is sent.

Signals:

  • plugin_selected is sent when the plugin is selected via either input text or messages.

Parameters:
  • user (User) – The user for whom selection is being evaluated.

  • input_text (Optional[str]) – Optional input text to check for search term matches.

  • messages (Optional[list[dict]]) – Optional list of message dictionaries to check for search term matches.

Returns:

True if the plugin is selected, False otherwise.

Return type:

bool

Note

This method requires the plugin to be ready. If the plugin is not ready, it will return False. The method also updates the internal _selected state when a match is found.

smarter_build_absolute_uri(request)

Attempts to get the absolute URI from a request object.

This utility function tries to retrieve the request URL from any valid child class of django.http.HttpRequest. It is especially useful in unit tests or scenarios where the request object may not implement build_absolute_uri().

Parameters:

request (Optional[HttpRequest]) – The request object.

Returns:

The absolute request URL.

Return type:

Optional[str]

Raises:

SmarterValueError – If the URI cannot be built from the request.

snake_to_camel(data, convert_values=False)

Converts snake_case strings, dictionary keys, or lists of such, to camelCase format.

Parameters:
  • data (str, dict, or list) – The input to convert. Can be a string, a dictionary (with snake_case keys), or a list containing strings or dictionaries.

  • convert_values (bool, optional) – If True, string values within dictionaries are also converted to camelCase. Default is False.

Returns:

The converted data in camelCase format. Returns a string, dictionary, or list, matching the input type.

Return type:

Optional[Union[str, dict, list]]

Note

  • For dictionaries, only keys are converted by default. If convert_values is set, string values are also converted.

  • Nested dictionaries and lists are processed recursively.

Warning

If the input is not a string, dictionary, or list, a SmarterValueError is raised.

Example usage:

from smarter.common.utils import snake_to_camel

# Convert a string
print(snake_to_camel("user_name"))  # Output: userName

# Convert a dictionary
data = {
    "user_name": "alice",
    "user_profile": {
        "first_name": "Alice",
        "last_name": "Smith"
    }
}
print(snake_to_camel(data))
# Output: {'userName': 'alice', 'userProfile': {'firstName': 'Alice', 'lastName': 'Smith'}}

# Convert a list of strings
print(snake_to_camel(["first_name", "last_name"]))
# Output: ['firstName', 'lastName']

# Convert values as well
data = {"user_name": "first_name"}
print(snake_to_camel(data, convert_values=True))
# Output: {'userName': 'firstName'}
sorted_dict(data)

Returns a new dictionary with keys sorted.

Parameters:

data (dict) – The dictionary to sort.

Returns:

A new dictionary with sorted keys.

Return type:

dict

to_json(version='v1')[source]

Serialize the SqlPlugin instance to a JSON-compatible dictionary suitable for Pydantic import.

This method transforms the plugin’s internal state, including its manifest and data, into a dictionary format that can be used to instantiate a Pydantic model. This is primarily used for rendering a plugin manifest for the Smarter API, enabling interoperability between Django ORM models and Pydantic schemas.

The output includes all relevant plugin fields, with the SQL data section populated from the plugin’s serializer. This ensures that the manifest is complete and conforms to the expected schema for API consumption or further validation.

Parameters:

version (str) – The API version to use for serialization. Only “v1” is supported.

Returns:

A dictionary representing the plugin in JSON format, or None if the plugin is not ready.

Return type:

Optional[dict[str, Any]]

Raises:

SmarterPluginError – If the plugin is not ready, the data is not a valid JSON object, or an unsupported version is specified.

Note:

The returned dictionary is structured for compatibility with Pydantic models and the Smarter API manifest specification. The SQL data is injected from the plugin’s serializer to ensure accurate representation.

Example:
>>> plugin = SqlPlugin()
>>> manifest_json = plugin.to_json()
>>> print(manifest_json["spec"]["sqlData"]["sql_query"])
SELECT * FROM auth_user WHERE username = '{username}';
tool_call_fetch_plugin_response(function_args)[source]

Fetch information from a Plugin object in response to an OpenAI API tool call.

This method processes the arguments received from an OpenAI function call, interpolates them into the SQL query, executes the query, and returns the result.

See the OpenAI documentation: https://platform.openai.com/docs/assistants/tools/function-calling/quickstart

Example tool call payload:

"tool_calls": [
    {
        "id": "call_1Ucn2R5WmBh7TtoE197SsP3p",
        "function": {
            "arguments": "{"description":"AI"}",  # these are the function_args
            "name": "smarter_plugin_0000004468"
        },
        "type": "function"
    }
]
Parameters:

function_args (Union[dict[str, Any], list]) – Arguments for the function call, as a dict, list, or JSON string.

Return type:

Union[str, dict, list, None]

Returns:

The result of the SQL query as a string, or an empty string if no results.

Raises:

SmarterSqlPluginError – If plugin data or SQL connection is invalid, or arguments are malformed.

property unformatted_class_name: str

Returns the raw class name without formatting.

Returns:

The unformatted class name as a string.

Return type:

str

This is useful for logging or serialization where the plain class name is needed.

update()

Update a plugin.

Returns:

True if the plugin was updated successfully, False otherwise.

Return type:

bool

Raises:

SmarterPluginError – If the plugin manifest is not set or the plugin does not exist.

property user: AnonymousUser | User | None

Returns the user for the current user. Handle lazy instantiation from user_profile or account.

Returns:

The user for the current user.

Return type:

User or None

property user_profile: UserProfile | None

Returns the user_profile for the current user. Handle lazy instantiation from user or account.

Returns:

The user_profile for the current user.

Return type:

UserProfile or None

property yaml: str

Return the plugin as a yaml string.

Returns:

The plugin as a yaml string.

Return type:

str

Raises:

SmarterPluginError – If the plugin is not ready.

yaml_to_json(yaml_string)

Convert a yaml string to a dictionary.

Parameters:

yaml_string (str) – The yaml string to convert.

Returns:

The converted dictionary.

Return type:

dict

Raises:

SmarterPluginError – If the yaml string is not valid.

smarter.apps.plugin.plugin.sql.should_log(level)[source]

Check if logging should be done based on the waffle switch.