System prompts for query generation.
Prompts are assembled in a fixed order so that core Lotus rules (the
{{var}} / [[...]] template DSL, the response contract, the workflow
instructions) always precede adapter-contributed content (the
ai_context.syntax_notes and :example_query). Untrusted adapters have
their free-form fields stripped upstream in
Lotus.Source.Adapter.ai_context/1; placing core content first means a
compromised adapter cannot override the Lotus DSL rules through later
text.
Summary
Functions
Extract both the statement and its variables from LLM response content.
Extract the generated statement from LLM response content.
Extract variable configurations from LLM response content.
Generate system prompt for query generation.
Functions
@spec extract_response(String.t()) :: {:ok, %{statement: String.t(), variables: [map()]}} | {:error, {:unable_to_generate, String.t()}}
Extract both the statement and its variables from LLM response content.
Combines extract_statement/1 and extract_variables/1 into a single call.
This is the primary extraction entry point for response parsing.
Parameters
content- Raw response content from the LLM
Returns
{:ok, %{statement: String.t(), variables: [map()]}}- Successfully extracted{:error, {:unable_to_generate, reason}}- LLM refused to generate
Examples
iex> extract_response("```sql\nSELECT * FROM users WHERE status = {{status}}\n```\n```variables\n[{\"name\": \"status\"}]\n```")
{:ok, %{statement: "SELECT * FROM users WHERE status = {{status}}", variables: [...]}}
@spec extract_statement(String.t()) :: {:ok, String.t()} | {:error, {:unable_to_generate, String.t()}}
Extract the generated statement from LLM response content.
Accepts any fence label, since the prompt asks for the adapter's language family, and detects when the LLM has refused to generate.
Parameters
content- Raw response content from the LLM
Returns
{:ok, statement}- Successfully extracted statement{:error, {:unable_to_generate, reason}}- LLM refused to generate
Examples
iex> extract_statement("```sql\nSELECT * FROM users\n```")
{:ok, "SELECT * FROM users"}
iex> extract_statement("UNABLE_TO_GENERATE: This is a weather question")
{:error, {:unable_to_generate, "This is a weather question"}}
Extract variable configurations from LLM response content.
Parses a ```variables JSON block from the response. Returns an empty list
if no block is found or if the JSON is malformed.
Parameters
content- Raw response content from the LLM
Returns
List of variable configuration maps (empty list if none found).
Examples
iex> extract_variables("```variables\n[{\"name\": \"status\", \"type\": \"text\"}]\n```")
[%{"name" => "status", "type" => "text", "widget" => "input", "list" => false}]
iex> extract_variables("Just a statement without variables")
[]
Generate system prompt for query generation.
Composition order
Each section is emitted in this order to establish the trust boundary:
- System role (core)
- Read-only / write-only instructions (core)
- Available tables (core, schema context)
- Tools + workflow (core)
- Lotus template DSL rules (core, immutable —
lotus_template_notes/0+Variables.system_docs/1) - Adapter
syntax_notes(filtered if untrusted, truncated at 1 KB) - Adapter
example_query(bounded at 2 KB) - Output contract examples (core)
Parameters
ai_context— the sanitized map returned byLotus.Source.Adapter.ai_context/1(:language,:example_query,:syntax_notes,:error_patterns).table_names— list of available table names.opts— keyword list::read_only— whentrue(default), instruct the LLM to stick to read-only statements.