diff --git a/google-gemini-marketplace-agents/oracle_ai_database_agent/README.md b/google-gemini-marketplace-agents/oracle_ai_database_agent/README.md deleted file mode 100644 index eaf648d..0000000 --- a/google-gemini-marketplace-agents/oracle_ai_database_agent/README.md +++ /dev/null @@ -1,238 +0,0 @@ -# Oracle AI Database Agent - -## Overview - -The **Oracle AI Database Agent** enables natural-language data analysis workflows by combining NL2SQL generation, metadata inspection, query correction, and chart generation inside Oracle Autonomous AI Database. - -For definitions of **Tool**, **Task**, **Agent**, and **Agent Team**, see the top-level guide: [README](../README.md#simple-agent-execution-flow). - -## How the NL2SQL agent improves upon Select AI NL2SQL - -Oracle Select AI already provides Natural Language to SQL (NL2SQL), but **real-world data retrieval often fails** due to: - -- Ambiguous column values -- Unknown or incorrect value ranges (dates, numbers) -- Invalid predicates leading to zero-row results -- Lack of visualization support - -This **Oracle AI Database Agent** addresses these limitations by combining: - -- Database introspection -- Fail-safe retries -- Distinct and range value discovery -- Chart and visualization generation - -into a **single autonomous agent workflow**. - ---- - -## Architecture Overview - -```text -User Query - ↓ -NL2SQL Task - ↓ -Agent Reasoning - ├── SQL_TOOL - ├── DISTINCT_VALUES_CHECK - ├── RANGE_VALUES_CHECK - └── GENERATE_CHART - ↓ -Final Verified Answer + Sources -``` - -The agent dynamically selects tools, retries intelligently, and produces **explainable outputs**. - ---- - -## Repository Contents - -```text -. -├── oracle_ai_database_agent_tool.sql -│ ├── PL/SQL utility functions -│ ├── Database-native analysis helpers -│ └── AI tool registration -│ -├── oracle_ai_database_agent.sql -│ ├── Task definition -│ ├── Agent creation -│ ├── Team orchestration -│ └── AI profile binding -│ -└── README.md -``` - ---- - -## Prerequisites - -- Oracle Autonomous AI Database (26ai recommended) -- Select AI enabled -- Run as ADMIN - ---- - -## Installation – Tools - -Before running installation commands: - -1. Clone or download this repository. -2. Open a terminal and change directory to `google-gemini-marketplace-agents`. -3. Choose one execution mode: - - SQL*Plus/SQLcl: run script files directly with `@script_name`. - - SQL Worksheet (Database Actions or other SQL IDE): open the `.sql` file and run/paste its contents. -4. Uploading scripts to `DATA_PUMP_DIR` is not required for these methods. - -Run as `ADMIN` (or another privileged user): - -```sql -sqlplus admin@ @oracle_ai_database_agent_tool.sql -``` -### Input Parameters required to run -- Target schema name (Schema where to the agent team needs to be installed) - -### What This Script Does - -- Grants required Select AI privileges -- Creates `SELECTAI_AGENT_CONFIG` -- Installs `ORACLE_AI_DATA_RETRIEVAL_FUNCTIONS` -- Registers all AI agent tools. - ---- - -## Installed Tools Explained - -### 1️⃣ SQL_TOOL -**Purpose:** Generate SQL from natural language and run it safely. - -**Fail-safe behavior:** -- SQL generation failure → feedback returned to the LLM -- Zero rows → agent retries using range or distinct tools - ---- - -### 2️⃣ DISTINCT_VALUES_CHECK -**Purpose:** Discover valid categorical values before filtering. - -**Use cases:** -- Status columns -- Country or region names -- Product categories - -**Matching modes:** `fuzzy` (default), `exact`, `regex` - ---- - -### 3️⃣ RANGE_VALUES_CHECK -**Purpose:** Determine minimum and maximum values for numeric, DATE, or TIMESTAMP columns. - -**Use cases:** -- Time-series analysis -- Salary or revenue ranges -- Boundary detection - ---- - -### 4️⃣ GENERATE_CHART -**Purpose:** Generate **Chart.js-compatible JSON** for visualizations. - -**Supported chart types:** -- bar, line, pie, doughnut -- radar, scatter, bubble, polarArea - ---- - -## Installation – Agent and Team - -From `google-gemini-marketplace-agents`, run: - -```sql -sqlplus admin@ @oracle_ai_database_agent.sql -``` - -You can also execute the contents of `oracle_ai_database_agent.sql` in SQL Worksheet. - -### Input Parameters required to run. -- Target schema name (Schema where to the agent team needs to be installed) -- AI Profile name (Select AI Profile name that needs to be used with the Agent) - - -### Objects Created - -| Object | Name | -|-------|------| -| Task | ORACLE_AI_DATABASE_TASK | -| Agent | ORACLE_AI_DATABASE_AGENT | -| Team | ORACLE_AI_DATABASE_TEAM | - ---- - -## Task Intelligence Highlights - -The task definition enforces: -- Tool-based reasoning -- Mandatory source attribution -- Structured, readable responses -- Explicit chart generation flow -- Retry logic for SQL failures -- Metadata-aware querying - ---- - -## Generalizing Teams Using Tools - -### Recommended Design Pattern -**Keep tools generic. -Specialize agents using tasks.** - -### Example Team Strategies - -| Team | Tools Used | Purpose | -|----|-----------|--------| -| Data Retrieval Team | All tools | General analytics | -| Finance Analytics Team | SQL + RANGE | Financial reporting | -| Visualization Team | SQL + CHART | Dashboards and insights | - -### Why This Scales Well -- Tools are reusable -- Tasks define behavior -- Agents bind AI profiles -- Teams orchestrate workflows - -### Example prompts -After creating the Oracle AI Database Agent team, you can interact with it using prompts such as: - -- “How can you help?” -- Ask questions related to the database tables associated with the selected profile. -- To generate visualizations, explicitly mention the chart type, for example: - “Generate a bar chart for the result.” (any supported chart type can be used) - ---- - -## Best Practices - -- Use `DISTINCT_VALUES_CHECK` before filtering text columns -- Use `RANGE_VALUES_CHECK` for DATE and NUMBER columns -- Maintain separate AI profiles per environment - ---- - -## License - -Universal Permissive License (UPL) 1.0 -https://oss.oracle.com/licenses/upl/ -Copyright (c) 2026 Oracle and/or its affiliates. - ---- - -## ✨ Final Thoughts - -This Oracle AI Database Agent elevates Select AI from a **SQL generator** to a **true autonomous data analyst** — capable of reasoning, validating, retrying, and visualizing data with confidence. - -Designed for: -- Domain-specific agents -- Multi-team orchestration -- UI / APEX integrations -- Autonomous dashboards diff --git a/google-gemini-marketplace-agents/oracle_ai_database_agent/oracle_ai_database_agent.sql b/google-gemini-marketplace-agents/oracle_ai_database_agent/oracle_ai_database_agent.sql deleted file mode 100644 index 04e730a..0000000 --- a/google-gemini-marketplace-agents/oracle_ai_database_agent/oracle_ai_database_agent.sql +++ /dev/null @@ -1,292 +0,0 @@ -rem ============================================================================ -rem LICENSE -rem Copyright (c) 2026 Oracle and/or its affiliates. -rem Licensed under the Universal Permissive License (UPL), Version 1.0 -rem https://oss.oracle.com/licenses/upl/ -rem -rem NAME -rem oracle_ai_database_agent.sql -rem -rem DESCRIPTION -rem Installer and configuration script for the Oracle AI Database Agent -rem using DBMS_CLOUD_AI_AGENT (Select AI / Oracle AI Database). -rem -rem This script performs an interactive installation of an -rem Oracle AI Database Agent team by: -rem - Prompting for target schema and AI Profile -rem - Granting required Select AI privileges -rem - Creating an installer procedure in the target schema -rem - Registering an NL2SQL task with supported analysis tools -rem - Creating an NL2SQL Data Retrieval AI Agent bound to the AI Profile -rem - Creating an NL2SQL Team linking the agent and task -rem - Executing the installer procedure to complete setup -rem -rem RELEASE VERSION -rem 1.1 -rem -rem RELEASE DATE -rem 06-Feb-2026 -rem -rem MAJOR CHANGES IN THIS RELEASE -rem - Initial release -rem - Added NL2SQL task, agent, and team registration -rem - Supports SQL generation, metadata analysis, -rem and chart/visualization generation -rem - Interactive installer with schema and AI profile prompts -rem -rem SCRIPT STRUCTURE -rem 1. Initialization: -rem - Enable output and error handling -rem - Prompt for target schema and AI profile -rem -rem 2. Grants: -rem - Grant DBMS_CLOUD_AI_AGENT and DBMS_CLOUD_AI -rem privileges to the target schema -rem -rem 3. Installer Procedure Creation: -rem - Create DATA_RETRIEVAL_AGENT procedure -rem in the target schema -rem -rem 4. AI Registration: -rem - Drop and create ORACLE_AI_DATABASE_TASK -rem - Drop and create ORACLE_AI_DATABASE_AGENT -rem - Drop and create ORACLE_AI_DATABASE_TEAM -rem -rem 5. Execution: -rem - Execute installer procedure with AI profile parameter -rem -rem INSTALL INSTRUCTIONS -rem 1. Connect as ADMIN or a privileged user -rem -rem 2. Run the script using SQL*Plus or SQLcl: -rem -rem sqlplus admin@db @oracle_ai_database_agent.sql -rem -rem 3. Provide inputs when prompted: -rem - Target schema name -rem - AI Profile name -rem -rem 4. Verify installation by confirming: -rem - ORACLE_AI_DATABASE_TASK exists -rem - ORACLE_AI_DATABASE_AGENT is created -rem - ORACLE_AI_DATABASE_TEAM is registered -rem -rem PARAMETERS -rem INSTALL_SCHEMA (Prompted) -rem Target schema where the installer procedure, -rem task, agent, and team are created. -rem -rem PROFILE_NAME (Prompted) -rem AI Profile name used to bind the Oracle AI Database Agent. -rem -rem NOTES -rem - Script is safe to re-run; existing tasks, agents, -rem and teams are dropped and recreated. -rem -rem - SQL data sources are clearly attributed in the -rem agent response. -rem -rem - Script exits immediately on SQL errors. -rem -rem ============================================================================ - - -SET SERVEROUTPUT ON -SET VERIFY OFF - -PROMPT ====================================================== -PROMPT Oracle AI Database Agent Installer -PROMPT ====================================================== - --- Target schema -VAR v_schema VARCHAR2(128) -EXEC :v_schema := '&SCHEMA_NAME'; - --- AI Profile -VAR v_ai_profile_name VARCHAR2(128) -EXEC :v_ai_profile_name := '&AI_PROFILE_NAME'; - - ----------------------------------------------------------------- --- 1. Grants (safe to re-run) ----------------------------------------------------------------- -DECLARE - l_sql VARCHAR2(500); - l_schema VARCHAR2(128); - l_session_user VARCHAR2(128); -BEGIN - l_schema := DBMS_ASSERT.SIMPLE_SQL_NAME(:v_schema); - l_session_user := SYS_CONTEXT('USERENV', 'SESSION_USER'); - - -- Avoid self-grant errors (ORA-01749) when target schema == connected user. - IF UPPER(l_schema) <> UPPER(l_session_user) THEN - l_sql := 'GRANT EXECUTE ON DBMS_CLOUD_AI_AGENT TO ' || l_schema; - EXECUTE IMMEDIATE l_sql; - - l_sql := 'GRANT EXECUTE ON DBMS_CLOUD_AI TO ' || l_schema; - EXECUTE IMMEDIATE l_sql; - - ELSE - DBMS_OUTPUT.PUT_LINE('Skipping grants for schema ' || l_schema || - ' (same as session user).'); - END IF; - - DBMS_OUTPUT.PUT_LINE('Grants completed.'); -END; -/ - - ----------------------------------------------------------------- --- 2. Create installer procedure in target schema ----------------------------------------------------------------- -BEGIN - EXECUTE IMMEDIATE - 'ALTER SESSION SET CURRENT_SCHEMA = ' || :v_schema; -END; -/ - -CREATE OR REPLACE PROCEDURE data_retrieval_agent ( - p_profile_name IN VARCHAR2 -) -AUTHID DEFINER -AS -BEGIN - DBMS_OUTPUT.PUT_LINE('--------------------------------------------'); - DBMS_OUTPUT.PUT_LINE('Starting Oracle AI Database Agent team installation'); - DBMS_OUTPUT.PUT_LINE('--------------------------------------------'); - - ------------------------------------------------------------ - -- Saving the profile name in SELECTAI_AGENT_CONFIG table - -- The same AI profile will be used with the tools. - ------------------------------------------------------------ - - BEGIN - - DELETE FROM SELECTAI_AGENT_CONFIG - WHERE KEY='AGENT_AI_PROFILE' AND AGENT='ORACLE_AI_DATABASE_AGENT'; - COMMIT; - - INSERT INTO SELECTAI_AGENT_CONFIG ("KEY", "VALUE", "AGENT") - VALUES ( - 'AGENT_AI_PROFILE', - p_profile_name, - 'ORACLE_AI_DATABASE_AGENT' - ); - - COMMIT; - - END; - - ------------------------------------------------------------ - -- DROP and CREATE TASK - ------------------------------------------------------------ - BEGIN - DBMS_CLOUD_AI_AGENT.DROP_TASK('ORACLE_AI_DATABASE_TASK'); - EXCEPTION - WHEN OTHERS THEN NULL; - END; - - DBMS_CLOUD_AI_AGENT.CREATE_TASK( - task_name => 'ORACLE_AI_DATABASE_TASK', - description => 'Task for natural language to SQL data retrieval, analysis, and visualization.', - attributes => - '{' || - '"instruction":"Analyze the user question: {query} and answer it using a combination of available tools. ' || - 'Always respond in a professional manner without any greetings. ' || - 'If the request requires database data, use SQL_TOOL to generate and execute SQL. ' || - 'If the query involves database object metadata, you may use the following metadata: {ORA$AI_PROFILE}. ' || - 'If the question involves charts, graphs, plots, or visualizations, first gather the required data using appropriate tools, ' || - 'then invoke the GENERATE_CHART tool with a detailed prompt to generate the chart configuration. ' || - 'In the final response, first provide a concise textual summary of the data or visualization, ' || - 'then include the raw JSON output from the GENERATE_CHART tool wrapped in a markdown code block using ```chartjs and closing with ```. ' || - 'Do not modify, reformat, or add any extra text inside the JSON block. ' || - 'You may use DISTINCT_VALUES_CHECK or RANGE_VALUES_CHECK tools to analyze column values, ' || - 'but you must clearly explain which values were selected and why in the final response. ' || - 'Always present answers in a clearly formatted and readable manner using bullet points. ' || - 'At the end of the response, add a blank line followed by a **Sources** section. ' || - 'If SQL_TOOL was used, include the source tag * ORACLE AI DATABASE. ' || - 'Use {current_location} to identify the user location when required. ' || - 'Use {logged_in_user} to identify the current user when required. ' || - 'Current system time: {current_time}. ' || - '",' || - '"tools":[' || - '"SQL_TOOL",' || - '"DISTINCT_VALUES_CHECK",' || - '"RANGE_VALUES_CHECK",' || - '"GENERATE_CHART"' || - '],' || - '"enable_human_tool":"false"' || - '}' - ); - - DBMS_OUTPUT.PUT_LINE('Created task ORACLE_AI_DATABASE_TASK'); - - ------------------------------------------------------------ - -- DROP and CREATE AGENT - ------------------------------------------------------------ - BEGIN - DBMS_CLOUD_AI_AGENT.DROP_AGENT('ORACLE_AI_DATABASE_AGENT'); - DBMS_OUTPUT.PUT_LINE('Dropped agent ORACLE_AI_DATABASE_AGENT'); - EXCEPTION - WHEN OTHERS THEN - DBMS_OUTPUT.PUT_LINE('Agent ORACLE_AI_DATABASE_AGENT does not exist, skipping'); - END; - - DBMS_CLOUD_AI_AGENT.CREATE_AGENT( - agent_name => 'ORACLE_AI_DATABASE_AGENT', - attributes => - '{' || - '"profile_name":"' || p_profile_name || '",' || - '"role":"You are a professional data analyst with deep knowledge of SQL, PL/SQL, and modern database features who owns different custom databases. ' || - 'Always answer in a professional manner without any greetings."' || - '}', - description => 'AI agent for natural language to SQL data retrieval' - ); - - DBMS_OUTPUT.PUT_LINE('Created agent ORACLE_AI_DATABASE_AGENT'); - - ------------------------------------------------------------ - -- DROP and CREATE TEAM - ------------------------------------------------------------ - BEGIN - DBMS_CLOUD_AI_AGENT.DROP_TEAM('ORACLE_AI_DATABASE_TEAM'); - DBMS_OUTPUT.PUT_LINE('Dropped team ORACLE_AI_DATABASE_TEAM'); - EXCEPTION - WHEN OTHERS THEN - DBMS_OUTPUT.PUT_LINE('Team ORACLE_AI_DATABASE_TEAM does not exist, skipping'); - END; - - DBMS_CLOUD_AI_AGENT.CREATE_TEAM( - team_name => 'ORACLE_AI_DATABASE_TEAM', - attributes => - '{' || - '"agents":[{"name":"ORACLE_AI_DATABASE_AGENT","task":"ORACLE_AI_DATABASE_TASK"}],' || - '"process":"sequential"' || - '}', - description => - 'Oracle AI Database Agent provides a natural language interface for querying enterprise data stored in Oracle AI Database on Google Cloud. Integrated with Gemini Enterprise, this agent removes the need to build custom natural language processing pipelines by automatically translating plain text inputs into SQL queries. It executes these queries against your Oracle database, retrieves results, and returns formatted data interpretations, all within the Gemini experience.' - ); - - DBMS_OUTPUT.PUT_LINE('Created team ORACLE_AI_DATABASE_TEAM'); - - DBMS_OUTPUT.PUT_LINE('------------------------------------------------'); - DBMS_OUTPUT.PUT_LINE('Oracle AI Database Team installation COMPLETE'); - DBMS_OUTPUT.PUT_LINE('------------------------------------------------'); - -END data_retrieval_agent; -/ - ----------------------------------------------------------------- --- 3. Execute installer in target schema ----------------------------------------------------------------- -PROMPT Executing installer procedure ... -BEGIN - data_retrieval_agent(p_profile_name => :v_ai_profile_name); -END; -/ - -PROMPT ====================================================== -PROMPT Installation finished successfully -PROMPT ====================================================== - -alter session set current_schema = ADMIN; diff --git a/google-gemini-marketplace-agents/oracle_ai_database_agent/oracle_ai_database_agent_tool.sql b/google-gemini-marketplace-agents/oracle_ai_database_agent/oracle_ai_database_agent_tool.sql deleted file mode 100644 index a25cdf9..0000000 --- a/google-gemini-marketplace-agents/oracle_ai_database_agent/oracle_ai_database_agent_tool.sql +++ /dev/null @@ -1,602 +0,0 @@ -rem ============================================================================ -rem LICENSE -rem Copyright (c) 2026 Oracle and/or its affiliates. -rem Licensed under the Universal Permissive License (UPL), Version 1.0 -rem https://oss.oracle.com/licenses/upl/ -rem -rem NAME -rem oracle_ai_database_agent_tool.sql -rem -rem DESCRIPTION -rem Installer script for Oracle AI Database Agent tools. -rem (Select AI Agent / Oracle AI Database). -rem -rem This script installs a consolidated PL/SQL package and registers -rem AI Agent tools used by the Oracle AI Database Agent to refine -rem Select AI NL2SQL operations via Select AI Agent -rem (Oracle AI Database). -rem -rem RELEASE VERSION -rem 1.1 -rem -rem RELEASE DATE -rem 6-Feb-2026 -rem -rem MAJOR CHANGES IN THIS RELEASE -rem - Run compatibility with Web SQL Developer -rem -rem SCRIPT STRUCTURE -rem 1. Initialization: -rem - Grants -rem - Configuration table setup -rem -rem 2. Package Deployment: -rem - oracle_ai_data_retrieval_functions -rem (package specification and body) -rem -rem 3. AI Tool Setup: -rem - Creation of all Oracle AI Database Agent tools -rem -rem INSTALL INSTRUCTIONS -rem 1. Connect as ADMIN or a user with required privileges -rem 2. Run the script using websqldeveloper/SQL Developer -rem 3. Verify installation by checking tool registration -rem and package compilation status. -rem -rem PARAMETERS -rem SCHEMA_NAME (Required) -rem Schema in which the package and tools will be created. -rem ---------------------------------------------------------------------------- -rem -rem ============================================================================ - - -SET SERVEROUTPUT ON -SET VERIFY OFF - --- ============================================================================ --- Installation Parameters --- ============================================================================ - --- First argument: Schema Name (Required) -VAR v_schema VARCHAR2(128) -EXEC :v_schema := '&SCHEMA_NAME'; - -PROMPT -PROMPT This installer registers database-native tools only. -PROMPT No additional configuration is required. -PROMPT - - -CREATE OR REPLACE PROCEDURE initialize_oracle_ai_data_retrieval_agent( - p_install_schema_name IN VARCHAR2 -) -IS - l_schema_name VARCHAR2(128); - - TYPE priv_list_t IS VARRAY(200) OF VARCHAR2(4000); - l_priv_list CONSTANT priv_list_t := priv_list_t( - 'DBMS_CLOUD_AI', - 'DBMS_CLOUD_AI_AGENT' - ); - - ---------------------------------------------------------------------------- - -- Helper: grant execute on list of objects - ---------------------------------------------------------------------------- - PROCEDURE execute_grants(p_schema IN VARCHAR2, p_objects IN priv_list_t) IS - l_session_user VARCHAR2(128); - BEGIN - l_session_user := SYS_CONTEXT('USERENV', 'SESSION_USER'); - - -- Avoid self-grant errors (ORA-01749) when installer schema == connected user. - IF UPPER(p_schema) = UPPER(l_session_user) THEN - DBMS_OUTPUT.PUT_LINE('Skipping grants for schema ' || p_schema || - ' (same as session user).'); - RETURN; - END IF; - - EXECUTE IMMEDIATE 'GRANT SELECT ON SYS.V_$PDBS TO ' || p_schema; - FOR i IN 1 .. p_objects.COUNT LOOP - BEGIN - EXECUTE IMMEDIATE 'GRANT EXECUTE ON ' || p_objects(i) || ' TO ' || p_schema; - EXCEPTION - WHEN OTHERS THEN - DBMS_OUTPUT.PUT_LINE('Warning: failed to grant ' || p_objects(i) || - ' to ' || p_schema || ' - ' || SQLERRM); - END; - END LOOP; - - EXCEPTION - WHEN OTHERS THEN - RAISE; - END execute_grants; - -BEGIN - -- Validate schema name to avoid SQL injection when used in identifiers - l_schema_name := DBMS_ASSERT.SIMPLE_SQL_NAME(p_install_schema_name); - - -- Grant required execute privileges using helper - execute_grants(l_schema_name, l_priv_list); - - -- Create generic agent config table - BEGIN - EXECUTE IMMEDIATE - 'CREATE TABLE ' || l_schema_name || '.SELECTAI_AGENT_CONFIG ( - "ID" NUMBER GENERATED BY DEFAULT AS IDENTITY, - "KEY" VARCHAR2(200) NOT NULL, - "VALUE" CLOB, - "AGENT" VARCHAR2(128) NOT NULL, - CONSTRAINT SELECTAI_AGENT_CONFIG_PK PRIMARY KEY ("ID"), - CONSTRAINT SELECTAI_AGENT_CONFIG_UK UNIQUE ("KEY","AGENT") - )'; - EXCEPTION - WHEN OTHERS THEN - IF SQLCODE = -955 THEN - NULL; -- already exists - ELSE - RAISE; - END IF; - END; - - DBMS_OUTPUT.PUT_LINE('initialize_oracle_ai_data_retrieval_agent completed for schema ' || l_schema_name); -EXCEPTION - WHEN OTHERS THEN - DBMS_OUTPUT.PUT_LINE('Fatal error in initialize_oracle_ai_data_retrieval_agent: ' || SQLERRM); - RAISE; - -END initialize_oracle_ai_data_retrieval_agent; -/ - -------------------------------------------------------------------------------- --- Run the setup for the Oracle AI Database Agent tools. -------------------------------------------------------------------------------- -BEGIN - - initialize_oracle_ai_data_retrieval_agent( - p_install_schema_name => :v_schema - ); - -END; -/ - -BEGIN - EXECUTE IMMEDIATE - 'ALTER SESSION SET CURRENT_SCHEMA = ' || :v_schema; -END; -/ - ------------------------------------------------------------------------- --- Package specification ------------------------------------------------------------------------- -CREATE OR REPLACE PACKAGE oracle_ai_data_retrieval_functions -AS - FUNCTION get_distinct_values_func( - schema_name IN VARCHAR2, - table_name IN VARCHAR2, - column_name IN VARCHAR2, - match_pattern IN VARCHAR2 DEFAULT NULL, - match_type IN VARCHAR2 DEFAULT NULL - ) RETURN CLOB; - - FUNCTION get_range_values_func( - user_prompt IN CLOB - ) RETURN CLOB; - - FUNCTION get_current_timestamp( - p_format IN VARCHAR2 DEFAULT 'YYYY-MM-DD HH24:MI:SS.FF' - ) RETURN CLOB; - - FUNCTION runsql_func( - user_prompt IN CLOB - ) RETURN CLOB; - - FUNCTION generate_chart_func( - chart_prompt IN CLOB - ) RETURN CLOB; - -END oracle_ai_data_retrieval_functions; -/ - ------------------------------------------------------------------------- --- Package body ------------------------------------------------------------------------- -CREATE OR REPLACE PACKAGE BODY oracle_ai_data_retrieval_functions -AS - FUNCTION get_distinct_values_func ( - schema_name IN VARCHAR2, - table_name IN VARCHAR2, - column_name IN VARCHAR2, - match_pattern IN VARCHAR2 DEFAULT NULL, - match_type IN VARCHAR2 DEFAULT NULL - ) RETURN CLOB IS - l_sql VARCHAR2(4000); - l_result CLOB; - l_data_type VARCHAR2(128); - max_length PLS_INTEGER := 32767; - l_match_type VARCHAR2(10); - l_threshold NUMBER := 50; -- fuzzy similarity threshold (0–100) - BEGIN - -- Fetch column data type - l_sql := 'SELECT data_type FROM all_tab_columns - WHERE owner = :1 - AND table_name = :2 - AND column_name = :3'; - EXECUTE IMMEDIATE l_sql INTO l_data_type - USING schema_name, table_name, column_name; - - -- Normalize match_type input - IF TRIM(match_pattern) IS NOT NULL AND - NVL(LOWER(TRIM(match_type)), 'NULL') NOT IN ('fuzzy', 'regex', 'exact') THEN - l_match_type := 'fuzzy'; - ELSE - l_match_type := LOWER(TRIM(match_type)); - END IF; - - -- Main matching logic - IF match_pattern IS NOT NULL AND LENGTH(TRIM(match_pattern)) > 0 THEN - l_sql := 'SELECT JSON_ARRAYAGG(col RETURNING CLOB) FROM (' || - 'SELECT DISTINCT ' || DBMS_ASSERT.enquote_name(column_name) || ' AS col ' || - 'FROM ' || DBMS_ASSERT.sql_object_name(schema_name || '.' || table_name); - - CASE l_match_type - WHEN 'fuzzy' THEN - l_sql := l_sql || - ' WHERE FUZZY_MATCH(JARO_WINKLER, ' || DBMS_ASSERT.enquote_name(column_name) || ', :pattern) >= :threshold)'; - EXECUTE IMMEDIATE l_sql INTO l_result USING match_pattern, l_threshold; - - WHEN 'exact' THEN - l_sql := l_sql || - ' WHERE ' || DBMS_ASSERT.enquote_name(column_name) || ' = :pattern)'; - EXECUTE IMMEDIATE l_sql INTO l_result USING match_pattern; - - WHEN 'regex' THEN - l_sql := l_sql || - ' WHERE REGEXP_LIKE(' || DBMS_ASSERT.enquote_name(column_name) || ', :pattern, ''i''))'; - EXECUTE IMMEDIATE l_sql INTO l_result USING match_pattern; - - ELSE - raise_application_error(-20000, INITCAP(l_match_type) || ' match type is not supported.'); - - END CASE; - END IF; - - -- Fallback: return all distinct values - IF l_result IS NULL THEN - l_sql := - 'SELECT JSON_ARRAYAGG(col RETURNING CLOB) FROM (' || - 'SELECT DISTINCT ' || DBMS_ASSERT.enquote_name(column_name) || ' AS col ' || - 'FROM ' || DBMS_ASSERT.sql_object_name(schema_name || '.' || table_name) || ')'; - EXECUTE IMMEDIATE l_sql INTO l_result; - END IF; - - -- Truncate long results - IF l_result IS NOT NULL AND DBMS_LOB.getlength(l_result) > max_length THEN - l_result := SUBSTR(l_result, 1, max_length - 1) - || ',"notice":"Results truncated to ' - || TO_CHAR(max_length) || ' characters."}'; - END IF; - - RETURN l_result; - - EXCEPTION - WHEN NO_DATA_FOUND THEN - RETURN '{"error": "Column not found."}'; - WHEN OTHERS THEN - RETURN '{"error": "' || REPLACE(SQLERRM, '"', '''') || '"}'; - END get_distinct_values_func; - - - - FUNCTION get_current_timestamp( - p_format IN VARCHAR2 DEFAULT 'YYYY-MM-DD HH24:MI:SS.FF' - ) RETURN CLOB - IS - l_timestamp TIMESTAMP := SYSTIMESTAMP; - l_clob CLOB; - BEGIN - l_clob := TO_CLOB(TO_CHAR(l_timestamp, p_format)); - RETURN l_clob; - END; - - - - FUNCTION get_range_values_func( - user_prompt IN CLOB - ) RETURN CLOB - IS - l_sql CLOB; - l_wrapped_sql CLOB; - l_sql_result CLOB; - l_json_result CLOB; - l_obj JSON_OBJECT_T:=new JSON_OBJECT_T(); - MAX_ROWS CONSTANT PLS_INTEGER := 1000; - SORRY_MESSAGE CONSTANT VARCHAR2(4000) := 'Sorry, unfortunately a valid SELECT statement could not be generated '; - l_ai_profile VARCHAR2(4000); - BEGIN - ------------------------------------------------------------------ - -- Fetch AI profile from SELECTAI_AGENT_CONFIG - ------------------------------------------------------------------ - SELECT value - INTO l_ai_profile - FROM selectai_agent_config - WHERE agent = 'ORACLE_AI_DATABASE_AGENT' - AND key = 'AGENT_AI_PROFILE'; - - BEGIN - l_sql := DBMS_CLOUD_AI.generate(prompt => user_prompt, - profile_name => l_ai_profile, - action => 'showsql'); - EXCEPTION - WHEN OTHERS THEN - RETURN 'Error Encountered: ' || SQLERRM; - END; - -- Check if SQL generation failed - -- If failed, we directly give the generated sql back to LLM - -- We want the LLM invoke the tool again with a better user prompt based on the sorry message - IF INSTR(l_sql, SORRY_MESSAGE) = 1 THEN - RETURN l_sql; - END IF; - -- Execute the SQL - - l_wrapped_sql := 'SELECT JSON_ARRAYAGG(JSON_OBJECT(* RETURNING CLOB) RETURNING CLOB) result ' || - 'FROM ( select * from (' || l_sql || ' ) FETCH FIRST ' || TO_CHAR(MAX_ROWS) || ' ROWS ONLY)'; - -- Execute the SQL - EXECUTE IMMEDIATE l_wrapped_sql - INTO l_sql_result; - - l_obj.put('sql_query',l_sql); - - IF l_sql_result is NULL THEN - l_obj.put('sql_result','No data found.'); - ELSE - l_obj.put('sql_result',JSON_ARRAY_T.PARSE(l_sql_result)); - END IF; - - RETURN l_obj.to_clob(); - - EXCEPTION - WHEN NO_DATA_FOUND THEN - RETURN '{"error":"AI profile not configured in SELECTAI_AGENT_CONFIG"}'; - WHEN OTHERS THEN - RETURN 'Run SQL exception encountered: ' || SQLERRM ; - END get_range_values_func; - - - - FUNCTION runsql_func( - user_prompt IN CLOB - ) RETURN CLOB - IS - l_sql CLOB; - l_wrapped_sql CLOB; - l_sql_result CLOB; - l_json_result CLOB; - l_obj JSON_OBJECT_T:=new JSON_OBJECT_T(); - MAX_ROWS CONSTANT PLS_INTEGER := 1000; - SORRY_MESSAGE CONSTANT VARCHAR2(4000) := 'Sorry, unfortunately a valid SELECT statement could not be generated '; - l_ai_profile VARCHAR2(4000); - BEGIN - ------------------------------------------------------------------ - -- Fetch AI profile from SELECTAI_AGENT_CONFIG - ------------------------------------------------------------------ - SELECT value - INTO l_ai_profile - FROM selectai_agent_config - WHERE agent = 'ORACLE_AI_DATABASE_AGENT' - AND key = 'AGENT_AI_PROFILE'; - - BEGIN - l_sql := DBMS_CLOUD_AI.generate(prompt => user_prompt, - profile_name => l_ai_profile, - action => 'showsql'); - EXCEPTION - WHEN OTHERS THEN - RETURN 'Error Encountered: ' || SQLERRM; - END; - -- Check if SQL generation failed - -- If failed, we directly give the generated sql back to LLM - -- We want the LLM invoke the tool again with a better user prompt based on the sorry message - IF INSTR(l_sql, SORRY_MESSAGE) = 1 THEN - RETURN l_sql; - END IF; - -- Execute the SQL - - l_wrapped_sql := 'SELECT JSON_ARRAYAGG(JSON_OBJECT(* RETURNING CLOB) RETURNING CLOB) result ' || - 'FROM ( select * from (' || l_sql || ' ) FETCH FIRST ' || TO_CHAR(MAX_ROWS) || ' ROWS ONLY)'; - -- Execute the SQL - EXECUTE IMMEDIATE l_wrapped_sql - INTO l_sql_result; - - l_obj.put('sql_query',l_sql); - - IF l_sql_result is NULL THEN - l_obj.put('sql_result','No data found.'); - ELSE - l_obj.put('sql_result',JSON_ARRAY_T.PARSE(l_sql_result)); - END IF; - - RETURN l_obj.to_clob(); - - - EXCEPTION - WHEN NO_DATA_FOUND THEN - RETURN '{"error":"AI profile not configured in SELECTAI_AGENT_CONFIG"}'; - WHEN OTHERS THEN - RETURN 'Run SQL exception encountered: ' || SQLERRM ; - - END runsql_func; - - - - ------------------------------------------------------------------------------------ - -- generate_chart_func - to generate the charts - ------------------------------------------------------------------------------------ - FUNCTION generate_chart_func( - chart_prompt IN CLOB - ) RETURN CLOB - IS - l_full_prompt CLOB; - l_result CLOB; - l_ai_profile VARCHAR2(4000); - BEGIN - ------------------------------------------------------------------ - -- Fetch AI profile from SELECTAI_AGENT_CONFIG - ------------------------------------------------------------------ - SELECT value - INTO l_ai_profile - FROM selectai_agent_config - WHERE agent = 'ORACLE_AI_DATABASE_AGENT' - AND key = 'AGENT_AI_PROFILE'; - - ------------------------------------------------------------------ - -- Build prompt - ------------------------------------------------------------------ - l_full_prompt := - 'You are a helpful assistant that generates Chart.js configurations in valid JSON format based on user prompts.' || CHR(10) || - '' || CHR(10) || - 'Rules:' || CHR(10) || - '- Output ONLY a single valid JSON object or array of JSON objects. No markdown, no code blocks, no explanations.' || CHR(10) || - '- JSON must be syntactically valid. No comments. No text outside braces. No trailing commas.' || CHR(10) || - '- Use only these Chart.js types: "bar", "line", "pie", "doughnut", "radar", "scatter", "bubble", "polarArea".' || CHR(10) || - '- Ensure "labels" and "datasets" arrays are properly formatted.' || CHR(10) || - '- For "backgroundColor" and "borderColor", use ONLY colors from this palette and repeat as needed:' || CHR(10) || - ' ["#007bff", "#6c757d", "#28a745", "#ffc107", "#dc3545",' || CHR(10) || - ' "#20c997", "#6610f2", "#e83e8c", "#fd7e14", "#17a2b8",' || CHR(10) || - ' "#8bc34a", "#673ab7", "#03a9f4", "#ff9800", "#ff5722",' || CHR(10) || - ' "#4caf50", "#795548", "#607d8b", "#c2185b", "#343a40"]' || CHR(10) || - '- Do NOT output this palette again in the JSON. Just use these colors as values.' || CHR(10) || - '- Example of correct output:' || CHR(10) || - '{' || CHR(10) || - ' "type": "bar",' || CHR(10) || - ' "data": {' || CHR(10) || - ' "labels": ["A", "B", "C", "D", "E"],' || CHR(10) || - ' "datasets": [{' || CHR(10) || - ' "label": "Dataset 1",' || CHR(10) || - ' "data": [10, 20, 30, 40, 50],' || CHR(10) || - ' "backgroundColor": ["#007bff", "#6c757d", "#28a745", "#ffc107", "#dc3545"],' || CHR(10) || - ' "borderColor": ["#007bff", "#6c757d", "#28a745", "#ffc107", "#dc3545"],' || CHR(10) || - ' "borderWidth": 1' || CHR(10) || - ' }]' || CHR(10) || - ' },' || CHR(10) || - ' "options": {' || CHR(10) || - ' "responsive": true,' || CHR(10) || - ' "plugins": {' || CHR(10) || - ' "title": {"display": true, "text": "Sample Chart"}' || CHR(10) || - ' }' || CHR(10) || - ' }' || CHR(10) || - '}' || CHR(10) || - chart_prompt; - - ------------------------------------------------------------------ - -- Invoke Select AI using configured profile - ------------------------------------------------------------------ - l_result := - DBMS_CLOUD_AI.generate( - prompt => l_full_prompt, - profile_name => l_ai_profile, - action => 'chat' - ); - - RETURN l_result; - - EXCEPTION - WHEN NO_DATA_FOUND THEN - RETURN '{"error":"AI profile not configured in SELECTAI_AGENT_CONFIG"}'; - WHEN OTHERS THEN - RETURN '{"error":"' || REPLACE(SQLERRM, '"', '\\"') || '"}'; - END generate_chart_func; - -END oracle_ai_data_retrieval_functions; -/ - - ------------------------------------------------------------------------------------------- --- This procedure installs or refreshes the NL2SQL data retrieval Agent tools in the --- current schema. It drops any existing tool definitions and recreates them --- pointing to the latest implementations in oracle_ai_data_retrieval_functions. ------------------------------------------------------------------------------------------- - -CREATE OR REPLACE PROCEDURE initialize_oracle_ai_data_retrieval_tools -IS - PROCEDURE drop_tool_if_exists (tool_name IN VARCHAR2) IS - l_tool_count NUMBER; - l_sql CLOB; - BEGIN - l_sql := 'SELECT COUNT(*) FROM USER_AI_AGENT_TOOLS WHERE TOOL_NAME = :1'; - EXECUTE IMMEDIATE l_sql INTO l_tool_count USING tool_name; - IF l_tool_count > 0 THEN - DBMS_CLOUD_AI_AGENT.DROP_TOOL(tool_name); - END IF; - END drop_tool_if_exists; -BEGIN - drop_tool_if_exists(tool_name => 'DISTINCT_VALUES_CHECK'); - - DBMS_CLOUD_AI_AGENT.create_tool( - tool_name => 'DISTINCT_VALUES_CHECK', - description => 'Returns all unique values from a specified database column. Supports optional pattern matching to help filter results, making it easier to discover or troubleshoot specific data entries.', - attributes => '{"instruction": "This tool returns distinct values from a specified column in a given table. ' || - 'If match_pattern is specified, then match_type must also be specified.' || - 'If both match_pattern and match_type are provided, the tool will filter distinct values using the specified matching technique.' || - 'If no matching values are found for the match_pattern, or if match_pattern was not specified, then the tool will return distinct values from the column.", - "function": "oracle_ai_data_retrieval_functions.get_distinct_values_func", - "tool_inputs": [{"name": "match_type", - "mandatory": false, - "description": "Type of filtering technique to use: ' || - '1.fuzzy - uses FUZZY MATCH string comparison in Oracle 23ai; ' || - '2.exact - uses ''='' operator for exact matches; ' || - '3.regex - uses REGEXP_LIKE for regular expression matching of the pattern."}, - {"name": "match_pattern", - "mandatory": false, - "description": "Pattern or keyword to filter values. If provided, matching_type must also be specified."} - ]}' - ); - - drop_tool_if_exists(tool_name => 'SQL_TOOL'); - - DBMS_CLOUD_AI_AGENT.create_tool( - tool_name => 'SQL_TOOL', - description => 'Generates a SQL query from the provided natural language prompt and runs that query against your Oracle AI Database, returning the results. If no data is found, consider revising your prompt to be more descriptive.', - attributes => '{"instruction": "This tool can access the data in database. It will take user question as user_prompt and generate a sql query, and then it will execute the sql query to get the result' || - ' If the result is 0 rows. It''s possible that there is an predicates issue. Please use RANGE_VALUES_CHECK for Numeric, DATE, or TIMESTAMP types or DISTINCT_VALUES_CHECK tool for other datatype columns to get all the distinct values and reinvoke the tool with a refined the user question", - "function": "oracle_ai_data_retrieval_functions.runsql_func"}' - ); - - drop_tool_if_exists(tool_name => 'RANGE_VALUES_CHECK'); - - DBMS_CLOUD_AI_AGENT.create_tool( - tool_name => 'RANGE_VALUES_CHECK', - description => 'Retrieves the minimum and maximum values for a numeric, date, or timestamp column in your table. Useful for understanding data boundaries or refining searches.', - attributes => '{ - "instruction": "This tool returns the minimum and maximum (range) values of a column in the given table. Only Numeric, DATE, or TIMESTAMP types columns are supported.", - "function": "oracle_ai_data_retrieval_functions.get_range_values_func" - }' - ); - - drop_tool_if_exists(tool_name => 'GENERATE_CHART'); - - DBMS_CLOUD_AI_AGENT.create_tool( - tool_name => 'GENERATE_CHART', - description => 'Creates charts or visualizations based on your data and preferences. Specify chart type, underlying data, and labels to generate formatted HTML or image output for display.', - attributes => '{"instruction": "Use this tool when you need to generate a chart, graph, or visualization based on data. Provide a detailed prompt describing the chart type, data, labels, titles, and any other details. The tool will return formatted HTML for embedding the chart in the response.", - "function": "oracle_ai_data_retrieval_functions.generate_chart_func"}' - ); - - DBMS_OUTPUT.PUT_LINE('initialize_oracle_ai_data_retrieval_tools completed.'); - -EXCEPTION - WHEN OTHERS THEN - DBMS_OUTPUT.PUT_LINE('Error in initialize_oracle_ai_data_retrieval_tools: ' || SQLERRM); - RAISE; - -END initialize_oracle_ai_data_retrieval_tools; -/ - -------------------------------------------------------------------------------- --- Call the procedure to (re)create all Oracle AI Database Agent tools -------------------------------------------------------------------------------- -BEGIN - initialize_oracle_ai_data_retrieval_tools; -END; -/ - -alter session set current_schema = ADMIN;