Skip to main content

Concepts API

The Concepts API allows you to manage and execute Vadalog concepts within projects. This is one of the core APIs for working with logical reasoning and data analysis.


Save Concept

Save or update a concept with Vadalog logic and optional Python scripts.

import prometheux_chain as px

# Define the concept in Vadalog
concept_def = """
company("Apple", "Redwood City, CA").
company("Google", "Mountain View, CA").
company("Microsoft", "Redmond, WA").

location(Location) <- company(_,Location).

@output("location").
"""

# Save the concept
result = px.save_concept(
project_id="my_project_id",
definition=concept_def
)

Function Signature

def save_concept(project_id, definition, python_scripts=None, scope="user",
description=None, concept_type="logic", concept_name=None,
binds=None, output_predicate="", existing_name=None,
position=None, group="group_id", compute=None)

Parameters

ParameterTypeRequiredDescription
project_idstrYesThe project identifier
definitionstrYesThe Vadalog rules, SQL query, or Python logic defining the concept (depending on concept_type)
python_scriptsdictNoDictionary of Python scripts to inject. Keys are script names, values are script content
scopestrNoThe scope of the concept. Defaults to "user"
descriptionstrNoHuman-readable description of the concept
concept_typestrNo"logic" or "sql". Defaults to "logic"
concept_namestrConditionalRequired for SQL concepts
bindsdictNoOptional binding parameters
output_predicatestrNoOutput predicate name. Defaults to ""
existing_namestrNoWhen updating, the name of the existing concept
positionobjectNoOptional layout position metadata
groupstrNoConcept group identifier. Defaults to "group_id"
computedictNoOptional compute configuration

Returns

The response data from saving the concept.

Example with Python Script Injection

import prometheux_chain as px

# Define a Python script with proper structure
python_script = """
import json

def main():
# Simple calculations
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# Calculate basic statistics
total = sum(numbers)
average = total / len(numbers)
maximum = max(numbers)
minimum = min(numbers)

# Create results as a list of dictionaries (tabular format)
results = [
{
"Numbers": numbers,
"Total": total,
"Average": round(average, 2),
"Maximum": maximum,
"Minimum": minimum,
"Count": len(numbers)
}
]

return results
"""

# Define the concept that uses Python script execution
concept_def = """
@output("test_python").
test_python(Numbers,Total,Average,Maximum,Minimum,Count) <- python:run("python_script").
"""

# Save the concept with Python script injection
result = px.save_concept(
project_id="my_project_id",
definition=concept_def,
python_scripts={
"python_script": python_script
}
)

Python Script Injection Requirements

When using Python script injection with save_concept, there are specific requirements that must be followed:

1. Main Function Requirement

Every Python script must contain a main() function that serves as the entry point. The function can optionally accept a params argument to receive @param values (see Using Parameters below). Scripts with a zero-argument main() continue to work as before.

def main():
# Your script logic here
return results

# Or, to receive @param values:
def main(params):
city = params["city"]
return results

2. Tabular Output Format

The main() function must return results in a tabular format, as a list of dictionaries:

def main():
results = [
{
"Column1": value1,
"Column2": value2,
"Column3": value3
}
]
return results

3. Concept Head Alignment

Output column names must match the parameters in the concept head:

# Python script returns:
results = [{"Numbers": [1, 2, 3], "Total": 6, "Average": 2.0}]

# Vadalog concept head must match:
test_python(Numbers, Total, Average) <- python:run("python_script").

4. Standalone Concept Rule

Python script concepts must be standalone:

# ✅ Correct - standalone Python script concept
@output("my_python_concept").
my_python_concept(Col1, Col2) <- python:run("my_script").

# ❌ Incorrect - cannot combine with other logic
@output("mixed_concept").
mixed_concept(Col1, Col2) <- python:run("my_script"), other_predicate(Col1).

5. Using Parameters in Python Scripts

Python concepts support @param annotations, the same mechanism used by Vadalog and SQL concepts. Declare default values in the concept definition, and the script receives them as a dictionary:

# Concept definition
@param("city", "Rome").
@param("year", 2024).
weather(City, Year, Temp) :- python:run("fetch_weather").
@output("weather").
# Python script — main(params) receives the merged parameters
def main(params):
city = params["city"] # "Rome" (from @param default)
year = params["year"] # 2024
return [
{"City": city, "Year": year, "Temp": "22C"},
{"City": city, "Year": year, "Temp": "30C"},
]

Runtime overrides work the same way as other concept types — pass params in the run call to override stored defaults:

# Stored @param("city","Rome") is overridden by runtime param
result = px.run_concept("my_project_id", "weather", params={"city": "Milan"})

Parameter propagation: when a concept with @param annotations is run, its parameters propagate to all dependency concepts in the execution chain. This means you can declare parameters at the top-level concept and have them flow to Python (and other) dependencies automatically, without redeclaring them on each dependency.


Run Concept

Execute a concept with specified parameters. This is the main endpoint for running Vadalog logic.

import prometheux_chain as px

# Run a concept with parameters
results = px.run_concept(
project_id="my_project_id",
concept_name="location",
params={"filter_city": "CA"},
persist_outputs=True
)

Function Signature

def run_concept(project_id, concept_name, params=None, scope="user",
force_rerun=True, persist_outputs=False, compute=None)

Parameters

ParameterTypeRequiredDescription
project_idstrYesThe project identifier
concept_namestrYesThe name of the concept to run
paramsdictNoParameters to pass to the concept execution
scopestrNoThe scope of the project. Defaults to "user"
force_rerunboolNoForce rerun even if results exist. Defaults to True
persist_outputsboolNoPersist the outputs. Defaults to False (SDK) / True (REST)
computedictNoOptional compute configuration

Returns

The execution results data.

Response

{
"data": {
"execution_id": "exec_12345",
"results": [...],
"execution_time": 1.23,
"rows_processed": 1500
},
"message": "Concept executed successfully",
"status": "success"
}

Fetch Results

Paginated fetch of stored results for an output predicate.

import prometheux_chain as px

rows = px.fetch_results(
project_id="my_project_id",
output_predicate="location",
page=1,
page_size=10,
scope="user",
order_by=None,
)

Function Signature

def fetch_results(project_id, output_predicate, page=1, page_size=10,
scope="user", order_by=None)

Parameters

ParameterTypeRequiredDescription
project_idstrYesThe project identifier
output_predicatestrYesOutput predicate name to fetch results for
pageintNoPage number. Defaults to 1
page_sizeintNoPage size. Defaults to 10
scopestrNoProject scope. Defaults to "user"
order_bystrNoOptional ordering expression

Returns

Paginated result data for the output predicate.


List Concepts

List all concepts in a project.

import prometheux_chain as px

# List all concepts in a project
concepts = px.list_concepts(project_id="my_project_id")
print(f"Available concepts: {concepts}")

Function Signature

def list_concepts(project_id, scope="user")

Parameters

ParameterTypeRequiredDescription
project_idstrYesThe project identifier
scopestrNoThe scope of the project. Defaults to "user"

Returns

List of concept information dictionaries.


Cleanup Concepts

Delete concepts from a project.

import prometheux_chain as px

# Clean up all concepts in a project
result = px.cleanup_concepts(project_id="my_project_id")

# Clean up specific concepts by name
result = px.cleanup_concepts(
project_id="my_project_id",
concept_names=["ordered_bom", "product_analysis"],
)

Function Signature

def cleanup_concepts(project_id, scope="user", concept_names=None)

Parameters

ParameterTypeRequiredDescription
project_idstrYesThe project identifier
scopestrNoThe scope of the project. Defaults to "user"
concept_nameslistNoSpecific concept names to delete; if omitted, deletes all matching concepts in scope

Complete Workflow Example

import prometheux_chain as px
import os

# Set up authentication and configuration
os.environ['PMTX_TOKEN'] = 'my_pmtx_token'
px.config.set('JARVISPY_URL', "https://api.prometheux.ai/jarvispy/my-org/my-user")

# Create a project
project_id = px.save_project(project_name="concept_demo")

# Define and save a concept
concept_def = """
company("Apple", "Redwood City, CA").
company("Google", "Mountain View, CA").
company("Microsoft", "Redmond, WA").

location(Location) <- company(_,Location).

@output("location").
"""

px.save_concept(project_id=project_id, definition=concept_def)

# List all concepts
concepts = px.list_concepts(project_id=project_id)
print(f"Available concepts: {concepts}")

# Run the concept
results = px.run_concept(project_id=project_id, concept_name="location")
print(f"Results: {results}")

# Fetch paginated results for the output predicate
fetched = px.fetch_results(
project_id=project_id,
output_predicate="location",
page=1,
page_size=10,
)
print(f"Fetched rows: {fetched}")

# Clean up when done
px.cleanup_concepts(project_id=project_id)