API Contracts
smarter.models.chat
Models of the Smarter Chat api contract, version 2: an LLMClient’s configuration, its prompt api’s request and response, and the prompt’s progress events.
These mirror smarter.apps.prompt.contract.models in the Smarter platform, whose JSON Schema is
chat-contract.schema.json. The SDK always asks for version 2 of the contract (with the
X-Smarter-Capabilities: chat-contract-v2 request header), so the deprecated version 1 models are
not mirrored.
Two deliberate differences from the platform’s models, both so that an SDK keeps working when the platform is upgraded:
every model allows extra fields, including the models of Django rows, whose platform models forbid them, and
values that the platform may add to, such as a plugin’s class or a progress event’s type, are
strrather thanLiteral. Their known values are listed in the field descriptions.
The SDK’s tests validate the platform’s published example of every contract model against these
models. See scripts/sync-contracts.sh.
- smarter.models.chat.CHAT_CONTRACT_V2 = 2
The version of the Smarter Chat api contract that the SDK reads.
- smarter.models.chat.CHAT_CONTRACT_V2_CAPABILITY = 'chat-contract-v2'
The
X-Smarter-Capabilitiesvalue with which the SDK asks for version 2 of the contract.
- smarter.models.chat.LLM_MESSAGE_ROLES = ('system', 'assistant', 'user', 'tool')
The message roles that the LLM providers accept.
Smarter’s own roles,
smarterandsmarter_error, are informational.
- class smarter.models.chat.PromptChatApiAudioPart(*, type: Literal['input_audio'], input_audio: PromptChatApiInputAudio, **extra_data: Any)[source]
Bases:
SmarterModelAn audio part of a message’s content.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiChoice(*, index: int = 0, finish_reason: str | None = None, message: PromptChatApiMessage | None = None, **extra_data: Any)[source]
Bases:
SmarterModelA choice of a chat completion.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiCompletion(*, id: str | None = None, object: str | None = None, created: int | None = None, model: str | None = None, choices: list[PromptChatApiChoice] = <factory>, usage: PromptChatApiUsage | None = None, system_fingerprint: str | None = None, service_tier: str | None = None, **extra_data: Any)[source]
Bases:
SmarterModelThe LLM’s chat completion, in the format of the OpenAI api.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiConfig(*, contract: int = 2, session_key: str, sandbox_mode: bool, debug_mode: bool, meta_data: PromptChatApiMetaData, llmclient: PromptChatApiLLMClient, history: PromptChatApiHistory, plugins: PromptChatApiPluginList, extensions: PromptChatApiExtensionList | None = None, **extra_data: Any)[source]
Bases:
SmarterModelAn LLMClient’s chat configuration: the LLMClient, the chat session’s key and history, and its plugins and extensions.
A new session’s configuration has an empty history. Pass its
session_keyto the prompt api to continue the session.- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiConfigRequest(*, session_key: str | None = None, **extra_data: Any)[source]
Bases:
SmarterModelThe configuration api’s request body.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiConfigResponse(*, api: str, metadata: PromptChatApiJournalMetadata = <factory>, data: PromptChatApiConfig, **extra_data: Any)[source]
Bases:
PromptChatApiEnvelopeThe configuration api’s response.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- smarter.models.chat.PromptChatApiContentPart
A part of a message whose content is a list of parts, by its
type.alias of
Annotated[PromptChatApiTextPart|PromptChatApiImagePart|PromptChatApiAudioPart|PromptChatApiFilePart|PromptChatApiRefusalPart, FieldInfo(annotation=NoneType, required=True, discriminator=’type’)]
- class smarter.models.chat.PromptChatApiEnvelope(*, api: str, metadata: PromptChatApiJournalMetadata = <factory>, **extra_data: Any)[source]
Bases:
SmarterModelThe fields that every chat response adds beside
data.- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiErrorBody(*, errorClass: str, description: str, status: int, **extra_data: Any)[source]
Bases:
SmarterModelThe
errorof a chat error response.- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiErrorResponse(*, error: PromptChatApiErrorBody, api: str | None = None, metadata: PromptChatApiJournalMetadata | None = None, **extra_data: Any)[source]
Bases:
SmarterModelA chat error response.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiExtensionList(*, meta_data: PromptChatApiListMetaData, extensions: list[PromptChatApiLLMClientExtension] = <factory>, **extra_data: Any)[source]
Bases:
SmarterModelThe LLMClient’s extensions.
The list itself is returned only in the complete configuration, with
verbose=True. Otherwiseextensionsis empty, andmeta_datahas the counts.- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiFileRef(*, file_data: str | None = None, file_id: str | None = None, filename: str | None = None, **extra_data: Any)[source]
Bases:
SmarterModelA file, base64 encoded, or by the provider’s file id.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiFilePart(*, type: Literal['file'], file: PromptChatApiFileRef, **extra_data: Any)[source]
Bases:
SmarterModelA file part of a message’s content.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiFunctionCall(*, name: str, arguments: str, **extra_data: Any)[source]
Bases:
SmarterModelThe function that a tool call calls.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiHistory(*, chat_history: list[PromptChatApiMessage] = <factory>, prompt_tool_call_history: list[PromptChatApiPromptToolCall] | None = None, prompt_plugin_usage_history: list[PromptChatApiPromptPluginUsage] | None = None, plugin_selector_history: list[PromptChatApiPluginSelection] | None = None, llmclient_request_history: list[PromptChatApiLLMClientRequest] | None = None, **extra_data: Any)[source]
Bases:
SmarterModelThe chat session’s history.
prompt_tool_call_historyis returned only in the complete configuration, withverbose=True.- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiImagePart(*, type: Literal['image_url'], image_url: PromptChatApiImageUrl, **extra_data: Any)[source]
Bases:
SmarterModelAn image part of a message’s content.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiImageUrl(*, url: str, detail: Literal['auto', 'low', 'high'] | None = None, **extra_data: Any)[source]
Bases:
SmarterModelAn image, by its url or as a data url.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiInputAudio(*, data: str, format: Literal['wav', 'mp3'], **extra_data: Any)[source]
Bases:
SmarterModelAudio, base64 encoded.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiJournalMetadata(*, command: str | None = None, thing: str | None = None, key: str | None = None, **extra_data: Any)[source]
Bases:
SmarterModelThe
metadataof a chat response.- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiLLMClient(*, id: int, name: str, url_llmclient: str | None = None, version: str | None = None, deployed: bool | None = None, provider: str | None = None, default_model: str | None = None, default_system_role: str | None = None, app_name: str | None = None, app_assistant: str | None = None, app_welcome_message: str | None = None, app_example_prompts: list[str] | None = None, app_placeholder: str | None = None, app_info_url: str | None = None, app_file_attachment: bool | None = None, styles: PromptChatApiStyles | None = None, total_tools: int | None = None, **extra_data: Any)[source]
Bases:
SmarterModelThe LLMClient, as its configuration describes it.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiLLMClientExtension(*, id: int, created_at: datetime | None = None, updated_at: datetime | None = None, llmclient: int, extension: int, name: str, version: str | None = None, enabled: bool, **extra_data: Any)[source]
Bases:
PromptChatApiOrmModelAn extension of the LLMClient, whose tools it offers the LLM.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiLLMClientPlugin(*, id: int, created_at: datetime | None = None, updated_at: datetime | None = None, llmclient: int, plugin_meta: PromptChatApiPluginMeta, **extra_data: Any)[source]
Bases:
PromptChatApiOrmModelA plugin of the LLMClient.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiLLMClientRequest(*, id: int, created_at: datetime | None = None, updated_at: datetime | None = None, llmclient: int, request: PromptChatApiPromptRequest | None = None, session_key: str | None = None, is_aggregation: bool | None = None, **extra_data: Any)[source]
Bases:
PromptChatApiOrmModelA request that Smarter sent to the LLM.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiListMetaData(*, total_plugins: int | None = None, plugins_returned: int | None = None, total_extensions: int | None = None, extensions_returned: int | None = None, **extra_data: Any)[source]
Bases:
SmarterModelThe counts of a list of the LLMClient’s plugins or extensions.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiMessage(*, role: str, content: str | list[Annotated[PromptChatApiTextPart | PromptChatApiImagePart | PromptChatApiAudioPart | PromptChatApiFilePart | PromptChatApiRefusalPart, FieldInfo(annotation=NoneType, required=True, discriminator='type')]] | None = None, tool_calls: list[PromptChatApiToolCall] | None = None, tool_call_id: str | None = None, name: str | None = None, **extra_data: Any)[source]
Bases:
SmarterModelA message of a chat thread, in the format of the OpenAI api.
Smarter adds its own roles:
smarterfor informational messages (e.g. the prompt’s configuration, the tools presented to the LLM, and its token charges), andsmarter_error. These are saved in the session’s history, and are never sent to the LLM.- property text: str
The message’s text: its content, or the text of its text parts, joined by blank lines.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiMetaData(*, ready: bool | None = None, is_valid: bool | None = None, is_deployed: bool | None = None, is_authentication_required: bool | None = None, is_custom_domain: bool | None = None, **extra_data: Any)[source]
Bases:
SmarterModelThe LLMClient’s state.
The complete configuration, from
config()withverbose=True, adds the platform’s other details of the LLMClient, which this model accepts as extra fields.- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiOrmModel(*, id: int, created_at: datetime | None = None, updated_at: datetime | None = None, **extra_data: Any)[source]
Bases:
SmarterModelThe fields of a Django row that the contract returns.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiPluginList(*, meta_data: PromptChatApiListMetaData, plugins: list[PromptChatApiLLMClientPlugin] = <factory>, **extra_data: Any)[source]
Bases:
SmarterModelThe LLMClient’s plugins.
The list itself is returned only in the complete configuration, with
verbose=True. Otherwisepluginsis empty, andmeta_datahas the counts.- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiPluginMeta(*, id: int, created_at: datetime | None = None, updated_at: datetime | None = None, name: str, description: str | None = None, version: str | None = None, tags: list[str] = [], annotations: list[dict[str, JsonValue]] | dict[str, JsonValue] | None = None, plugin_class: str, **extra_data: Any)[source]
Bases:
PromptChatApiOrmModelA plugin’s metadata.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiPluginSelection(*, id: int, created_at: datetime | None = None, updated_at: datetime | None = None, plugin_selector: int, search_term: str | None = None, messages: list[PromptChatApiMessage] | None = None, session_key: str | None = None, **extra_data: Any)[source]
Bases:
PromptChatApiOrmModelA plugin selector’s decision in the chat session.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiProgressEvent(*, type: str, message: str, **extra_data: Any)[source]
Bases:
SmarterModelThe data of a
progressevent: a step of a running prompt.Events may carry more fields, depending on their type, e.g.
toolandarguments.- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiProgressResult(*, status: int, response: PromptChatApiPromptResponse | PromptChatApiErrorResponse, **extra_data: Any)[source]
Bases:
SmarterModelThe data of the final
resultevent.- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiPromptPluginUsage(*, id: int, created_at: datetime | None = None, updated_at: datetime | None = None, prompt: int, plugin: int, input_text: str | None = None, **extra_data: Any)[source]
Bases:
PromptChatApiOrmModelA use of a plugin in the chat session.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiPromptRequest(*, session_key: str | None = None, messages: list[PromptChatApiMessage], **extra_data: Any)[source]
Bases:
SmarterModelThe prompt api’s request body.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiPromptResponse(*, api: str, metadata: PromptChatApiJournalMetadata = <factory>, data: PromptChatApiPromptResult, error: PromptChatApiErrorBody | None = None, **extra_data: Any)[source]
Bases:
PromptChatApiEnvelopeThe prompt api’s response.
A failed prompt has
errortoo, and itsdata.messagesinclude asmarter_errormessage.- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiPromptResult(*, contract: int = 2, status: int, messages: list[PromptChatApiMessage] = <factory>, completion: PromptChatApiCompletion | None = None, plugins: list[str] = <factory>, tools: list[str] = <factory>, **extra_data: Any)[source]
Bases:
SmarterModelThe result of a prompt.
- property assistant_messages: list[PromptChatApiMessage]
The assistant messages that the prompt added, which are the LLM’s replies and tool calls.
- property text: str
The text of the LLM’s final reply: the last assistant message that has content, or an empty string.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiPromptToolCall(*, id: int, created_at: datetime | None = None, updated_at: datetime | None = None, prompt: int, plugin: int | None = None, function_name: str | None = None, function_args: str | None = None, request: JsonValue = None, response: JsonValue = None, **extra_data: Any)[source]
Bases:
PromptChatApiOrmModelA tool call of the chat session.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiRefusalPart(*, type: Literal['refusal'], refusal: str, **extra_data: Any)[source]
Bases:
SmarterModelThe LLM’s refusal, as a part of a message’s content.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiStyleSection(*, background_color: str | None = None, color: str | None = None, border_color: str | None = None, info_color: str | None = None, link_color: str | None = None, editor_background_color: str | None = None, placeholder_color: str | None = None, **extra_data: Any)[source]
Bases:
SmarterModelThe colors of one section of the chat ui.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiStyles(*, app_logo_url: str | None = None, app_background_image_url: str | None = None, app_background_image_size: str | None = None, assistant_avatar_url: str | None = None, user_avatar_url: str | None = None, font_family: str | None = None, google_font: str | None = None, font_size: str | None = None, border_radius: str | None = None, main_container: PromptChatApiStyleSection | None = None, conversation_header: PromptChatApiStyleSection | None = None, message_list: PromptChatApiStyleSection | None = None, incoming_message: PromptChatApiStyleSection | None = None, outgoing_message: PromptChatApiStyleSection | None = None, message_input: PromptChatApiStyleSection | None = None, buttons: PromptChatApiStyleSection | None = None, typing_indicator: PromptChatApiStyleSection | None = None, **extra_data: Any)[source]
Bases:
SmarterModelThe LLMClient’s chat ui styles.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiTextPart(*, type: Literal['text'], text: str, **extra_data: Any)[source]
Bases:
SmarterModelA text part of a message’s content.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiTokenDetails(*, reasoning_tokens: int | None = None, cached_tokens: int | None = None, audio_tokens: int | None = None, **extra_data: Any)[source]
Bases:
SmarterModelThe breakdown of a completion’s tokens.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiToolCall(*, id: str, type: str = 'function', function: PromptChatApiFunctionCall, **extra_data: Any)[source]
Bases:
SmarterModelA tool call of an assistant message.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.chat.PromptChatApiUsage(*, prompt_tokens: int | None = None, completion_tokens: int | None = None, total_tokens: int | None = None, prompt_tokens_details: PromptChatApiTokenDetails | None = None, completion_tokens_details: PromptChatApiTokenDetails | None = None, **extra_data: Any)[source]
Bases:
SmarterModelA chat completion’s token usage.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
smarter.models.journal
Models of the Smarter Journal api contract: the envelope of every journaled response, its error body, and a journal entry.
The Smarter platform journals its api responses. Each one carries api (the api version, e.g.
smarter.sh/v1) and metadata (the command and the resource kind, which the platform calls
its “thing”) beside its own data, message or error.
These models mirror smarter.lib.journal.contract.models in the Smarter platform, whose JSON
Schema is journal-contract.schema.json. The SDK’s tests validate the platform’s schema against
them. See scripts/sync-contracts.sh.
- class smarter.models.journal.JournalEntry(*, key: str, createdAt: datetime | None = None, user: str | None = None, thing: str, command: str, statusCode: int, request: JsonValue = None, response: JsonValue = None, **extra_data: Any)[source]
Bases:
SmarterCamelModelA Smarter Journal entry, as
/api/v1/journal/returns it.The list returns entries without
requestandresponse. Retrieving one entry by its key includes them. Only superusers may read the journal, because the request documents hold the callers’ credentials.- model_config = {'alias_generator': <function to_camel>, 'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.journal.JournalPage(*, objects: list[JournalEntry] = [], pagination: JournalPagination, **extra_data: Any)[source]
Bases:
SmarterModelOne page of the journal’s entries.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.journal.JournalPagination(*, page: int, pageSize: int, numPages: int, count: int, search: str = '', ordering: str = '', sortFields: list[str] = [], filter: str = '', filters: list[str] = <factory>, **extra_data: Any)[source]
Bases:
SmarterCamelModelThe description of one page of the journal’s entries.
- model_config = {'alias_generator': <function to_camel>, 'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.journal.SAMJournalApiEnvelope(*, api: str = 'smarter.sh/v1', metadata: SAMJournalApiMetadata | None = None, **extra_data: Any)[source]
Bases:
SmarterModelThe fields that every journaled response adds beside its own data.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.journal.SAMJournalApiErrorBody(*, errorClass: str, stacktrace: str | None = None, description: str | None = None, status: int, args: JsonValue = None, cause: str | None = None, context: str | None = None, thing: str | None = None, command: str | None = None, **extra_data: Any)[source]
Bases:
SmarterModelThe
errorof a journaled error response.Every error of the cli api has this shape.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.journal.SAMJournalApiErrorResponse(*, api: str = 'smarter.sh/v1', metadata: SAMJournalApiMetadata | None = None, error: SAMJournalApiErrorBody, **extra_data: Any)[source]
Bases:
SAMJournalApiEnvelopeThe body of a journaled error response.
- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.journal.SAMJournalApiMetadata(*, command: str, thing: str, key: str | None = None, **extra_data: Any)[source]
Bases:
SmarterModelThe
metadataof a journaled response: its command and thing, and the key of its journal entry.- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.journal.SmarterJournalMessage(*, api: str = 'smarter.sh/v1', metadata: SAMJournalApiMetadata | None = None, message: str | None = None, **extra_data: Any)[source]
Bases:
SAMJournalApiEnvelopeA journaled response that carries only a
message, e.g. the response of delete or deploy.- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.journal.SmarterJournaledResponse(*, api: str = 'smarter.sh/v1', metadata: SAMJournalApiMetadata | None = None, data: DataT | None = None, message: str | None = None, **extra_data: Any)[source]
Bases:
SAMJournalApiEnvelope,Generic[DataT]A successful journaled response: the envelope, the response’s
data, and an optionalmessage.datais typed by the endpoint, e.g.SmarterJournaledResponse[WhoAmI].- model_config = {'extra': 'allow', 'populate_by_name': True, 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
smarter.models.react
Pydantic models of the Smarter platform’s Django-React integration: a React app’s Vite manifest, and the assets that a template includes.
The platform’s web console pages are React apps that Django hosts.
SmarterReactTemplateTagManager (in smarter.lib.django.templatetags) reads each app’s
Vite-generated manifest.json, and each <app>_react_assets template tag returns the files
that a template includes. These models are a copy of the platform’s
smarter.lib.django.templatetags.smarter_react_contract, which is pure Pydantic, so that tools
that build or check React apps for a Smarter platform can use them without the platform.
ViteManifestis a Vite-generated Reactmanifest.json: a map ofViteManifestChunkkeyed by source path. The manager validates the file against it when it loads it, and collects an entry point’s assets with its methods.ReactAppAssetsis what every<app>_react_assetstemplate tag returns: the ordered JS and CSS files that a Django template includes for a React app.
The manifest is a third-party shape. ViteManifestChunk declares the
fields that Vite documents, and allows extra fields, which newer Vite (or
Rolldown) versions add, so that a Vite upgrade doesn’t break page rendering.
Smarter’s own addition, the _custom entry that every package’s
vite.config.ts writes after the build, is a ReactAppBuildInfo.
- smarter.models.react.BUILD_INFO_KEY = '_custom'
The key of the build information that each React package’s
vite.config.tsadds to its manifest.json.
- class smarter.models.react.ReactAppAssets(*, js: list[str] = <factory>, css: list[str] = <factory>)[source]
Bases:
BaseModelThe ordered JS and CSS files of a React app’s entry point, which a Django template includes.
Every
<app>_react_assetstemplate tag returns one. Templates read its attributes, e.g.{% for css_file in assets.css %}.Example:
{ "js": [ "assets/index-CZK_Bxxh.js", "assets/rolldown-runtime-B3igc2qu.js", "assets/xterm-D5XSfLrr.js" ], "css": [ "assets/index-58MXwt-L.css", "assets/xterm-kHJ-D0s7.css" ] }
- model_config = {'extra': 'forbid'}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.models.react.ReactAppBuildInfo(*, buildTime: datetime, version: str, buildEnv: str)[source]
Bases:
BaseModelThe build information that each React package’s
vite.config.tsadds to its manifest.json, as_custom.Example:
"_custom": { "buildTime": "2026-10-12T01:09:47.988Z", "version": "0.3.0", "buildEnv": "production" }
- model_config = {'extra': 'forbid', 'populate_by_name': True}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- smarter.models.react.ReactAssetType
The kinds of asset that a React app’s entry point loads.
alias of
Literal[‘js’, ‘css’]
- class smarter.models.react.ViteManifest(*, chunks: dict[str, ViteManifestChunk], build_info: ReactAppBuildInfo | None = None)[source]
Bases:
BaseModelA React app’s Vite-generated
manifest.json: its chunks, keyed by source path, and Smarter’s build information.In the file, the build information is the
_customentry, beside the chunks. Validating a manifest.json splits it out intobuild_info, and dumping the model puts it back, somodel_dump(by_alias=True)has the file’s shape.See https://vite.dev/guide/backend-integration.
- model_config = {'extra': 'forbid'}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- classmethod split_build_info(data: object) object[source]
Split a manifest.json’s
_customentry from its chunks.Input that already has
chunks, e.g. keyword arguments, is left as is.- Parameters:
data – The manifest.json’s content.
- Returns:
The model’s fields.
- Return type:
- join_build_info(handler: SerializerFunctionWrapHandler) dict[str, Any][source]
Dump the manifest in the shape of manifest.json, with the build information as its
_customentry.- Parameters:
handler – Pydantic’s default serializer.
- Returns:
The chunks, keyed by source path, and
_custom.- Return type:
- entry_key() str | None[source]
Find the key of the manifest’s entry point, the first chunk with
"isEntry": true.- Returns:
The entry point’s key, or None if the manifest has no entry point.
- Return type:
Optional[str]
- collect_assets(key: str, asset_type: Literal['js', 'css'], seen: set[str] | None = None) list[str][source]
Recursively collect the JS or CSS files of a chunk and of its static imports.
A chunk’s own files come first, followed by those of each of its
imports, depth first, in the order they are listed. Each chunk is visited once, so circular imports terminate.
- class smarter.models.react.ViteManifestChunk(*, file: str, name: str | None = None, names: list[str] = <factory>, src: str | None = None, isEntry: bool = False, isDynamicEntry: bool = False, imports: list[str] = <factory>, dynamicImports: list[str] = <factory>, css: list[str] = <factory>, assets: list[str] = <factory>, **extra_data: Any)[source]
Bases:
BaseModelOne entry of a Vite-generated
manifest.json: a chunk, or a static asset.See https://vite.dev/guide/backend-integration. Extra fields are allowed, because Vite and Rolldown add their own.
Example:
"index.html": { "file": "assets/index.js", "name": "index", "src": "index.html", "isEntry": true, "imports": ["_rolldown-runtime.js", "_xterm.js"], "css": ["assets/index-DvLY75bJ.css"] }
- model_config = {'extra': 'allow', 'populate_by_name': True}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].