release/v1.4 -> master (#548)

This commit is contained in:
cybermaggedon 2025-10-06 17:54:26 +01:00 committed by GitHub
parent 3ec2cd54f9
commit 2bd68ed7f4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
94 changed files with 8571 additions and 1740 deletions

View file

@ -72,6 +72,7 @@ tg-show-kg-cores = "trustgraph.cli.show_kg_cores:main"
tg-show-library-documents = "trustgraph.cli.show_library_documents:main"
tg-show-library-processing = "trustgraph.cli.show_library_processing:main"
tg-show-mcp-tools = "trustgraph.cli.show_mcp_tools:main"
tg-show-parameter-types = "trustgraph.cli.show_parameter_types:main"
tg-show-processor-state = "trustgraph.cli.show_processor_state:main"
tg-show-prompts = "trustgraph.cli.show_prompts:main"
tg-show-token-costs = "trustgraph.cli.show_token_costs:main"

View file

@ -599,8 +599,7 @@ def _send_to_trustgraph(objects, api_url, flow, batch_size=1000):
imported_count += 1
if imported_count % 100 == 0:
logger.info(f"Imported {imported_count}/{len(objects)} records...")
print(f"✅ Imported {imported_count}/{len(objects)} records...")
logger.debug(f"Imported {imported_count}/{len(objects)} records...")
except Exception as e:
logger.error(f"Failed to send record {imported_count + 1}: {e}")

View file

@ -5,38 +5,93 @@ Shows all defined flow classes.
import argparse
import os
import tabulate
from trustgraph.api import Api
from trustgraph.api import Api, ConfigKey
import json
default_url = os.getenv("TRUSTGRAPH_URL", 'http://localhost:8088/')
def format_parameters(params_metadata, config_api):
"""
Format parameter metadata for display
Args:
params_metadata: Parameter definitions from flow class
config_api: API client to get parameter type information
Returns:
Formatted string describing parameters
"""
if not params_metadata:
return "None"
param_list = []
# Sort parameters by order if available
sorted_params = sorted(
params_metadata.items(),
key=lambda x: x[1].get("order", 999)
)
for param_name, param_meta in sorted_params:
description = param_meta.get("description", param_name)
param_type = param_meta.get("type", "unknown")
# Get type information if available
type_info = param_type
if config_api:
try:
key = ConfigKey("parameter-types", param_type)
type_def_value = config_api.get([key])[0].value
param_type_def = json.loads(type_def_value)
# Add default value if available
default = param_type_def.get("default")
if default is not None:
type_info = f"{param_type} (default: {default})"
except:
# If we can't get type definition, just show the type name
pass
param_list.append(f" {param_name}: {description} [{type_info}]")
return "\n".join(param_list)
def show_flow_classes(url):
api = Api(url).flow()
api = Api(url)
flow_api = api.flow()
config_api = api.config()
class_names = api.list_classes()
class_names = flow_api.list_classes()
if len(class_names) == 0:
print("No flows.")
print("No flow classes.")
return
classes = []
for class_name in class_names:
cls = api.get_class(class_name)
classes.append((
class_name,
cls.get("description", ""),
", ".join(cls.get("tags", [])),
))
cls = flow_api.get_class(class_name)
print(tabulate.tabulate(
classes,
tablefmt="pretty",
maxcolwidths=[None, 40, 20],
stralign="left",
headers = ["flow class", "description", "tags"],
))
table = []
table.append(("name", class_name))
table.append(("description", cls.get("description", "")))
tags = cls.get("tags", [])
if tags:
table.append(("tags", ", ".join(tags)))
# Show parameters if they exist
parameters = cls.get("parameters", {})
if parameters:
param_str = format_parameters(parameters, config_api)
table.append(("parameters", param_str))
print(tabulate.tabulate(
table,
tablefmt="pretty",
stralign="left",
))
print()
def main():

View file

@ -45,6 +45,89 @@ def describe_interfaces(intdefs, flow):
return "\n".join(lst)
def get_enum_description(param_value, param_type_def):
"""
Get the human-readable description for an enum value
Args:
param_value: The actual parameter value (e.g., "gpt-4")
param_type_def: The parameter type definition containing enum objects
Returns:
Human-readable description or the original value if not found
"""
enum_list = param_type_def.get("enum", [])
# Handle both old format (strings) and new format (objects with id/description)
for enum_item in enum_list:
if isinstance(enum_item, dict):
if enum_item.get("id") == param_value:
return enum_item.get("description", param_value)
elif enum_item == param_value:
return param_value
# If not found in enum, return original value
return param_value
def format_parameters(flow_params, class_params_metadata, config_api):
"""
Format flow parameters with their human-readable descriptions
Args:
flow_params: The actual parameter values used in the flow
class_params_metadata: The parameter metadata from the flow class definition
config_api: API client to retrieve parameter type definitions
Returns:
Formatted string of parameters with descriptions
"""
if not flow_params:
return "None"
param_list = []
# Sort parameters by order if available
sorted_params = sorted(
class_params_metadata.items(),
key=lambda x: x[1].get("order", 999)
)
for param_name, param_meta in sorted_params:
if param_name in flow_params:
value = flow_params[param_name]
description = param_meta.get("description", param_name)
param_type = param_meta.get("type", "")
controlled_by = param_meta.get("controlled-by", None)
# Try to get enum description if this parameter has a type definition
display_value = value
if param_type and config_api:
try:
from trustgraph.api import ConfigKey
key = ConfigKey("parameter-types", param_type)
type_def_value = config_api.get([key])[0].value
param_type_def = json.loads(type_def_value)
display_value = get_enum_description(value, param_type_def)
except:
# If we can't get the type definition, just use the original value
display_value = value
# Format the parameter line
line = f"{description}: {display_value}"
# Add controlled-by indicator if present
if controlled_by:
line += f" (controlled by {controlled_by})"
param_list.append(line)
# Add any parameters that aren't in the class metadata (shouldn't happen normally)
for param_name, value in flow_params.items():
if param_name not in class_params_metadata:
param_list.append(f"{param_name}: {value} (undefined)")
return "\n".join(param_list) if param_list else "None"
def show_flows(url):
api = Api(url)
@ -74,6 +157,26 @@ def show_flows(url):
table.append(("id", id))
table.append(("class", flow.get("class-name", "")))
table.append(("desc", flow.get("description", "")))
# Display parameters with human-readable descriptions
parameters = flow.get("parameters", {})
if parameters:
# Try to get the flow class definition for parameter metadata
class_name = flow.get("class-name", "")
if class_name:
try:
flow_class = flow_api.get_class(class_name)
class_params_metadata = flow_class.get("parameters", {})
param_str = format_parameters(parameters, class_params_metadata, config_api)
except Exception as e:
# Fallback to JSON if we can't get the class definition
param_str = json.dumps(parameters, indent=2)
else:
# No class name, fallback to JSON
param_str = json.dumps(parameters, indent=2)
table.append(("parameters", param_str))
table.append(("queue", describe_interfaces(interface_defs, flow)))
print(tabulate.tabulate(

View file

@ -0,0 +1,210 @@
"""
Shows all defined parameter types used in flow classes.
Parameter types define the schema and constraints for parameters that can
be used in flow class definitions. This includes data types, default values,
valid enums, and validation rules.
"""
import argparse
import os
import tabulate
from trustgraph.api import Api, ConfigKey
import json
default_url = os.getenv("TRUSTGRAPH_URL", 'http://localhost:8088/')
def format_enum_values(enum_list):
"""
Format enum values for display, handling both old and new formats
Args:
enum_list: List of enum values (strings or objects with id/description)
Returns:
Formatted string describing enum options
"""
if not enum_list:
return "Any value"
enum_items = []
for item in enum_list:
if isinstance(item, dict):
# New format: objects with id and description
enum_id = item.get("id", "")
description = item.get("description", "")
if description:
enum_items.append(f"{enum_id} ({description})")
else:
enum_items.append(enum_id)
else:
# Old format: simple strings
enum_items.append(str(item))
return "\n".join(f"{item}" for item in enum_items)
def format_constraints(param_type_def):
"""
Format validation constraints for display
Args:
param_type_def: Parameter type definition
Returns:
Formatted string describing constraints
"""
constraints = []
# Handle numeric constraints
if "minimum" in param_type_def:
constraints.append(f"min: {param_type_def['minimum']}")
if "maximum" in param_type_def:
constraints.append(f"max: {param_type_def['maximum']}")
# Handle string constraints
if "minLength" in param_type_def:
constraints.append(f"min length: {param_type_def['minLength']}")
if "maxLength" in param_type_def:
constraints.append(f"max length: {param_type_def['maxLength']}")
if "pattern" in param_type_def:
constraints.append(f"pattern: {param_type_def['pattern']}")
# Handle required field
if param_type_def.get("required", False):
constraints.append("required")
return ", ".join(constraints) if constraints else "None"
def show_parameter_types(url):
"""
Show all parameter type definitions
"""
api = Api(url)
config_api = api.config()
# Get list of all parameter types
try:
param_type_names = config_api.list("parameter-types")
except Exception as e:
print(f"Error retrieving parameter types: {e}")
return
if len(param_type_names) == 0:
print("No parameter types defined.")
return
for param_type_name in param_type_names:
try:
# Get the parameter type definition
key = ConfigKey("parameter-types", param_type_name)
type_def_value = config_api.get([key])[0].value
param_type_def = json.loads(type_def_value)
table = []
table.append(("name", param_type_name))
table.append(("description", param_type_def.get("description", "")))
table.append(("type", param_type_def.get("type", "unknown")))
# Show default value if present
default = param_type_def.get("default")
if default is not None:
table.append(("default", str(default)))
# Show enum values if present
enum_list = param_type_def.get("enum")
if enum_list:
enum_str = format_enum_values(enum_list)
table.append(("valid values", enum_str))
# Show constraints
constraints = format_constraints(param_type_def)
if constraints != "None":
table.append(("constraints", constraints))
print(tabulate.tabulate(
table,
tablefmt="pretty",
stralign="left",
))
print()
except Exception as e:
print(f"Error retrieving parameter type '{param_type_name}': {e}")
print()
def main():
parser = argparse.ArgumentParser(
prog='tg-show-parameter-types',
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument(
'-u', '--api-url',
default=default_url,
help=f'API URL (default: {default_url})',
)
parser.add_argument(
'-t', '--type',
help='Show only the specified parameter type',
)
args = parser.parse_args()
try:
if args.type:
# Show specific parameter type
show_specific_parameter_type(args.api_url, args.type)
else:
# Show all parameter types
show_parameter_types(args.api_url)
except Exception as e:
print("Exception:", e, flush=True)
def show_specific_parameter_type(url, param_type_name):
"""
Show a specific parameter type definition
"""
api = Api(url)
config_api = api.config()
try:
# Get the parameter type definition
key = ConfigKey("parameter-types", param_type_name)
type_def_value = config_api.get([key])[0].value
param_type_def = json.loads(type_def_value)
table = []
table.append(("name", param_type_name))
table.append(("description", param_type_def.get("description", "")))
table.append(("type", param_type_def.get("type", "unknown")))
# Show default value if present
default = param_type_def.get("default")
if default is not None:
table.append(("default", str(default)))
# Show enum values if present
enum_list = param_type_def.get("enum")
if enum_list:
enum_str = format_enum_values(enum_list)
table.append(("valid values", enum_str))
# Show constraints
constraints = format_constraints(param_type_def)
if constraints != "None":
table.append(("constraints", constraints))
print(tabulate.tabulate(
table,
tablefmt="pretty",
stralign="left",
))
except Exception as e:
print(f"Error retrieving parameter type '{param_type_name}': {e}")
if __name__ == "__main__":
main()

View file

@ -1,5 +1,13 @@
"""
Starts a processing flow using a defined flow class
Starts a processing flow using a defined flow class.
Parameters can be provided in three ways:
1. As key=value pairs: --param model=gpt-4 --param temp=0.7
2. As JSON string: -p '{"model": "gpt-4", "temp": 0.7}'
3. As JSON file: --parameters-file params.json
Note: All parameter values are stored as strings internally, regardless of their
input format. Numbers and booleans will be converted to string representation.
"""
import argparse
@ -10,7 +18,7 @@ import json
default_url = os.getenv("TRUSTGRAPH_URL", 'http://localhost:8088/')
def start_flow(url, class_name, flow_id, description):
def start_flow(url, class_name, flow_id, description, parameters=None):
api = Api(url).flow()
@ -18,6 +26,7 @@ def start_flow(url, class_name, flow_id, description):
class_name = class_name,
id = flow_id,
description = description,
parameters = parameters,
)
def main():
@ -51,15 +60,58 @@ def main():
help=f'Flow description',
)
parser.add_argument(
'-p', '--parameters',
help='Flow parameters as JSON string (e.g., \'{"model": "gpt-4", "temp": 0.7}\')',
)
parser.add_argument(
'--parameters-file',
help='Path to JSON file containing flow parameters',
)
parser.add_argument(
'--param',
action='append',
help='Flow parameter as key=value pair (can be used multiple times, e.g., --param model=gpt-4 --param temp=0.7)',
)
args = parser.parse_args()
try:
# Parse parameters from command line arguments
parameters = None
if args.parameters_file:
with open(args.parameters_file, 'r') as f:
params_data = json.load(f)
# Convert all values to strings
parameters = {k: str(v) for k, v in params_data.items()}
elif args.parameters:
params_data = json.loads(args.parameters)
# Convert all values to strings
parameters = {k: str(v) for k, v in params_data.items()}
elif args.param:
# Parse key=value pairs
parameters = {}
for param in args.param:
if '=' not in param:
raise ValueError(f"Invalid parameter format: {param}. Expected key=value")
key, value = param.split('=', 1)
key = key.strip()
value = value.strip()
# All parameter values must be strings for Pulsar
# Just store everything as a string
parameters[key] = value
start_flow(
url = args.api_url,
class_name = args.class_name,
flow_id = args.flow_id,
description = args.description,
parameters = parameters,
)
except Exception as e: