Interface BBjAdminAI
- All Superinterfaces:
Remote,Serializable
Provides access to the Basis AI natural-language-to-SQL library from within
the BBj Admin API. Use this interface to configure an LLM provider, index a
BBj database schema, and convert plain-English questions into SQL
SELECT statements. It also exposes a general-purpose LLM prompting
API (sendPrompt(String) / sendPrompt(BBjAdminAIPromptRequest))
for any other AI-assisted feature - explanations, summaries, multi-turn chat -
that does not need to go through the SQL-generation pipeline.
Obtain an instance via BBjAdminBase.getAI(). The instance is not
yet configured on creation; call configure(BBjAdminAIConfig),
loadDefaultConfig(), or loadConfig(String) before invoking
any schema or query methods.
Typical usage pattern
Most client applications obtain a single BBjAdminAI instance when a
screen, session, or job starts and reuse it for that lifetime. The instance is
loaded with whatever configuration was last saved via loadDefaultConfig();
if none has been saved yet, that call throws BBjAdminException - which
simply means AI-driven functionality should stay disabled until the user
configures a provider:
BBjAdminAI ai = api.getAI();
try {
ai.loadDefaultConfig();
} catch (BBjAdminException e) {
// No configuration saved yet - leave AI-driven features disabled
// until the user configures a provider via configure(BBjAdminAIConfig).
}
Once a provider is configured, prefer fetching a snapshot with
getConfig(), mutating it, and handing it back to
saveConfig(BBjAdminAIConfig) in a single call, rather than
reconfiguring the whole engine via configure(BBjAdminAIConfig):
BBjAdminAIConfig config = ai.getConfig();
config.getOpenai().setApiKey(newApiKey);
config.setActiveProvider(BBjAdminAIConfig.PROVIDER_OPENAI);
ai.saveConfig(config);
Java Sample: configure, index a schema, and ask a question
BBjAdminBase api = BBjAdminFactory.getBBjAdmin(InetAddress.getByName("myserver"), 2002, true, "admin", "admin123");
BBjAdminAI ai = api.getAI();
BBjAdminAIConfig cfg = new BBjAdminAIConfig();
cfg.setActiveProvider(BBjAdminAIConfig.PROVIDER_OPENAI);
cfg.getOpenai().setApiKey("sk-...");
ai.configure(cfg);
ai.indexSchema("jdbc:basis://localhost?database=ChileCompany", "admin", "admin123", null);
BBjAdminAIQueryResult result = ai.buildQuery("Show all invoices for customer ACME Corp");
if (result.isSuccessful()) {
System.out.println(result.getGeneratedSql());
} else {
System.err.println(result.getErrorMessage());
}
ai.close();
Java Sample: general-purpose prompting alongside SQL generation
// A one-shot explanation, independent of any indexed schema
BBjAdminAIPromptResponse explanation = ai.sendPrompt("Explain what a correlated subquery is.");
System.out.println(explanation.getContent());
// A multi-turn conversation that references an earlier answer
BBjAdminAIPromptRequest followUp = new BBjAdminAIPromptRequest("Which of those tables stores addresses?");
followUp.addHistory(BBjAdminAIChatMessage.user("What tables are in the database?"));
followUp.addHistory(BBjAdminAIChatMessage.assistant("CUSTOMER, INVOICE, ADDRESS"));
BBjAdminAIPromptResponse answer = ai.sendPrompt(followUp);
System.out.println(answer.getContent());
BBj Sample
use com.basis.api.admin.BBjAdminAI
use com.basis.api.admin.BBjAdminAIConfig
...
ai! = api!.getAI()
cfg! = new BBjAdminAIConfig()
cfg!.setActiveProvider(BBjAdminAIConfig.PROVIDER_OPENAI)
cfg!.getOpenai().setApiKey("sk-...")
ai!.configure(cfg!)
ai!.indexSchema("jdbc:basis://localhost?database=ChileCompany", "admin", "admin123", BBjAPI.NULL)
result! = ai!.buildQuery("Show all invoices for customer ACME Corp")
if result!.isSuccessful()
print result!.getGeneratedSql()
endif
ai!.close()
- See Also:
-
Method Summary
Modifier and TypeMethodDescriptionbuildQuery(String p_naturalLanguageQuery) Converts a plain-English question into a SQLSELECTstatement using a Retrieval-Augmented Generation (RAG) pipeline.buildQuery(String p_naturalLanguageQuery, String p_databaseName) Converts a plain-English question into a SQLSELECTstatement, restricting schema retrieval to documents indexed underp_databaseName.buildQuery(String p_naturalLanguageQuery, String p_databaseName, String p_provider, String p_model) Converts a plain-English question into a SQLSELECTstatement using an explicitly requested provider/model instead of the configured default, restricting schema retrieval to documents indexed underp_databaseName.voidDeletes all documents from the schema vector index.voidclose()Closes the underlying AI engine and releases all resources (schema vector store, embedding model, etc.).voidconfigure(BBjAdminAIConfig p_config) Configures the AI instance with the supplied settings and activates the specified LLM provider.Returns a snapshot of the currently active configuration, ornullif no configuration has been set yet.longReturns the number of documents currently stored in the schema index.voidOpens a new JDBC connection, reads the database schema viaDatabaseMetaData, embeds the schema as dense vectors, and stores them in a JSON-backed vector store.voidindexSchema(Connection p_connection, List<String> p_tables) Indexes the schema using an already-openConnection.listIndexedTableNames(String p_jdbcUrl) Returns an alphabetically sorted, immutable list of table names that have been indexed in the schema vector store for the database identified by the given JDBC URL.Returns every document in the schema index, sorted by type (TABLEfirst, thenRELATIONSHIP) then by table name.listTables(String p_jdbcUrl, String p_username, String p_password) Opens a JDBC connection and returns the names of all user tables visible to the given credentials, without modifying the schema index.voidloadConfig(String p_configPath) Loads configuration from the specified JSON file path and activates it.voidLoads configuration from the default location (~/.basis-ai/config.json) and activates it.voidEncrypts sensitive fields and writes the current configuration to the default location (~/.basis-ai/config.json).voidsaveConfig(BBjAdminAIConfig p_config) Updates the active configuration fromp_configand writes it to the default location (~/.basis-ai/config.json).voidsaveConfig(BBjAdminAIConfig p_config, String p_configPath) Updates the active configuration fromp_configand writes it to the specified path.voidsaveConfig(String p_configPath) Encrypts sensitive fields and writes the current configuration to the specified path.sendPrompt(BBjAdminAIPromptRequest p_request) Sends a fully configured prompt to the LLM, supporting an explicit system prompt, conversation history, temperature override, and max-token override.sendPrompt(String p_prompt) Sends a simple one-shot prompt to the configured LLM using the configuredgeneralSystemPrompt.
-
Method Details
-
configure
Configures the AI instance with the supplied settings and activates the specified LLM provider. Any previously active configuration is discarded.Use this when building a configuration from scratch (e.g. an initial setup screen). To edit an already-active configuration, prefer
getConfig()followed bysaveConfig(BBjAdminAIConfig), which persists the change without discarding unrelated settings.BBjAdminAIConfig config = new BBjAdminAIConfig(); config.setActiveProvider(BBjAdminAIConfig.PROVIDER_ANTHROPIC); BBjAdminAIConfig.Anthropic anthropic = config.getAnthropic(); anthropic.setApiKey("sk-ant-..."); anthropic.setModels(List.of("claude-sonnet-5", "claude-haiku-4-5")); anthropic.setDefaultModel("claude-sonnet-5"); anthropic.setTemperature(0.2); anthropic.setTimeoutSeconds(60); ai.configure(config);- Parameters:
p_config- Configuration to apply. Must not benull.- Throws:
BBjAdminException- if the underlying AI engine cannot be initialised with the given configuration.
-
loadDefaultConfig
Loads configuration from the default location (~/.basis-ai/config.json) and activates it. If the file does not exist, a default unconfigured instance is prepared.Client applications typically call this immediately after
BBjAdminBase.getAI(), and treat a thrown exception as "no provider configured yet" rather than a fatal error:BBjAdminAI ai = api.getAI(); try { ai.loadDefaultConfig(); } catch (BBjAdminException e) { // AI may not be configured yet; the user will see an error // if they try to build a query or send a prompt before configuring. }- Throws:
BBjAdminException- if the configuration file cannot be read or the AI engine cannot be initialised.
-
loadConfig
Loads configuration from the specified JSON file path and activates it.ai.loadConfig("/etc/basis/ai/prod-config.json");- Parameters:
p_configPath- Filesystem path to a JSON configuration file.- Throws:
BBjAdminException- if the file cannot be read or the AI engine cannot be initialised.
-
getConfig
Returns a snapshot of the currently active configuration, ornullif no configuration has been set yet.A settings screen typically loads this snapshot once, lets the user edit any number of fields across one or more providers, then hands the same object back to
saveConfig(BBjAdminAIConfig)in a single call:BBjAdminAIConfig config = ai.getConfig(); if (config == null) { config = new BBjAdminAIConfig(); } config.getOpenai().setModels(List.of("gpt-5", "gpt-5-mini")); config.getOpenai().setDefaultModel("gpt-5"); config.setActiveProvider(BBjAdminAIConfig.PROVIDER_OPENAI); ai.saveConfig(config);- Returns:
- A snapshot of the active configuration, or
nullif none has been set. - Throws:
BBjAdminException- if the configuration cannot be read.
-
saveConfig
Encrypts sensitive fields and writes the current configuration to the default location (~/.basis-ai/config.json). Parent directories are created if they do not exist.ai.saveConfig();- Throws:
BBjAdminException- if the configuration cannot be written.
-
saveConfig
Updates the active configuration fromp_configand writes it to the default location (~/.basis-ai/config.json).This is the preferred overload when the caller obtained a config via
getConfig(), modified it, and wants to persist the changes without reinitialising the AI engine.BBjAdminAIConfig config = ai.getConfig(); BBjAdminAIConfig.OpenAI openai = config.getOpenai(); openai.setApiKey(newApiKey); openai.setModels(List.of("gpt-5", "gpt-5-mini")); openai.setDefaultModel("gpt-5"); config.setActiveProvider(BBjAdminAIConfig.PROVIDER_OPENAI); ai.saveConfig(config);- Parameters:
p_config- The configuration to apply and save.- Throws:
BBjAdminException- if the configuration cannot be applied or written.
-
saveConfig
Updates the active configuration fromp_configand writes it to the specified path.ai.saveConfig(config, "/etc/basis/ai/prod-config.json");- Parameters:
p_config- The configuration to apply and save.p_configPath- Filesystem path to write the JSON configuration to.- Throws:
BBjAdminException- if the configuration cannot be applied or written.
-
saveConfig
Encrypts sensitive fields and writes the current configuration to the specified path.ai.saveConfig("/etc/basis/ai/prod-config.json");- Parameters:
p_configPath- Filesystem path to write the JSON configuration to.- Throws:
BBjAdminException- if the configuration cannot be written.
-
listIndexedTableNames
Returns an alphabetically sorted, immutable list of table names that have been indexed in the schema vector store for the database identified by the given JDBC URL. The database name is extracted from thedatabasequery-string parameter of the URL.A common use of this method is driving a table-picker UI that shows every table in the database with the already-indexed ones pre-checked, as in the Enterprise Manager's AI Databases screen:
String jdbcUrl = "jdbc:basis://localhost?database=ChileCompany&token=" + api.getTokenValue(); List<String> indexed = ai.listIndexedTableNames(jdbcUrl); BBjAdminDatabase db = api.getDatabase("ChileCompany"); for (String table : db.getTableNames(false, false)) { boolean isIndexed = indexed.contains(table); System.out.println(table + (isIndexed ? " [indexed]" : " [not indexed]")); }- Parameters:
p_jdbcUrl- JDBC URL containing adatabase=<name>parameter, e.g.jdbc:basis://localhost?database=ChileCompany&token=...- Returns:
- sorted list of indexed table names; empty if none are indexed
- Throws:
BBjAdminException- if the index cannot be read
-
listTables
List<String> listTables(String p_jdbcUrl, String p_username, String p_password) throws BBjAdminException Opens a JDBC connection and returns the names of all user tables visible to the given credentials, without modifying the schema index.This is a lightweight alternative to
indexSchema(java.lang.String, java.lang.String, java.lang.String, java.util.List<java.lang.String>)intended for populating a table-picker UI before the user decides which tables to index.List<String> tables = ai.listTables("jdbc:basis://localhost?database=ChileCompany", "admin", "admin123"); // Present as a checkbox list; the checked subset becomes p_tables // in a subsequent call to indexSchema(...).- Parameters:
p_jdbcUrl- JDBC connection URL.p_username- Database username. May benull.p_password- Database password. May benull.- Returns:
- Sorted, immutable list of table names.
- Throws:
BBjAdminException- if the connection or metadata call fails.
-
indexSchema
void indexSchema(String p_jdbcUrl, String p_username, String p_password, List<String> p_tables) throws BBjAdminException Opens a new JDBC connection, reads the database schema viaDatabaseMetaData, embeds the schema as dense vectors, and stores them in a JSON-backed vector store. Any previously indexed data for the same tables is replaced.Schema indexing is a one-time operation. The schema index persists across JVM restarts; re-index only when the database schema changes.
Indexing embeds every column/table/relationship description through the configured LLM provider, so it is comparatively slow. In a UI application, run it off the UI/event thread and report status back when it completes, e.g.:
List<String> tablesToIndex = List.of("CUSTOMER", "INVOICE", "INVOICE_LINE"); new Thread(() -> { try { String jdbcUrl = "jdbc:basis://" + host + "?database=" + dbName + "&token=" + api.getTokenValue(); // Pass null username/password -- the token in the URL authenticates the connection. ai.indexSchema(jdbcUrl, null, null, tablesToIndex); System.out.println("Index updated for " + dbName); } catch (BBjAdminException e) { System.err.println("Index update failed: " + e.getMessage()); } }).start();- Parameters:
p_jdbcUrl- JDBC connection URL (e.g.jdbc:basis://localhost?database=ChileCompany).p_username- Database username. May benull.p_password- Database password. May benull.p_tables- Table names to index. Passnullor an empty list to index all tables in the database.- Throws:
BBjAdminException- if indexing fails or no AI instance has been configured yet.
-
indexSchema
Indexes the schema using an already-openConnection. The connection is not closed by this method; the caller retains ownership.Use this overload when the caller already manages its own JDBC connection pool or transaction and does not want a second connection opened just for indexing:
try (Connection conn = DriverManager.getConnection("jdbc:basis://localhost?database=ChileCompany", "admin", "admin123")) { ai.indexSchema(conn, List.of("CUSTOMER", "INVOICE")); }- Parameters:
p_connection- An open JDBC connection.p_tables- Table names to index, ornull/ empty to index all tables.- Throws:
BBjAdminException- if indexing fails or no AI instance has been configured yet.
-
clearSchemaIndex
Deletes all documents from the schema vector index. Useful before performing a full re-index.ai.clearSchemaIndex(); ai.indexSchema("jdbc:basis://localhost?database=ChileCompany", "admin", "admin123", null); // full re-index- Throws:
BBjAdminException- if the index cannot be cleared.
-
getSchemaDocumentCount
Returns the number of documents currently stored in the schema index.long count = ai.getSchemaDocumentCount(); System.out.println(count + " schema document(s) indexed.");- Returns:
- Document count.
- Throws:
BBjAdminException- if the count cannot be retrieved.
-
listSchemaDocuments
Returns every document in the schema index, sorted by type (TABLEfirst, thenRELATIONSHIP) then by table name. Embedding vectors are not included in the returned objects.Useful for an inspection/debugging screen that shows exactly what context the RAG pipeline has available for a given table:
for (BBjAdminAISchemaDocument doc : ai.listSchemaDocuments()) { if (BBjAdminAISchemaDocument.TYPE_TABLE.equals(doc.getType())) { System.out.println("Table: " + doc.getTableName()); } else { System.out.println("Relationship involving: " + doc.getTableName()); } System.out.println(" " + doc.getContent()); }- Returns:
- Immutable list of
BBjAdminAISchemaDocumentobjects. - Throws:
BBjAdminException- if the index cannot be read.
-
buildQuery
Converts a plain-English question into a SQLSELECTstatement using a Retrieval-Augmented Generation (RAG) pipeline. The schema must have been indexed at least once before calling this method.Always check
BBjAdminAIQueryResult.isSuccessful()before usingBBjAdminAIQueryResult.getGeneratedSql().BBjAdminAIQueryResult result = ai.buildQuery("Show all invoices for customer ACME Corp"); if (result.isSuccessful()) { System.out.println(result.getGeneratedSql()); } else { System.err.println(result.getErrorMessage()); }- Parameters:
p_naturalLanguageQuery- Plain-English description of the data to retrieve.- Returns:
- A
BBjAdminAIQueryResultcontaining the generated SQL or an error message. - Throws:
BBjAdminException- if the LLM call fails or no AI instance has been configured yet.
-
buildQuery
BBjAdminAIQueryResult buildQuery(String p_naturalLanguageQuery, String p_databaseName) throws BBjAdminException Converts a plain-English question into a SQLSELECTstatement, restricting schema retrieval to documents indexed underp_databaseName. Use this overload when the index contains schemas from multiple databases and queries should only consider one of them.In a query-builder UI,
p_databaseNameis typically whatever database the user currently has selected in a combo box:String selectedDatabase = databaseCombo.getItem(databaseCombo.getSelectionIndex()); BBjAdminAIQueryResult result = ai.buildQuery( "List customers with overdue invoices", selectedDatabase); if (result.isSuccessful()) { sqlTextArea.setText(result.getGeneratedSql()); } else { showError(result.getErrorMessage()); }- Parameters:
p_naturalLanguageQuery- Plain-English description of the data to retrieve.p_databaseName- Logical database name whose indexed schema to use. Passnullto search all indexed databases.- Returns:
- A
BBjAdminAIQueryResultcontaining the generated SQL or an error message. - Throws:
BBjAdminException- if the LLM call fails or no AI instance has been configured yet.
-
buildQuery
BBjAdminAIQueryResult buildQuery(String p_naturalLanguageQuery, String p_databaseName, String p_provider, String p_model) throws BBjAdminException Converts a plain-English question into a SQLSELECTstatement using an explicitly requested provider/model instead of the configured default, restricting schema retrieval to documents indexed underp_databaseName.This overload backs a "Model:" picker that lets the user try a specific provider/model for one query without changing the configured default - pass
nullfor bothp_providerandp_modelfor a "(Default)" choice:BBjAdminAIQueryResult result = ai.buildQuery( "List customers with overdue invoices", "ChileCompany", BBjAdminAIConfig.PROVIDER_ANTHROPIC, "claude-sonnet-5"); if (result.isSuccessful()) { sqlTextArea.setText(result.getGeneratedSql()); } else { showError(result.getErrorMessage()); }- Parameters:
p_naturalLanguageQuery- Plain-English description of the data to retrieve.p_databaseName- Logical database name whose indexed schema to use. Passnullto search all indexed databases.p_provider- Provider to use, matching one of thePROVIDER_*constants onBBjAdminAIConfig, ornullto use the configured default provider.p_model- Model name to use, ornullto use the resolved provider's configured default model.- Returns:
- A
BBjAdminAIQueryResultcontaining the generated SQL or an error message. - Throws:
BBjAdminException- if the LLM call fails or no AI instance has been configured yet.
-
sendPrompt
Sends a simple one-shot prompt to the configured LLM using the configuredgeneralSystemPrompt. Ideal for explanations, summaries, or any non-SQL interaction.BBjAdminAIPromptResponse response = ai.sendPrompt("Summarize what a correlated subquery is."); System.out.println(response.getContent()); System.out.println("Tokens used: " + response.getTotalTokens());- Parameters:
p_prompt- The user message to send.- Returns:
- A
BBjAdminAIPromptResponsecontaining the reply and token-usage information. - Throws:
BBjAdminException- if the LLM call fails or no AI instance has been configured yet.
-
sendPrompt
Sends a fully configured prompt to the LLM, supporting an explicit system prompt, conversation history, temperature override, and max-token override.Use this overload to carry a multi-turn conversation, override the system prompt for one request, or pin a specific provider/model the same way
buildQuery(String, String, String, String)does:BBjAdminAIPromptRequest request = new BBjAdminAIPromptRequest("Which of those tables stores addresses?"); request.setSystemPrompt("You are a helpful BBj database assistant."); request.addHistory(BBjAdminAIChatMessage.user("What tables are in the database?")); request.addHistory(BBjAdminAIChatMessage.assistant("CUSTOMER, INVOICE, ADDRESS")); request.setProvider(BBjAdminAIConfig.PROVIDER_OPENAI); request.setModel("gpt-5-mini"); BBjAdminAIPromptResponse response = ai.sendPrompt(request); System.out.println(response.getContent());- Parameters:
p_request- ABBjAdminAIPromptRequestdescribing the request.- Returns:
- A
BBjAdminAIPromptResponsecontaining the reply and token-usage information. - Throws:
BBjAdminException- if the LLM call fails or no AI instance has been configured yet.
-
close
Closes the underlying AI engine and releases all resources (schema vector store, embedding model, etc.). After this call, all other methods will throwBBjAdminExceptionuntil the instance is reconfigured viaconfigure(BBjAdminAIConfig)orloadDefaultConfig().Call this when a screen or session that owns a
BBjAdminAIinstance is shutting down, mirroring how a UI'sdispose()closes its other server-side resources (e.g. an open JDBC connection):public void dispose() { try { if (ai != null) { ai.close(); } } catch (BBjAdminException e) { // Ignore on shutdown } }- Throws:
BBjAdminException- if resources cannot be released cleanly.
-