mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-04-25 00:16:23 +02:00
Python API docs (#614)
* Python API docs working * Python API doc generation
This commit is contained in:
parent
8a17375603
commit
1c006d5b14
14 changed files with 5508 additions and 64 deletions
48
docs/README.api-docs.md
Normal file
48
docs/README.api-docs.md
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
|
||||||
|
# Auto-generating docs
|
||||||
|
|
||||||
|
## REST and WebSocket API Documentation
|
||||||
|
|
||||||
|
- `specs/build-docs.sh` - Builds the REST and websocket documentation from the
|
||||||
|
OpenAPI and AsyncAPI specs.
|
||||||
|
|
||||||
|
## Python API Documentation
|
||||||
|
|
||||||
|
The Python API documentation is generated from docstrings using a custom Python script that introspects the `trustgraph.api` package.
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
The trustgraph package must be importable. If you're working in a development environment:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd trustgraph-base
|
||||||
|
pip install -e .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Generating Documentation
|
||||||
|
|
||||||
|
From the docs directory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd docs
|
||||||
|
python3 generate-api-docs.py > python-api.md
|
||||||
|
```
|
||||||
|
|
||||||
|
This generates a single markdown file with complete API documentation showing:
|
||||||
|
- Installation and quick start guide
|
||||||
|
- Import statements for each class/type
|
||||||
|
- Full docstrings with examples
|
||||||
|
- Table of contents organized by category
|
||||||
|
|
||||||
|
### Documentation Style
|
||||||
|
|
||||||
|
All docstrings follow Google-style format:
|
||||||
|
- Brief one-line summary
|
||||||
|
- Detailed description
|
||||||
|
- Args section with parameter descriptions
|
||||||
|
- Returns section
|
||||||
|
- Raises section (when applicable)
|
||||||
|
- Example code blocks with proper syntax highlighting
|
||||||
|
|
||||||
|
The generated documentation shows the public API exactly as users import it from `trustgraph.api`, without exposing internal module structure.
|
||||||
|
|
||||||
351
docs/generate-api-docs.py
Normal file
351
docs/generate-api-docs.py
Normal file
|
|
@ -0,0 +1,351 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Generate clean markdown documentation for trustgraph.api
|
||||||
|
|
||||||
|
This script introspects the trustgraph.api package and generates markdown
|
||||||
|
documentation showing the API as users actually import it.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import inspect
|
||||||
|
import importlib
|
||||||
|
from dataclasses import is_dataclass, fields
|
||||||
|
from typing import get_type_hints
|
||||||
|
|
||||||
|
# Add parent directory to path
|
||||||
|
sys.path.insert(0, '../trustgraph-base')
|
||||||
|
|
||||||
|
def parse_docstring(docstring):
|
||||||
|
"""Parse Google-style docstring into sections"""
|
||||||
|
if not docstring:
|
||||||
|
return {"description": "", "args": [], "returns": "", "raises": [], "examples": []}
|
||||||
|
|
||||||
|
lines = docstring.split('\n')
|
||||||
|
result = {
|
||||||
|
"description": [],
|
||||||
|
"args": [],
|
||||||
|
"returns": "",
|
||||||
|
"raises": [],
|
||||||
|
"examples": [],
|
||||||
|
"attributes": []
|
||||||
|
}
|
||||||
|
|
||||||
|
current_section = "description"
|
||||||
|
current_item = None
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
stripped = line.strip()
|
||||||
|
|
||||||
|
# Check for section headers
|
||||||
|
if stripped in ["Args:", "Arguments:"]:
|
||||||
|
current_section = "args"
|
||||||
|
current_item = None
|
||||||
|
continue
|
||||||
|
elif stripped in ["Returns:", "Return:"]:
|
||||||
|
current_section = "returns"
|
||||||
|
current_item = None
|
||||||
|
continue
|
||||||
|
elif stripped in ["Raises:"]:
|
||||||
|
current_section = "raises"
|
||||||
|
current_item = None
|
||||||
|
continue
|
||||||
|
elif stripped in ["Example:", "Examples:"]:
|
||||||
|
current_section = "examples"
|
||||||
|
current_item = None
|
||||||
|
continue
|
||||||
|
elif stripped in ["Attributes:"]:
|
||||||
|
current_section = "attributes"
|
||||||
|
current_item = None
|
||||||
|
continue
|
||||||
|
elif stripped.startswith("Note:"):
|
||||||
|
current_section = "description"
|
||||||
|
result["description"].append(line)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Process content based on section
|
||||||
|
if current_section == "description":
|
||||||
|
result["description"].append(line)
|
||||||
|
elif current_section == "args":
|
||||||
|
# Check if this is a new argument (starts with word followed by colon)
|
||||||
|
if stripped and not line.startswith(' ' * 8) and ':' in stripped:
|
||||||
|
parts = stripped.split(':', 1)
|
||||||
|
arg_name = parts[0].strip()
|
||||||
|
arg_desc = parts[1].strip() if len(parts) > 1 else ""
|
||||||
|
current_item = {"name": arg_name, "description": arg_desc}
|
||||||
|
result["args"].append(current_item)
|
||||||
|
elif current_item and stripped:
|
||||||
|
# Continuation of previous arg description
|
||||||
|
current_item["description"] += " " + stripped
|
||||||
|
elif current_section == "returns":
|
||||||
|
if stripped:
|
||||||
|
result["returns"] += stripped + " "
|
||||||
|
elif current_section == "raises":
|
||||||
|
if stripped and ':' in stripped:
|
||||||
|
parts = stripped.split(':', 1)
|
||||||
|
exc_name = parts[0].strip()
|
||||||
|
exc_desc = parts[1].strip() if len(parts) > 1 else ""
|
||||||
|
current_item = {"name": exc_name, "description": exc_desc}
|
||||||
|
result["raises"].append(current_item)
|
||||||
|
elif current_item and stripped:
|
||||||
|
current_item["description"] += " " + stripped
|
||||||
|
elif current_section == "examples":
|
||||||
|
result["examples"].append(line)
|
||||||
|
elif current_section == "attributes":
|
||||||
|
if stripped and '-' in stripped:
|
||||||
|
parts = stripped.split('-', 1)
|
||||||
|
if len(parts) == 2:
|
||||||
|
attr_name = parts[0].strip().strip('`')
|
||||||
|
attr_desc = parts[1].strip()
|
||||||
|
result["attributes"].append({"name": attr_name, "description": attr_desc})
|
||||||
|
|
||||||
|
# Clean up description
|
||||||
|
result["description"] = '\n'.join(result["description"]).strip()
|
||||||
|
result["returns"] = result["returns"].strip()
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def format_signature(name, obj):
|
||||||
|
"""Format function/method signature"""
|
||||||
|
try:
|
||||||
|
sig = inspect.signature(obj)
|
||||||
|
return f"{name}{sig}"
|
||||||
|
except:
|
||||||
|
return f"{name}(...)"
|
||||||
|
|
||||||
|
def document_function(name, func, indent=0):
|
||||||
|
"""Generate markdown for a function"""
|
||||||
|
ind = " " * indent
|
||||||
|
md = []
|
||||||
|
|
||||||
|
# Function heading and signature
|
||||||
|
md.append(f"{ind}### `{format_signature(name, func)}`\n")
|
||||||
|
|
||||||
|
# Parse docstring
|
||||||
|
doc = inspect.getdoc(func)
|
||||||
|
if doc:
|
||||||
|
parsed = parse_docstring(doc)
|
||||||
|
|
||||||
|
# Description
|
||||||
|
if parsed["description"]:
|
||||||
|
md.append(f"{ind}{parsed['description']}\n")
|
||||||
|
|
||||||
|
# Arguments
|
||||||
|
if parsed["args"]:
|
||||||
|
md.append(f"{ind}**Arguments:**\n")
|
||||||
|
for arg in parsed["args"]:
|
||||||
|
md.append(f"{ind}- `{arg['name']}`: {arg['description']}")
|
||||||
|
md.append("")
|
||||||
|
|
||||||
|
# Returns
|
||||||
|
if parsed["returns"]:
|
||||||
|
md.append(f"{ind}**Returns:** {parsed['returns']}\n")
|
||||||
|
|
||||||
|
# Raises
|
||||||
|
if parsed["raises"]:
|
||||||
|
md.append(f"{ind}**Raises:**\n")
|
||||||
|
for exc in parsed["raises"]:
|
||||||
|
md.append(f"{ind}- `{exc['name']}`: {exc['description']}")
|
||||||
|
md.append("")
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
if parsed["examples"]:
|
||||||
|
md.append(f"{ind}**Example:**\n")
|
||||||
|
|
||||||
|
# Strip common leading whitespace from examples
|
||||||
|
import textwrap
|
||||||
|
example_text = '\n'.join(parsed["examples"])
|
||||||
|
dedented = textwrap.dedent(example_text)
|
||||||
|
example_lines = dedented.split('\n')
|
||||||
|
|
||||||
|
# Check if examples already contain code fences
|
||||||
|
if '```' in dedented:
|
||||||
|
# Already has code fences, don't wrap
|
||||||
|
for line in example_lines:
|
||||||
|
md.append(line.rstrip())
|
||||||
|
md.append("")
|
||||||
|
else:
|
||||||
|
# No code fences, wrap in python block
|
||||||
|
md.append("```python")
|
||||||
|
for line in example_lines:
|
||||||
|
md.append(line.rstrip())
|
||||||
|
md.append("```\n")
|
||||||
|
|
||||||
|
return '\n'.join(md)
|
||||||
|
|
||||||
|
def document_class(name, cls):
|
||||||
|
"""Generate markdown for a class"""
|
||||||
|
md = []
|
||||||
|
|
||||||
|
# Class heading
|
||||||
|
md.append(f"## `{name}`\n")
|
||||||
|
|
||||||
|
# Import statement
|
||||||
|
md.append(f"```python")
|
||||||
|
md.append(f"from trustgraph.api import {name}")
|
||||||
|
md.append(f"```\n")
|
||||||
|
|
||||||
|
# Parse class docstring
|
||||||
|
doc = inspect.getdoc(cls)
|
||||||
|
if doc:
|
||||||
|
parsed = parse_docstring(doc)
|
||||||
|
|
||||||
|
# Description
|
||||||
|
if parsed["description"]:
|
||||||
|
md.append(f"{parsed['description']}\n")
|
||||||
|
|
||||||
|
# Attributes (for class-level attributes)
|
||||||
|
if parsed["attributes"]:
|
||||||
|
md.append(f"**Attributes:**\n")
|
||||||
|
for attr in parsed["attributes"]:
|
||||||
|
md.append(f"- `{attr['name']}`: {attr['description']}")
|
||||||
|
md.append("")
|
||||||
|
|
||||||
|
# For dataclasses, show fields
|
||||||
|
if is_dataclass(cls):
|
||||||
|
md.append("**Fields:**\n")
|
||||||
|
for field in fields(cls):
|
||||||
|
field_doc = ""
|
||||||
|
if cls.__doc__:
|
||||||
|
# Try to extract field description from docstring
|
||||||
|
pass
|
||||||
|
md.append(f"- `{field.name}`: {field.type}")
|
||||||
|
md.append("")
|
||||||
|
|
||||||
|
# Document methods
|
||||||
|
methods = []
|
||||||
|
for method_name, method in inspect.getmembers(cls, predicate=inspect.isfunction):
|
||||||
|
# Skip private methods except special ones
|
||||||
|
if method_name.startswith('_') and method_name not in ['__init__', '__enter__', '__exit__', '__aenter__', '__aexit__']:
|
||||||
|
continue
|
||||||
|
methods.append((method_name, method))
|
||||||
|
|
||||||
|
if methods:
|
||||||
|
md.append("### Methods\n")
|
||||||
|
for method_name, method in methods:
|
||||||
|
md.append(document_function(method_name, method, indent=0))
|
||||||
|
|
||||||
|
return '\n'.join(md)
|
||||||
|
|
||||||
|
def document_exception(name, exc):
|
||||||
|
"""Generate markdown for an exception"""
|
||||||
|
md = []
|
||||||
|
|
||||||
|
md.append(f"## `{name}`\n")
|
||||||
|
|
||||||
|
# Import statement
|
||||||
|
md.append(f"```python")
|
||||||
|
md.append(f"from trustgraph.api import {name}")
|
||||||
|
md.append(f"```\n")
|
||||||
|
|
||||||
|
doc = inspect.getdoc(exc)
|
||||||
|
if doc:
|
||||||
|
md.append(f"{doc}\n")
|
||||||
|
else:
|
||||||
|
md.append(f"Exception class for {name.replace('Exception', '').replace('Error', '')} errors.\n")
|
||||||
|
|
||||||
|
return '\n'.join(md)
|
||||||
|
|
||||||
|
def generate_toc(items):
|
||||||
|
"""Generate table of contents"""
|
||||||
|
md = []
|
||||||
|
md.append("# TrustGraph Python API Reference\n")
|
||||||
|
|
||||||
|
# Add introduction
|
||||||
|
md.append("## Installation\n")
|
||||||
|
md.append("```bash")
|
||||||
|
md.append("pip install trustgraph")
|
||||||
|
md.append("```\n")
|
||||||
|
|
||||||
|
md.append("## Quick Start\n")
|
||||||
|
md.append("All classes and types are imported from the `trustgraph.api` package:\n")
|
||||||
|
md.append("```python")
|
||||||
|
md.append("from trustgraph.api import Api, Triple, ConfigKey")
|
||||||
|
md.append("")
|
||||||
|
md.append("# Create API client")
|
||||||
|
md.append("api = Api(url=\"http://localhost:8088/\")")
|
||||||
|
md.append("")
|
||||||
|
md.append("# Get a flow instance")
|
||||||
|
md.append("flow = api.flow().id(\"default\")")
|
||||||
|
md.append("")
|
||||||
|
md.append("# Execute a graph RAG query")
|
||||||
|
md.append("response = flow.graph_rag(")
|
||||||
|
md.append(" query=\"What are the main topics?\",")
|
||||||
|
md.append(" user=\"trustgraph\",")
|
||||||
|
md.append(" collection=\"default\"")
|
||||||
|
md.append(")")
|
||||||
|
md.append("```\n")
|
||||||
|
|
||||||
|
md.append("## Table of Contents\n")
|
||||||
|
|
||||||
|
# Group by category
|
||||||
|
categories = {
|
||||||
|
"Core": ["Api"],
|
||||||
|
"Flow Clients": ["Flow", "FlowInstance", "AsyncFlow", "AsyncFlowInstance"],
|
||||||
|
"WebSocket Clients": ["SocketClient", "SocketFlowInstance", "AsyncSocketClient", "AsyncSocketFlowInstance"],
|
||||||
|
"Bulk Operations": ["BulkClient", "AsyncBulkClient"],
|
||||||
|
"Metrics": ["Metrics", "AsyncMetrics"],
|
||||||
|
"Data Types": ["Triple", "ConfigKey", "ConfigValue", "DocumentMetadata", "ProcessingMetadata",
|
||||||
|
"CollectionMetadata", "StreamingChunk", "AgentThought", "AgentObservation",
|
||||||
|
"AgentAnswer", "RAGChunk"],
|
||||||
|
"Exceptions": []
|
||||||
|
}
|
||||||
|
|
||||||
|
# Find exceptions
|
||||||
|
for item in items:
|
||||||
|
if "Exception" in item or "Error" in item:
|
||||||
|
categories["Exceptions"].append(item)
|
||||||
|
|
||||||
|
for category, names in categories.items():
|
||||||
|
if not names:
|
||||||
|
continue
|
||||||
|
md.append(f"### {category}\n")
|
||||||
|
for name in names:
|
||||||
|
if name in items:
|
||||||
|
md.append(f"- [{name}](#{name.lower()})")
|
||||||
|
md.append("")
|
||||||
|
|
||||||
|
return '\n'.join(md)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Generate API documentation"""
|
||||||
|
|
||||||
|
# Import the package
|
||||||
|
try:
|
||||||
|
api_module = importlib.import_module('trustgraph.api')
|
||||||
|
except ImportError as e:
|
||||||
|
print(f"Error importing trustgraph.api: {e}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Get exported names
|
||||||
|
if not hasattr(api_module, '__all__'):
|
||||||
|
print("Error: trustgraph.api has no __all__", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
all_names = api_module.__all__
|
||||||
|
|
||||||
|
# Generate TOC
|
||||||
|
print(generate_toc(all_names))
|
||||||
|
print("---\n")
|
||||||
|
|
||||||
|
# Document each exported item
|
||||||
|
for name in all_names:
|
||||||
|
try:
|
||||||
|
obj = getattr(api_module, name)
|
||||||
|
|
||||||
|
# Determine what kind of object it is
|
||||||
|
if inspect.isclass(obj):
|
||||||
|
if issubclass(obj, Exception):
|
||||||
|
print(document_exception(name, obj))
|
||||||
|
else:
|
||||||
|
print(document_class(name, obj))
|
||||||
|
elif inspect.isfunction(obj):
|
||||||
|
print(document_function(name, obj))
|
||||||
|
|
||||||
|
print("\n---\n")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error documenting {name}: {e}", file=sys.stderr)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
2143
docs/python-api.md
Normal file
2143
docs/python-api.md
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,3 +1,55 @@
|
||||||
|
"""
|
||||||
|
TrustGraph API Client Library
|
||||||
|
|
||||||
|
This package provides Python client interfaces for interacting with TrustGraph services.
|
||||||
|
TrustGraph is a knowledge graph and RAG (Retrieval-Augmented Generation) platform that
|
||||||
|
combines graph databases, vector embeddings, and LLM capabilities.
|
||||||
|
|
||||||
|
The library offers both synchronous and asynchronous APIs for:
|
||||||
|
- Flow management and execution
|
||||||
|
- Knowledge graph operations (triples, entities, embeddings)
|
||||||
|
- RAG queries (graph-based and document-based)
|
||||||
|
- Agent interactions with streaming support
|
||||||
|
- WebSocket-based real-time communication
|
||||||
|
- Bulk import/export operations
|
||||||
|
- Configuration and collection management
|
||||||
|
|
||||||
|
Quick Start:
|
||||||
|
```python
|
||||||
|
from trustgraph.api import Api
|
||||||
|
|
||||||
|
# Create API client
|
||||||
|
api = Api(url="http://localhost:8088/")
|
||||||
|
|
||||||
|
# Get a flow instance
|
||||||
|
flow = api.flow().id("default")
|
||||||
|
|
||||||
|
# Execute a graph RAG query
|
||||||
|
response = flow.graph_rag(
|
||||||
|
query="What are the main topics?",
|
||||||
|
user="trustgraph",
|
||||||
|
collection="default"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
For streaming and async operations:
|
||||||
|
```python
|
||||||
|
# WebSocket streaming
|
||||||
|
socket = api.socket()
|
||||||
|
flow = socket.flow("default")
|
||||||
|
|
||||||
|
for chunk in flow.agent(question="Hello", user="trustgraph"):
|
||||||
|
print(chunk.content)
|
||||||
|
|
||||||
|
# Async operations
|
||||||
|
async with Api(url="http://localhost:8088/") as api:
|
||||||
|
async_flow = api.async_flow()
|
||||||
|
result = await async_flow.id("default").text_completion(
|
||||||
|
system="You are helpful",
|
||||||
|
prompt="Hello"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# Core API
|
# Core API
|
||||||
from .api import Api
|
from .api import Api
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,8 @@
|
||||||
|
"""
|
||||||
|
TrustGraph API Client
|
||||||
|
|
||||||
|
Core API client for interacting with TrustGraph services via REST and WebSocket protocols.
|
||||||
|
"""
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
import json
|
import json
|
||||||
|
|
@ -26,8 +31,47 @@ def check_error(response):
|
||||||
raise ApplicationException(f"{tp}: {msg}")
|
raise ApplicationException(f"{tp}: {msg}")
|
||||||
|
|
||||||
class Api:
|
class Api:
|
||||||
|
"""
|
||||||
|
Main TrustGraph API client for synchronous and asynchronous operations.
|
||||||
|
|
||||||
|
This class provides access to all TrustGraph services including flow management,
|
||||||
|
knowledge graph operations, document processing, RAG queries, and more. It supports
|
||||||
|
both REST-based and WebSocket-based communication patterns.
|
||||||
|
|
||||||
|
The client can be used as a context manager for automatic resource cleanup:
|
||||||
|
```python
|
||||||
|
with Api(url="http://localhost:8088/") as api:
|
||||||
|
result = api.flow().id("default").graph_rag(query="test")
|
||||||
|
```
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
url: Base URL for the TrustGraph API endpoint
|
||||||
|
timeout: Request timeout in seconds
|
||||||
|
token: Optional bearer token for authentication
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, url="http://localhost:8088/", timeout=60, token: Optional[str] = None):
|
def __init__(self, url="http://localhost:8088/", timeout=60, token: Optional[str] = None):
|
||||||
|
"""
|
||||||
|
Initialize the TrustGraph API client.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
url: Base URL for TrustGraph API (default: "http://localhost:8088/")
|
||||||
|
timeout: Request timeout in seconds (default: 60)
|
||||||
|
token: Optional bearer token for authentication
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
# Local development
|
||||||
|
api = Api()
|
||||||
|
|
||||||
|
# Production with authentication
|
||||||
|
api = Api(
|
||||||
|
url="https://trustgraph.example.com/",
|
||||||
|
timeout=120,
|
||||||
|
token="your-api-token"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
self.url = url
|
self.url = url
|
||||||
|
|
||||||
|
|
@ -49,15 +93,97 @@ class Api:
|
||||||
self._async_metrics = None
|
self._async_metrics = None
|
||||||
|
|
||||||
def flow(self):
|
def flow(self):
|
||||||
|
"""
|
||||||
|
Get a Flow client for managing and interacting with flows.
|
||||||
|
|
||||||
|
Flows are the primary execution units in TrustGraph, providing access to
|
||||||
|
services like agents, RAG queries, embeddings, and document processing.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Flow: Flow management client
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
flow_client = api.flow()
|
||||||
|
|
||||||
|
# List available blueprints
|
||||||
|
blueprints = flow_client.list_blueprints()
|
||||||
|
|
||||||
|
# Get a specific flow instance
|
||||||
|
flow_instance = flow_client.id("default")
|
||||||
|
response = flow_instance.text_completion(
|
||||||
|
system="You are helpful",
|
||||||
|
prompt="Hello"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
return Flow(api=self)
|
return Flow(api=self)
|
||||||
|
|
||||||
def config(self):
|
def config(self):
|
||||||
|
"""
|
||||||
|
Get a Config client for managing configuration settings.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Config: Configuration management client
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
config = api.config()
|
||||||
|
|
||||||
|
# Get configuration values
|
||||||
|
values = config.get([ConfigKey(type="llm", key="model")])
|
||||||
|
|
||||||
|
# Set configuration
|
||||||
|
config.put([ConfigValue(type="llm", key="model", value="gpt-4")])
|
||||||
|
```
|
||||||
|
"""
|
||||||
return Config(api=self)
|
return Config(api=self)
|
||||||
|
|
||||||
def knowledge(self):
|
def knowledge(self):
|
||||||
|
"""
|
||||||
|
Get a Knowledge client for managing knowledge graph cores.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Knowledge: Knowledge graph management client
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
knowledge = api.knowledge()
|
||||||
|
|
||||||
|
# List available KG cores
|
||||||
|
cores = knowledge.list_kg_cores(user="trustgraph")
|
||||||
|
|
||||||
|
# Load a KG core
|
||||||
|
knowledge.load_kg_core(id="core-123", user="trustgraph")
|
||||||
|
```
|
||||||
|
"""
|
||||||
return Knowledge(api=self)
|
return Knowledge(api=self)
|
||||||
|
|
||||||
def request(self, path, request):
|
def request(self, path, request):
|
||||||
|
"""
|
||||||
|
Make a low-level REST API request.
|
||||||
|
|
||||||
|
This method is primarily for internal use but can be used for direct
|
||||||
|
API access when needed.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path: API endpoint path (relative to base URL)
|
||||||
|
request: Request payload as a dictionary
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Response object
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ProtocolException: If the response status is not 200 or response is not JSON
|
||||||
|
ApplicationException: If the response contains an error
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
response = api.request("flow", {
|
||||||
|
"operation": "list-flows"
|
||||||
|
})
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
url = f"{self.url}{path}"
|
url = f"{self.url}{path}"
|
||||||
|
|
||||||
|
|
@ -83,14 +209,90 @@ class Api:
|
||||||
return object
|
return object
|
||||||
|
|
||||||
def library(self):
|
def library(self):
|
||||||
|
"""
|
||||||
|
Get a Library client for document management.
|
||||||
|
|
||||||
|
The library provides document storage, metadata management, and
|
||||||
|
processing workflow coordination.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Library: Document library management client
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
library = api.library()
|
||||||
|
|
||||||
|
# Add a document
|
||||||
|
library.add_document(
|
||||||
|
document=b"Document content",
|
||||||
|
id="doc-123",
|
||||||
|
metadata=[],
|
||||||
|
user="trustgraph",
|
||||||
|
title="My Document",
|
||||||
|
comments="Test document"
|
||||||
|
)
|
||||||
|
|
||||||
|
# List documents
|
||||||
|
docs = library.get_documents(user="trustgraph")
|
||||||
|
```
|
||||||
|
"""
|
||||||
return Library(self)
|
return Library(self)
|
||||||
|
|
||||||
def collection(self):
|
def collection(self):
|
||||||
|
"""
|
||||||
|
Get a Collection client for managing data collections.
|
||||||
|
|
||||||
|
Collections organize documents and knowledge graph data into
|
||||||
|
logical groupings for isolation and access control.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Collection: Collection management client
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
collection = api.collection()
|
||||||
|
|
||||||
|
# List collections
|
||||||
|
colls = collection.list_collections(user="trustgraph")
|
||||||
|
|
||||||
|
# Update collection metadata
|
||||||
|
collection.update_collection(
|
||||||
|
user="trustgraph",
|
||||||
|
collection="default",
|
||||||
|
name="Default Collection",
|
||||||
|
description="Main data collection"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
return Collection(self)
|
return Collection(self)
|
||||||
|
|
||||||
# New synchronous methods
|
# New synchronous methods
|
||||||
def socket(self):
|
def socket(self):
|
||||||
"""Synchronous WebSocket-based interface for streaming operations"""
|
"""
|
||||||
|
Get a synchronous WebSocket client for streaming operations.
|
||||||
|
|
||||||
|
WebSocket connections provide streaming support for real-time responses
|
||||||
|
from agents, RAG queries, and text completions. This method returns a
|
||||||
|
synchronous wrapper around the WebSocket protocol.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
SocketClient: Synchronous WebSocket client
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
socket = api.socket()
|
||||||
|
flow = socket.flow("default")
|
||||||
|
|
||||||
|
# Stream agent responses
|
||||||
|
for chunk in flow.agent(
|
||||||
|
question="Explain quantum computing",
|
||||||
|
user="trustgraph",
|
||||||
|
streaming=True
|
||||||
|
):
|
||||||
|
if hasattr(chunk, 'content'):
|
||||||
|
print(chunk.content, end='', flush=True)
|
||||||
|
```
|
||||||
|
"""
|
||||||
if self._socket_client is None:
|
if self._socket_client is None:
|
||||||
from . socket_client import SocketClient
|
from . socket_client import SocketClient
|
||||||
# Extract base URL (remove api/v1/ suffix)
|
# Extract base URL (remove api/v1/ suffix)
|
||||||
|
|
@ -99,7 +301,31 @@ class Api:
|
||||||
return self._socket_client
|
return self._socket_client
|
||||||
|
|
||||||
def bulk(self):
|
def bulk(self):
|
||||||
"""Synchronous bulk operations interface for import/export"""
|
"""
|
||||||
|
Get a synchronous bulk operations client for import/export.
|
||||||
|
|
||||||
|
Bulk operations allow efficient transfer of large datasets via WebSocket
|
||||||
|
connections, including triples, embeddings, entity contexts, and objects.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
BulkClient: Synchronous bulk operations client
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
bulk = api.bulk()
|
||||||
|
|
||||||
|
# Export triples
|
||||||
|
for triple in bulk.export_triples(flow="default"):
|
||||||
|
print(f"{triple.s} {triple.p} {triple.o}")
|
||||||
|
|
||||||
|
# Import triples
|
||||||
|
def triple_generator():
|
||||||
|
yield Triple(s="subj", p="pred", o="obj")
|
||||||
|
# ... more triples
|
||||||
|
|
||||||
|
bulk.import_triples(flow="default", triples=triple_generator())
|
||||||
|
```
|
||||||
|
"""
|
||||||
if self._bulk_client is None:
|
if self._bulk_client is None:
|
||||||
from . bulk_client import BulkClient
|
from . bulk_client import BulkClient
|
||||||
# Extract base URL (remove api/v1/ suffix)
|
# Extract base URL (remove api/v1/ suffix)
|
||||||
|
|
@ -108,7 +334,22 @@ class Api:
|
||||||
return self._bulk_client
|
return self._bulk_client
|
||||||
|
|
||||||
def metrics(self):
|
def metrics(self):
|
||||||
"""Synchronous metrics interface"""
|
"""
|
||||||
|
Get a synchronous metrics client for monitoring.
|
||||||
|
|
||||||
|
Retrieves Prometheus-formatted metrics from the TrustGraph service
|
||||||
|
for monitoring and observability.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Metrics: Synchronous metrics client
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
metrics = api.metrics()
|
||||||
|
prometheus_text = metrics.get()
|
||||||
|
print(prometheus_text)
|
||||||
|
```
|
||||||
|
"""
|
||||||
if self._metrics is None:
|
if self._metrics is None:
|
||||||
from . metrics import Metrics
|
from . metrics import Metrics
|
||||||
# Extract base URL (remove api/v1/ suffix)
|
# Extract base URL (remove api/v1/ suffix)
|
||||||
|
|
@ -118,14 +359,60 @@ class Api:
|
||||||
|
|
||||||
# New asynchronous methods
|
# New asynchronous methods
|
||||||
def async_flow(self):
|
def async_flow(self):
|
||||||
"""Asynchronous REST-based flow interface"""
|
"""
|
||||||
|
Get an asynchronous REST-based flow client.
|
||||||
|
|
||||||
|
Provides async/await style access to flow operations. This is preferred
|
||||||
|
for async Python applications and frameworks (FastAPI, aiohttp, etc.).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
AsyncFlow: Asynchronous flow client
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
async_flow = api.async_flow()
|
||||||
|
|
||||||
|
# List flows
|
||||||
|
flow_ids = await async_flow.list()
|
||||||
|
|
||||||
|
# Execute operations
|
||||||
|
instance = async_flow.id("default")
|
||||||
|
result = await instance.text_completion(
|
||||||
|
system="You are helpful",
|
||||||
|
prompt="Hello"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
if self._async_flow is None:
|
if self._async_flow is None:
|
||||||
from . async_flow import AsyncFlow
|
from . async_flow import AsyncFlow
|
||||||
self._async_flow = AsyncFlow(self.url, self.timeout, self.token)
|
self._async_flow = AsyncFlow(self.url, self.timeout, self.token)
|
||||||
return self._async_flow
|
return self._async_flow
|
||||||
|
|
||||||
def async_socket(self):
|
def async_socket(self):
|
||||||
"""Asynchronous WebSocket-based interface for streaming operations"""
|
"""
|
||||||
|
Get an asynchronous WebSocket client for streaming operations.
|
||||||
|
|
||||||
|
Provides async/await style WebSocket access with streaming support.
|
||||||
|
This is the preferred method for async streaming in Python.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
AsyncSocketClient: Asynchronous WebSocket client
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
async_socket = api.async_socket()
|
||||||
|
flow = async_socket.flow("default")
|
||||||
|
|
||||||
|
# Stream agent responses
|
||||||
|
async for chunk in flow.agent(
|
||||||
|
question="Explain quantum computing",
|
||||||
|
user="trustgraph",
|
||||||
|
streaming=True
|
||||||
|
):
|
||||||
|
if hasattr(chunk, 'content'):
|
||||||
|
print(chunk.content, end='', flush=True)
|
||||||
|
```
|
||||||
|
"""
|
||||||
if self._async_socket_client is None:
|
if self._async_socket_client is None:
|
||||||
from . async_socket_client import AsyncSocketClient
|
from . async_socket_client import AsyncSocketClient
|
||||||
# Extract base URL (remove api/v1/ suffix)
|
# Extract base URL (remove api/v1/ suffix)
|
||||||
|
|
@ -134,7 +421,34 @@ class Api:
|
||||||
return self._async_socket_client
|
return self._async_socket_client
|
||||||
|
|
||||||
def async_bulk(self):
|
def async_bulk(self):
|
||||||
"""Asynchronous bulk operations interface for import/export"""
|
"""
|
||||||
|
Get an asynchronous bulk operations client.
|
||||||
|
|
||||||
|
Provides async/await style bulk import/export operations via WebSocket
|
||||||
|
for efficient handling of large datasets.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
AsyncBulkClient: Asynchronous bulk operations client
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
async_bulk = api.async_bulk()
|
||||||
|
|
||||||
|
# Export triples asynchronously
|
||||||
|
async for triple in async_bulk.export_triples(flow="default"):
|
||||||
|
print(f"{triple.s} {triple.p} {triple.o}")
|
||||||
|
|
||||||
|
# Import with async generator
|
||||||
|
async def triple_gen():
|
||||||
|
yield Triple(s="subj", p="pred", o="obj")
|
||||||
|
# ... more triples
|
||||||
|
|
||||||
|
await async_bulk.import_triples(
|
||||||
|
flow="default",
|
||||||
|
triples=triple_gen()
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
if self._async_bulk_client is None:
|
if self._async_bulk_client is None:
|
||||||
from . async_bulk_client import AsyncBulkClient
|
from . async_bulk_client import AsyncBulkClient
|
||||||
# Extract base URL (remove api/v1/ suffix)
|
# Extract base URL (remove api/v1/ suffix)
|
||||||
|
|
@ -143,7 +457,21 @@ class Api:
|
||||||
return self._async_bulk_client
|
return self._async_bulk_client
|
||||||
|
|
||||||
def async_metrics(self):
|
def async_metrics(self):
|
||||||
"""Asynchronous metrics interface"""
|
"""
|
||||||
|
Get an asynchronous metrics client.
|
||||||
|
|
||||||
|
Provides async/await style access to Prometheus metrics.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
AsyncMetrics: Asynchronous metrics client
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
async_metrics = api.async_metrics()
|
||||||
|
prometheus_text = await async_metrics.get()
|
||||||
|
print(prometheus_text)
|
||||||
|
```
|
||||||
|
"""
|
||||||
if self._async_metrics is None:
|
if self._async_metrics is None:
|
||||||
from . async_metrics import AsyncMetrics
|
from . async_metrics import AsyncMetrics
|
||||||
# Extract base URL (remove api/v1/ suffix)
|
# Extract base URL (remove api/v1/ suffix)
|
||||||
|
|
@ -153,14 +481,52 @@ class Api:
|
||||||
|
|
||||||
# Resource management
|
# Resource management
|
||||||
def close(self):
|
def close(self):
|
||||||
"""Close all synchronous connections"""
|
"""
|
||||||
|
Close all synchronous client connections.
|
||||||
|
|
||||||
|
This method closes WebSocket and bulk operation connections.
|
||||||
|
It is automatically called when exiting a context manager.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
api = Api()
|
||||||
|
socket = api.socket()
|
||||||
|
# ... use socket
|
||||||
|
api.close() # Clean up connections
|
||||||
|
|
||||||
|
# Or use context manager (automatic cleanup)
|
||||||
|
with Api() as api:
|
||||||
|
socket = api.socket()
|
||||||
|
# ... use socket
|
||||||
|
# Automatically closed
|
||||||
|
```
|
||||||
|
"""
|
||||||
if self._socket_client:
|
if self._socket_client:
|
||||||
self._socket_client.close()
|
self._socket_client.close()
|
||||||
if self._bulk_client:
|
if self._bulk_client:
|
||||||
self._bulk_client.close()
|
self._bulk_client.close()
|
||||||
|
|
||||||
async def aclose(self):
|
async def aclose(self):
|
||||||
"""Close all asynchronous connections"""
|
"""
|
||||||
|
Close all asynchronous client connections.
|
||||||
|
|
||||||
|
This method closes async WebSocket, bulk operation, and flow connections.
|
||||||
|
It is automatically called when exiting an async context manager.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
api = Api()
|
||||||
|
async_socket = api.async_socket()
|
||||||
|
# ... use async_socket
|
||||||
|
await api.aclose() # Clean up connections
|
||||||
|
|
||||||
|
# Or use async context manager (automatic cleanup)
|
||||||
|
async with Api() as api:
|
||||||
|
async_socket = api.async_socket()
|
||||||
|
# ... use async_socket
|
||||||
|
# Automatically closed
|
||||||
|
```
|
||||||
|
"""
|
||||||
if self._async_socket_client:
|
if self._async_socket_client:
|
||||||
await self._async_socket_client.aclose()
|
await self._async_socket_client.aclose()
|
||||||
if self._async_bulk_client:
|
if self._async_bulk_client:
|
||||||
|
|
@ -170,13 +536,17 @@ class Api:
|
||||||
|
|
||||||
# Context manager support
|
# Context manager support
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
|
"""Enter synchronous context manager."""
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __exit__(self, *args):
|
def __exit__(self, *args):
|
||||||
|
"""Exit synchronous context manager and close connections."""
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
async def __aenter__(self):
|
async def __aenter__(self):
|
||||||
|
"""Enter asynchronous context manager."""
|
||||||
return self
|
return self
|
||||||
|
|
||||||
async def __aexit__(self, *args):
|
async def __aexit__(self, *args):
|
||||||
|
"""Exit asynchronous context manager and close connections."""
|
||||||
await self.aclose()
|
await self.aclose()
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,14 @@
|
||||||
|
"""
|
||||||
|
TrustGraph Asynchronous Flow Management
|
||||||
|
|
||||||
|
This module provides async/await based interfaces for managing and interacting
|
||||||
|
with TrustGraph flows using REST API calls. Unlike async_socket_client which
|
||||||
|
provides streaming support, this module is focused on non-streaming operations
|
||||||
|
that return complete responses.
|
||||||
|
|
||||||
|
For streaming support (e.g., real-time agent responses, streaming RAG), use
|
||||||
|
AsyncSocketClient instead.
|
||||||
|
"""
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import json
|
import json
|
||||||
|
|
@ -18,15 +29,47 @@ def check_error(response):
|
||||||
|
|
||||||
|
|
||||||
class AsyncFlow:
|
class AsyncFlow:
|
||||||
"""Asynchronous REST-based flow interface"""
|
"""
|
||||||
|
Asynchronous flow management client using REST API.
|
||||||
|
|
||||||
|
Provides async/await based flow management operations including listing,
|
||||||
|
starting, stopping flows, and managing flow class definitions. Also provides
|
||||||
|
access to flow-scoped services like agents, RAG, and queries via non-streaming
|
||||||
|
REST endpoints.
|
||||||
|
|
||||||
|
Note: For streaming support, use AsyncSocketClient instead.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, url: str, timeout: int, token: Optional[str]) -> None:
|
def __init__(self, url: str, timeout: int, token: Optional[str]) -> None:
|
||||||
|
"""
|
||||||
|
Initialize async flow client.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
url: Base URL for TrustGraph API
|
||||||
|
timeout: Request timeout in seconds
|
||||||
|
token: Optional bearer token for authentication
|
||||||
|
"""
|
||||||
self.url: str = url
|
self.url: str = url
|
||||||
self.timeout: int = timeout
|
self.timeout: int = timeout
|
||||||
self.token: Optional[str] = token
|
self.token: Optional[str] = token
|
||||||
|
|
||||||
async def request(self, path: str, request_data: Dict[str, Any]) -> Dict[str, Any]:
|
async def request(self, path: str, request_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
"""Make async HTTP request to Gateway API"""
|
"""
|
||||||
|
Make async HTTP POST request to Gateway API.
|
||||||
|
|
||||||
|
Internal method for making authenticated requests to the TrustGraph API.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path: API endpoint path (relative to base URL)
|
||||||
|
request_data: Request payload dictionary
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Response object from API
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ProtocolException: If HTTP status is not 200 or response is not valid JSON
|
||||||
|
ApplicationException: If API returns an error response
|
||||||
|
"""
|
||||||
url = f"{self.url}{path}"
|
url = f"{self.url}{path}"
|
||||||
|
|
||||||
headers = {"Content-Type": "application/json"}
|
headers = {"Content-Type": "application/json"}
|
||||||
|
|
@ -49,12 +92,49 @@ class AsyncFlow:
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
async def list(self) -> List[str]:
|
async def list(self) -> List[str]:
|
||||||
"""List all flows"""
|
"""
|
||||||
|
List all flow identifiers.
|
||||||
|
|
||||||
|
Retrieves IDs of all flows currently deployed in the system.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[str]: List of flow identifiers
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
async_flow = await api.async_flow()
|
||||||
|
|
||||||
|
# List all flows
|
||||||
|
flows = await async_flow.list()
|
||||||
|
print(f"Available flows: {flows}")
|
||||||
|
```
|
||||||
|
"""
|
||||||
result = await self.request("flow", {"operation": "list-flows"})
|
result = await self.request("flow", {"operation": "list-flows"})
|
||||||
return result.get("flow-ids", [])
|
return result.get("flow-ids", [])
|
||||||
|
|
||||||
async def get(self, id: str) -> Dict[str, Any]:
|
async def get(self, id: str) -> Dict[str, Any]:
|
||||||
"""Get flow definition"""
|
"""
|
||||||
|
Get flow definition.
|
||||||
|
|
||||||
|
Retrieves the complete flow configuration including its class name,
|
||||||
|
description, and parameters.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id: Flow identifier
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Flow definition object
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
async_flow = await api.async_flow()
|
||||||
|
|
||||||
|
# Get flow definition
|
||||||
|
flow_def = await async_flow.get("default")
|
||||||
|
print(f"Flow class: {flow_def.get('class-name')}")
|
||||||
|
print(f"Description: {flow_def.get('description')}")
|
||||||
|
```
|
||||||
|
"""
|
||||||
result = await self.request("flow", {
|
result = await self.request("flow", {
|
||||||
"operation": "get-flow",
|
"operation": "get-flow",
|
||||||
"flow-id": id
|
"flow-id": id
|
||||||
|
|
@ -62,7 +142,31 @@ class AsyncFlow:
|
||||||
return json.loads(result.get("flow", "{}"))
|
return json.loads(result.get("flow", "{}"))
|
||||||
|
|
||||||
async def start(self, class_name: str, id: str, description: str, parameters: Optional[Dict] = None):
|
async def start(self, class_name: str, id: str, description: str, parameters: Optional[Dict] = None):
|
||||||
"""Start a flow"""
|
"""
|
||||||
|
Start a new flow instance.
|
||||||
|
|
||||||
|
Creates and starts a flow from a flow class definition with the specified
|
||||||
|
parameters.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
class_name: Flow class name to instantiate
|
||||||
|
id: Identifier for the new flow instance
|
||||||
|
description: Human-readable description of the flow
|
||||||
|
parameters: Optional configuration parameters for the flow
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
async_flow = await api.async_flow()
|
||||||
|
|
||||||
|
# Start a flow from a class
|
||||||
|
await async_flow.start(
|
||||||
|
class_name="default",
|
||||||
|
id="my-flow",
|
||||||
|
description="Custom flow instance",
|
||||||
|
parameters={"model": "claude-3-opus"}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
request_data = {
|
request_data = {
|
||||||
"operation": "start-flow",
|
"operation": "start-flow",
|
||||||
"flow-id": id,
|
"flow-id": id,
|
||||||
|
|
@ -75,19 +179,70 @@ class AsyncFlow:
|
||||||
await self.request("flow", request_data)
|
await self.request("flow", request_data)
|
||||||
|
|
||||||
async def stop(self, id: str):
|
async def stop(self, id: str):
|
||||||
"""Stop a flow"""
|
"""
|
||||||
|
Stop a running flow.
|
||||||
|
|
||||||
|
Stops and removes a flow instance, freeing its resources.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id: Flow identifier to stop
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
async_flow = await api.async_flow()
|
||||||
|
|
||||||
|
# Stop a flow
|
||||||
|
await async_flow.stop("my-flow")
|
||||||
|
```
|
||||||
|
"""
|
||||||
await self.request("flow", {
|
await self.request("flow", {
|
||||||
"operation": "stop-flow",
|
"operation": "stop-flow",
|
||||||
"flow-id": id
|
"flow-id": id
|
||||||
})
|
})
|
||||||
|
|
||||||
async def list_classes(self) -> List[str]:
|
async def list_classes(self) -> List[str]:
|
||||||
"""List flow classes"""
|
"""
|
||||||
|
List all flow class names.
|
||||||
|
|
||||||
|
Retrieves names of all flow classes (blueprints) available in the system.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[str]: List of flow class names
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
async_flow = await api.async_flow()
|
||||||
|
|
||||||
|
# List available flow classes
|
||||||
|
classes = await async_flow.list_classes()
|
||||||
|
print(f"Available flow classes: {classes}")
|
||||||
|
```
|
||||||
|
"""
|
||||||
result = await self.request("flow", {"operation": "list-classes"})
|
result = await self.request("flow", {"operation": "list-classes"})
|
||||||
return result.get("class-names", [])
|
return result.get("class-names", [])
|
||||||
|
|
||||||
async def get_class(self, class_name: str) -> Dict[str, Any]:
|
async def get_class(self, class_name: str) -> Dict[str, Any]:
|
||||||
"""Get flow class definition"""
|
"""
|
||||||
|
Get flow class definition.
|
||||||
|
|
||||||
|
Retrieves the blueprint definition for a flow class, including its
|
||||||
|
configuration schema and service bindings.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
class_name: Flow class name
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Flow class definition object
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
async_flow = await api.async_flow()
|
||||||
|
|
||||||
|
# Get flow class definition
|
||||||
|
class_def = await async_flow.get_class("default")
|
||||||
|
print(f"Services: {class_def.get('services')}")
|
||||||
|
```
|
||||||
|
"""
|
||||||
result = await self.request("flow", {
|
result = await self.request("flow", {
|
||||||
"operation": "get-class",
|
"operation": "get-class",
|
||||||
"class-name": class_name
|
"class-name": class_name
|
||||||
|
|
@ -95,7 +250,29 @@ class AsyncFlow:
|
||||||
return json.loads(result.get("class-definition", "{}"))
|
return json.loads(result.get("class-definition", "{}"))
|
||||||
|
|
||||||
async def put_class(self, class_name: str, definition: Dict[str, Any]):
|
async def put_class(self, class_name: str, definition: Dict[str, Any]):
|
||||||
"""Create/update flow class"""
|
"""
|
||||||
|
Create or update a flow class definition.
|
||||||
|
|
||||||
|
Stores a flow class blueprint that can be used to instantiate flows.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
class_name: Flow class name
|
||||||
|
definition: Flow class definition object
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
async_flow = await api.async_flow()
|
||||||
|
|
||||||
|
# Create a custom flow class
|
||||||
|
class_def = {
|
||||||
|
"services": {
|
||||||
|
"agent": {"module": "agent", "config": {...}},
|
||||||
|
"graph-rag": {"module": "graph-rag", "config": {...}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await async_flow.put_class("custom-flow", class_def)
|
||||||
|
```
|
||||||
|
"""
|
||||||
await self.request("flow", {
|
await self.request("flow", {
|
||||||
"operation": "put-class",
|
"operation": "put-class",
|
||||||
"class-name": class_name,
|
"class-name": class_name,
|
||||||
|
|
@ -103,35 +280,145 @@ class AsyncFlow:
|
||||||
})
|
})
|
||||||
|
|
||||||
async def delete_class(self, class_name: str):
|
async def delete_class(self, class_name: str):
|
||||||
"""Delete flow class"""
|
"""
|
||||||
|
Delete a flow class definition.
|
||||||
|
|
||||||
|
Removes a flow class blueprint from the system. Does not affect
|
||||||
|
running flow instances.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
class_name: Flow class name to delete
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
async_flow = await api.async_flow()
|
||||||
|
|
||||||
|
# Delete a flow class
|
||||||
|
await async_flow.delete_class("old-flow-class")
|
||||||
|
```
|
||||||
|
"""
|
||||||
await self.request("flow", {
|
await self.request("flow", {
|
||||||
"operation": "delete-class",
|
"operation": "delete-class",
|
||||||
"class-name": class_name
|
"class-name": class_name
|
||||||
})
|
})
|
||||||
|
|
||||||
def id(self, flow_id: str):
|
def id(self, flow_id: str):
|
||||||
"""Get async flow instance"""
|
"""
|
||||||
|
Get an async flow instance client.
|
||||||
|
|
||||||
|
Returns a client for interacting with a specific flow's services
|
||||||
|
(agent, RAG, queries, embeddings, etc.).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
flow_id: Flow identifier
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
AsyncFlowInstance: Client for flow-specific operations
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
async_flow = await api.async_flow()
|
||||||
|
|
||||||
|
# Get flow instance
|
||||||
|
flow = async_flow.id("default")
|
||||||
|
|
||||||
|
# Use flow services
|
||||||
|
result = await flow.graph_rag(
|
||||||
|
query="What is TrustGraph?",
|
||||||
|
user="trustgraph",
|
||||||
|
collection="default"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
return AsyncFlowInstance(self, flow_id)
|
return AsyncFlowInstance(self, flow_id)
|
||||||
|
|
||||||
async def aclose(self) -> None:
|
async def aclose(self) -> None:
|
||||||
"""Close connection (cleanup handled by aiohttp session)"""
|
"""
|
||||||
|
Close async client and cleanup resources.
|
||||||
|
|
||||||
|
Note: Cleanup is handled automatically by aiohttp session context managers.
|
||||||
|
This method is provided for consistency with other async clients.
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AsyncFlowInstance:
|
class AsyncFlowInstance:
|
||||||
"""Asynchronous REST flow instance"""
|
"""
|
||||||
|
Asynchronous flow instance client.
|
||||||
|
|
||||||
|
Provides async/await access to flow-scoped services including agents,
|
||||||
|
RAG queries, embeddings, and graph queries. All operations return complete
|
||||||
|
responses (non-streaming).
|
||||||
|
|
||||||
|
Note: For streaming support, use AsyncSocketFlowInstance instead.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, flow: AsyncFlow, flow_id: str):
|
def __init__(self, flow: AsyncFlow, flow_id: str):
|
||||||
|
"""
|
||||||
|
Initialize async flow instance.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
flow: Parent AsyncFlow client
|
||||||
|
flow_id: Flow identifier
|
||||||
|
"""
|
||||||
self.flow = flow
|
self.flow = flow
|
||||||
self.flow_id = flow_id
|
self.flow_id = flow_id
|
||||||
|
|
||||||
async def request(self, service: str, request_data: Dict[str, Any]) -> Dict[str, Any]:
|
async def request(self, service: str, request_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
"""Make request to flow-scoped service"""
|
"""
|
||||||
|
Make request to a flow-scoped service.
|
||||||
|
|
||||||
|
Internal method for calling services within this flow instance.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
service: Service name (e.g., "agent", "graph-rag", "triples")
|
||||||
|
request_data: Service request payload
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Service response object
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ProtocolException: If request fails or response is invalid
|
||||||
|
ApplicationException: If service returns an error
|
||||||
|
"""
|
||||||
return await self.flow.request(f"flow/{self.flow_id}/service/{service}", request_data)
|
return await self.flow.request(f"flow/{self.flow_id}/service/{service}", request_data)
|
||||||
|
|
||||||
async def agent(self, question: str, user: str, state: Optional[Dict] = None,
|
async def agent(self, question: str, user: str, state: Optional[Dict] = None,
|
||||||
group: Optional[str] = None, history: Optional[List] = None, **kwargs: Any) -> Dict[str, Any]:
|
group: Optional[str] = None, history: Optional[List] = None, **kwargs: Any) -> Dict[str, Any]:
|
||||||
"""Execute agent (non-streaming, use async_socket for streaming)"""
|
"""
|
||||||
|
Execute an agent operation (non-streaming).
|
||||||
|
|
||||||
|
Runs an agent to answer a question, with optional conversation state and
|
||||||
|
history. Returns the complete response after the agent has finished
|
||||||
|
processing.
|
||||||
|
|
||||||
|
Note: This method does not support streaming. For real-time agent thoughts
|
||||||
|
and observations, use AsyncSocketFlowInstance.agent() instead.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
question: User question or instruction
|
||||||
|
user: User identifier
|
||||||
|
state: Optional state dictionary for conversation context
|
||||||
|
group: Optional group identifier for session management
|
||||||
|
history: Optional conversation history list
|
||||||
|
**kwargs: Additional service-specific parameters
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Complete agent response including answer and metadata
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
async_flow = await api.async_flow()
|
||||||
|
flow = async_flow.id("default")
|
||||||
|
|
||||||
|
# Execute agent
|
||||||
|
result = await flow.agent(
|
||||||
|
question="What is the capital of France?",
|
||||||
|
user="trustgraph"
|
||||||
|
)
|
||||||
|
print(f"Answer: {result.get('response')}")
|
||||||
|
```
|
||||||
|
"""
|
||||||
request_data = {
|
request_data = {
|
||||||
"question": question,
|
"question": question,
|
||||||
"user": user,
|
"user": user,
|
||||||
|
|
@ -148,7 +435,36 @@ class AsyncFlowInstance:
|
||||||
return await self.request("agent", request_data)
|
return await self.request("agent", request_data)
|
||||||
|
|
||||||
async def text_completion(self, system: str, prompt: str, **kwargs: Any) -> str:
|
async def text_completion(self, system: str, prompt: str, **kwargs: Any) -> str:
|
||||||
"""Text completion (non-streaming, use async_socket for streaming)"""
|
"""
|
||||||
|
Generate text completion (non-streaming).
|
||||||
|
|
||||||
|
Generates a text response from an LLM given a system prompt and user prompt.
|
||||||
|
Returns the complete response text.
|
||||||
|
|
||||||
|
Note: This method does not support streaming. For streaming text generation,
|
||||||
|
use AsyncSocketFlowInstance.text_completion() instead.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
system: System prompt defining the LLM's behavior
|
||||||
|
prompt: User prompt or question
|
||||||
|
**kwargs: Additional service-specific parameters
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Complete generated text response
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
async_flow = await api.async_flow()
|
||||||
|
flow = async_flow.id("default")
|
||||||
|
|
||||||
|
# Generate text
|
||||||
|
response = await flow.text_completion(
|
||||||
|
system="You are a helpful assistant.",
|
||||||
|
prompt="Explain quantum computing in simple terms."
|
||||||
|
)
|
||||||
|
print(response)
|
||||||
|
```
|
||||||
|
"""
|
||||||
request_data = {
|
request_data = {
|
||||||
"system": system,
|
"system": system,
|
||||||
"prompt": prompt,
|
"prompt": prompt,
|
||||||
|
|
@ -162,7 +478,43 @@ class AsyncFlowInstance:
|
||||||
async def graph_rag(self, query: str, user: str, collection: str,
|
async def graph_rag(self, query: str, user: str, collection: str,
|
||||||
max_subgraph_size: int = 1000, max_subgraph_count: int = 5,
|
max_subgraph_size: int = 1000, max_subgraph_count: int = 5,
|
||||||
max_entity_distance: int = 3, **kwargs: Any) -> str:
|
max_entity_distance: int = 3, **kwargs: Any) -> str:
|
||||||
"""Graph RAG (non-streaming, use async_socket for streaming)"""
|
"""
|
||||||
|
Execute graph-based RAG query (non-streaming).
|
||||||
|
|
||||||
|
Performs Retrieval-Augmented Generation using knowledge graph data.
|
||||||
|
Identifies relevant entities and their relationships, then generates a
|
||||||
|
response grounded in the graph structure. Returns complete response.
|
||||||
|
|
||||||
|
Note: This method does not support streaming. For streaming RAG responses,
|
||||||
|
use AsyncSocketFlowInstance.graph_rag() instead.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query: User query text
|
||||||
|
user: User identifier
|
||||||
|
collection: Collection identifier containing the knowledge graph
|
||||||
|
max_subgraph_size: Maximum number of triples per subgraph (default: 1000)
|
||||||
|
max_subgraph_count: Maximum number of subgraphs to retrieve (default: 5)
|
||||||
|
max_entity_distance: Maximum graph distance for entity expansion (default: 3)
|
||||||
|
**kwargs: Additional service-specific parameters
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Complete generated response grounded in graph data
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
async_flow = await api.async_flow()
|
||||||
|
flow = async_flow.id("default")
|
||||||
|
|
||||||
|
# Query knowledge graph
|
||||||
|
response = await flow.graph_rag(
|
||||||
|
query="What are the relationships between these entities?",
|
||||||
|
user="trustgraph",
|
||||||
|
collection="medical-kb",
|
||||||
|
max_subgraph_count=3
|
||||||
|
)
|
||||||
|
print(response)
|
||||||
|
```
|
||||||
|
"""
|
||||||
request_data = {
|
request_data = {
|
||||||
"query": query,
|
"query": query,
|
||||||
"user": user,
|
"user": user,
|
||||||
|
|
@ -179,7 +531,41 @@ class AsyncFlowInstance:
|
||||||
|
|
||||||
async def document_rag(self, query: str, user: str, collection: str,
|
async def document_rag(self, query: str, user: str, collection: str,
|
||||||
doc_limit: int = 10, **kwargs: Any) -> str:
|
doc_limit: int = 10, **kwargs: Any) -> str:
|
||||||
"""Document RAG (non-streaming, use async_socket for streaming)"""
|
"""
|
||||||
|
Execute document-based RAG query (non-streaming).
|
||||||
|
|
||||||
|
Performs Retrieval-Augmented Generation using document embeddings.
|
||||||
|
Retrieves relevant document chunks via semantic search, then generates
|
||||||
|
a response grounded in the retrieved documents. Returns complete response.
|
||||||
|
|
||||||
|
Note: This method does not support streaming. For streaming RAG responses,
|
||||||
|
use AsyncSocketFlowInstance.document_rag() instead.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query: User query text
|
||||||
|
user: User identifier
|
||||||
|
collection: Collection identifier containing documents
|
||||||
|
doc_limit: Maximum number of document chunks to retrieve (default: 10)
|
||||||
|
**kwargs: Additional service-specific parameters
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Complete generated response grounded in document data
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
async_flow = await api.async_flow()
|
||||||
|
flow = async_flow.id("default")
|
||||||
|
|
||||||
|
# Query documents
|
||||||
|
response = await flow.document_rag(
|
||||||
|
query="What does the documentation say about authentication?",
|
||||||
|
user="trustgraph",
|
||||||
|
collection="docs",
|
||||||
|
doc_limit=5
|
||||||
|
)
|
||||||
|
print(response)
|
||||||
|
```
|
||||||
|
"""
|
||||||
request_data = {
|
request_data = {
|
||||||
"query": query,
|
"query": query,
|
||||||
"user": user,
|
"user": user,
|
||||||
|
|
@ -193,7 +579,39 @@ class AsyncFlowInstance:
|
||||||
return result.get("response", "")
|
return result.get("response", "")
|
||||||
|
|
||||||
async def graph_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs: Any):
|
async def graph_embeddings_query(self, text: str, user: str, collection: str, limit: int = 10, **kwargs: Any):
|
||||||
"""Query graph embeddings for semantic search"""
|
"""
|
||||||
|
Query graph embeddings for semantic entity search.
|
||||||
|
|
||||||
|
Performs semantic search over graph entity embeddings to find entities
|
||||||
|
most relevant to the input text. Returns entities ranked by similarity.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text: Query text for semantic search
|
||||||
|
user: User identifier
|
||||||
|
collection: Collection identifier containing graph embeddings
|
||||||
|
limit: Maximum number of results to return (default: 10)
|
||||||
|
**kwargs: Additional service-specific parameters
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Response containing ranked entity matches with similarity scores
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
async_flow = await api.async_flow()
|
||||||
|
flow = async_flow.id("default")
|
||||||
|
|
||||||
|
# Find related entities
|
||||||
|
results = await flow.graph_embeddings_query(
|
||||||
|
text="machine learning algorithms",
|
||||||
|
user="trustgraph",
|
||||||
|
collection="tech-kb",
|
||||||
|
limit=5
|
||||||
|
)
|
||||||
|
|
||||||
|
for entity in results.get("entities", []):
|
||||||
|
print(f"{entity['name']}: {entity['score']}")
|
||||||
|
```
|
||||||
|
"""
|
||||||
request_data = {
|
request_data = {
|
||||||
"text": text,
|
"text": text,
|
||||||
"user": user,
|
"user": user,
|
||||||
|
|
@ -205,14 +623,72 @@ class AsyncFlowInstance:
|
||||||
return await self.request("graph-embeddings", request_data)
|
return await self.request("graph-embeddings", request_data)
|
||||||
|
|
||||||
async def embeddings(self, text: str, **kwargs: Any):
|
async def embeddings(self, text: str, **kwargs: Any):
|
||||||
"""Generate text embeddings"""
|
"""
|
||||||
|
Generate embeddings for input text.
|
||||||
|
|
||||||
|
Converts text into a numerical vector representation using the flow's
|
||||||
|
configured embedding model. Useful for semantic search and similarity
|
||||||
|
comparisons.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text: Input text to embed
|
||||||
|
**kwargs: Additional service-specific parameters
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Response containing embedding vector and metadata
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
async_flow = await api.async_flow()
|
||||||
|
flow = async_flow.id("default")
|
||||||
|
|
||||||
|
# Generate embeddings
|
||||||
|
result = await flow.embeddings(text="Sample text to embed")
|
||||||
|
vector = result.get("embedding")
|
||||||
|
print(f"Embedding dimension: {len(vector)}")
|
||||||
|
```
|
||||||
|
"""
|
||||||
request_data = {"text": text}
|
request_data = {"text": text}
|
||||||
request_data.update(kwargs)
|
request_data.update(kwargs)
|
||||||
|
|
||||||
return await self.request("embeddings", request_data)
|
return await self.request("embeddings", request_data)
|
||||||
|
|
||||||
async def triples_query(self, s=None, p=None, o=None, user=None, collection=None, limit=100, **kwargs: Any):
|
async def triples_query(self, s=None, p=None, o=None, user=None, collection=None, limit=100, **kwargs: Any):
|
||||||
"""Triple pattern query"""
|
"""
|
||||||
|
Query RDF triples using pattern matching.
|
||||||
|
|
||||||
|
Searches for triples matching the specified subject, predicate, and/or
|
||||||
|
object patterns. Patterns use None as a wildcard to match any value.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
s: Subject pattern (None for wildcard)
|
||||||
|
p: Predicate pattern (None for wildcard)
|
||||||
|
o: Object pattern (None for wildcard)
|
||||||
|
user: User identifier (None for all users)
|
||||||
|
collection: Collection identifier (None for all collections)
|
||||||
|
limit: Maximum number of triples to return (default: 100)
|
||||||
|
**kwargs: Additional service-specific parameters
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Response containing matching triples
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
async_flow = await api.async_flow()
|
||||||
|
flow = async_flow.id("default")
|
||||||
|
|
||||||
|
# Find all triples with a specific predicate
|
||||||
|
results = await flow.triples_query(
|
||||||
|
p="knows",
|
||||||
|
user="trustgraph",
|
||||||
|
collection="social",
|
||||||
|
limit=50
|
||||||
|
)
|
||||||
|
|
||||||
|
for triple in results.get("triples", []):
|
||||||
|
print(f"{triple['s']} knows {triple['o']}")
|
||||||
|
```
|
||||||
|
"""
|
||||||
request_data = {"limit": limit}
|
request_data = {"limit": limit}
|
||||||
if s is not None:
|
if s is not None:
|
||||||
request_data["s"] = str(s)
|
request_data["s"] = str(s)
|
||||||
|
|
@ -230,7 +706,50 @@ class AsyncFlowInstance:
|
||||||
|
|
||||||
async def objects_query(self, query: str, user: str, collection: str, variables: Optional[Dict] = None,
|
async def objects_query(self, query: str, user: str, collection: str, variables: Optional[Dict] = None,
|
||||||
operation_name: Optional[str] = None, **kwargs: Any):
|
operation_name: Optional[str] = None, **kwargs: Any):
|
||||||
"""GraphQL query"""
|
"""
|
||||||
|
Execute a GraphQL query on stored objects.
|
||||||
|
|
||||||
|
Queries structured data objects using GraphQL syntax. Supports complex
|
||||||
|
queries with variables and named operations.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query: GraphQL query string
|
||||||
|
user: User identifier
|
||||||
|
collection: Collection identifier containing objects
|
||||||
|
variables: Optional GraphQL query variables
|
||||||
|
operation_name: Optional operation name for multi-operation queries
|
||||||
|
**kwargs: Additional service-specific parameters
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: GraphQL response with data and/or errors
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
async_flow = await api.async_flow()
|
||||||
|
flow = async_flow.id("default")
|
||||||
|
|
||||||
|
# Execute GraphQL query
|
||||||
|
query = '''
|
||||||
|
query GetUsers($status: String!) {
|
||||||
|
users(status: $status) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
email
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
|
||||||
|
result = await flow.objects_query(
|
||||||
|
query=query,
|
||||||
|
user="trustgraph",
|
||||||
|
collection="users",
|
||||||
|
variables={"status": "active"}
|
||||||
|
)
|
||||||
|
|
||||||
|
for user in result.get("data", {}).get("users", []):
|
||||||
|
print(f"{user['name']}: {user['email']}")
|
||||||
|
```
|
||||||
|
"""
|
||||||
request_data = {
|
request_data = {
|
||||||
"query": query,
|
"query": query,
|
||||||
"user": user,
|
"user": user,
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,10 @@
|
||||||
|
"""
|
||||||
|
TrustGraph Synchronous Bulk Operations Client
|
||||||
|
|
||||||
|
This module provides synchronous bulk import/export operations via WebSocket
|
||||||
|
for efficient transfer of large datasets including triples, embeddings,
|
||||||
|
entity contexts, and objects.
|
||||||
|
"""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
@ -9,9 +16,24 @@ from . exceptions import ProtocolException
|
||||||
|
|
||||||
|
|
||||||
class BulkClient:
|
class BulkClient:
|
||||||
"""Synchronous bulk operations client"""
|
"""
|
||||||
|
Synchronous bulk operations client for import/export.
|
||||||
|
|
||||||
|
Provides efficient bulk data transfer via WebSocket for large datasets.
|
||||||
|
Wraps async WebSocket operations with synchronous generators for ease of use.
|
||||||
|
|
||||||
|
Note: For true async support, use AsyncBulkClient instead.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, url: str, timeout: int, token: Optional[str]) -> None:
|
def __init__(self, url: str, timeout: int, token: Optional[str]) -> None:
|
||||||
|
"""
|
||||||
|
Initialize synchronous bulk client.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
url: Base URL for TrustGraph API (HTTP/HTTPS will be converted to WS/WSS)
|
||||||
|
timeout: WebSocket timeout in seconds
|
||||||
|
token: Optional bearer token for authentication
|
||||||
|
"""
|
||||||
self.url: str = self._convert_to_ws_url(url)
|
self.url: str = self._convert_to_ws_url(url)
|
||||||
self.timeout: int = timeout
|
self.timeout: int = timeout
|
||||||
self.token: Optional[str] = token
|
self.token: Optional[str] = token
|
||||||
|
|
@ -41,7 +63,32 @@ class BulkClient:
|
||||||
return loop.run_until_complete(coro)
|
return loop.run_until_complete(coro)
|
||||||
|
|
||||||
def import_triples(self, flow: str, triples: Iterator[Triple], **kwargs: Any) -> None:
|
def import_triples(self, flow: str, triples: Iterator[Triple], **kwargs: Any) -> None:
|
||||||
"""Bulk import triples via WebSocket"""
|
"""
|
||||||
|
Bulk import RDF triples into a flow.
|
||||||
|
|
||||||
|
Efficiently uploads large numbers of triples via WebSocket streaming.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
flow: Flow identifier
|
||||||
|
triples: Iterator yielding Triple objects
|
||||||
|
**kwargs: Additional parameters (reserved for future use)
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
from trustgraph.api import Triple
|
||||||
|
|
||||||
|
bulk = api.bulk()
|
||||||
|
|
||||||
|
# Generate triples to import
|
||||||
|
def triple_generator():
|
||||||
|
yield Triple(s="subj1", p="pred", o="obj1")
|
||||||
|
yield Triple(s="subj2", p="pred", o="obj2")
|
||||||
|
# ... more triples
|
||||||
|
|
||||||
|
# Import triples
|
||||||
|
bulk.import_triples(flow="default", triples=triple_generator())
|
||||||
|
```
|
||||||
|
"""
|
||||||
self._run_async(self._import_triples_async(flow, triples))
|
self._run_async(self._import_triples_async(flow, triples))
|
||||||
|
|
||||||
async def _import_triples_async(self, flow: str, triples: Iterator[Triple]) -> None:
|
async def _import_triples_async(self, flow: str, triples: Iterator[Triple]) -> None:
|
||||||
|
|
@ -60,7 +107,27 @@ class BulkClient:
|
||||||
await websocket.send(json.dumps(message))
|
await websocket.send(json.dumps(message))
|
||||||
|
|
||||||
def export_triples(self, flow: str, **kwargs: Any) -> Iterator[Triple]:
|
def export_triples(self, flow: str, **kwargs: Any) -> Iterator[Triple]:
|
||||||
"""Bulk export triples via WebSocket"""
|
"""
|
||||||
|
Bulk export RDF triples from a flow.
|
||||||
|
|
||||||
|
Efficiently downloads all triples via WebSocket streaming.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
flow: Flow identifier
|
||||||
|
**kwargs: Additional parameters (reserved for future use)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Iterator[Triple]: Stream of Triple objects
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
bulk = api.bulk()
|
||||||
|
|
||||||
|
# Export and process triples
|
||||||
|
for triple in bulk.export_triples(flow="default"):
|
||||||
|
print(f"{triple.s} -> {triple.p} -> {triple.o}")
|
||||||
|
```
|
||||||
|
"""
|
||||||
async_gen = self._export_triples_async(flow)
|
async_gen = self._export_triples_async(flow)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -101,7 +168,32 @@ class BulkClient:
|
||||||
)
|
)
|
||||||
|
|
||||||
def import_graph_embeddings(self, flow: str, embeddings: Iterator[Dict[str, Any]], **kwargs: Any) -> None:
|
def import_graph_embeddings(self, flow: str, embeddings: Iterator[Dict[str, Any]], **kwargs: Any) -> None:
|
||||||
"""Bulk import graph embeddings via WebSocket"""
|
"""
|
||||||
|
Bulk import graph embeddings into a flow.
|
||||||
|
|
||||||
|
Efficiently uploads graph entity embeddings via WebSocket streaming.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
flow: Flow identifier
|
||||||
|
embeddings: Iterator yielding embedding dictionaries
|
||||||
|
**kwargs: Additional parameters (reserved for future use)
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
bulk = api.bulk()
|
||||||
|
|
||||||
|
# Generate embeddings to import
|
||||||
|
def embedding_generator():
|
||||||
|
yield {"entity": "entity1", "embedding": [0.1, 0.2, ...]}
|
||||||
|
yield {"entity": "entity2", "embedding": [0.3, 0.4, ...]}
|
||||||
|
# ... more embeddings
|
||||||
|
|
||||||
|
bulk.import_graph_embeddings(
|
||||||
|
flow="default",
|
||||||
|
embeddings=embedding_generator()
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
self._run_async(self._import_graph_embeddings_async(flow, embeddings))
|
self._run_async(self._import_graph_embeddings_async(flow, embeddings))
|
||||||
|
|
||||||
async def _import_graph_embeddings_async(self, flow: str, embeddings: Iterator[Dict[str, Any]]) -> None:
|
async def _import_graph_embeddings_async(self, flow: str, embeddings: Iterator[Dict[str, Any]]) -> None:
|
||||||
|
|
@ -115,7 +207,29 @@ class BulkClient:
|
||||||
await websocket.send(json.dumps(embedding))
|
await websocket.send(json.dumps(embedding))
|
||||||
|
|
||||||
def export_graph_embeddings(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]:
|
def export_graph_embeddings(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]:
|
||||||
"""Bulk export graph embeddings via WebSocket"""
|
"""
|
||||||
|
Bulk export graph embeddings from a flow.
|
||||||
|
|
||||||
|
Efficiently downloads all graph entity embeddings via WebSocket streaming.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
flow: Flow identifier
|
||||||
|
**kwargs: Additional parameters (reserved for future use)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Iterator[Dict[str, Any]]: Stream of embedding dictionaries
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
bulk = api.bulk()
|
||||||
|
|
||||||
|
# Export and process embeddings
|
||||||
|
for embedding in bulk.export_graph_embeddings(flow="default"):
|
||||||
|
entity = embedding.get("entity")
|
||||||
|
vector = embedding.get("embedding")
|
||||||
|
print(f"{entity}: {len(vector)} dimensions")
|
||||||
|
```
|
||||||
|
"""
|
||||||
async_gen = self._export_graph_embeddings_async(flow)
|
async_gen = self._export_graph_embeddings_async(flow)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -151,7 +265,33 @@ class BulkClient:
|
||||||
yield json.loads(raw_message)
|
yield json.loads(raw_message)
|
||||||
|
|
||||||
def import_document_embeddings(self, flow: str, embeddings: Iterator[Dict[str, Any]], **kwargs: Any) -> None:
|
def import_document_embeddings(self, flow: str, embeddings: Iterator[Dict[str, Any]], **kwargs: Any) -> None:
|
||||||
"""Bulk import document embeddings via WebSocket"""
|
"""
|
||||||
|
Bulk import document embeddings into a flow.
|
||||||
|
|
||||||
|
Efficiently uploads document chunk embeddings via WebSocket streaming
|
||||||
|
for use in document RAG queries.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
flow: Flow identifier
|
||||||
|
embeddings: Iterator yielding embedding dictionaries
|
||||||
|
**kwargs: Additional parameters (reserved for future use)
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
bulk = api.bulk()
|
||||||
|
|
||||||
|
# Generate document embeddings to import
|
||||||
|
def doc_embedding_generator():
|
||||||
|
yield {"id": "doc1-chunk1", "embedding": [0.1, 0.2, ...]}
|
||||||
|
yield {"id": "doc1-chunk2", "embedding": [0.3, 0.4, ...]}
|
||||||
|
# ... more embeddings
|
||||||
|
|
||||||
|
bulk.import_document_embeddings(
|
||||||
|
flow="default",
|
||||||
|
embeddings=doc_embedding_generator()
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
self._run_async(self._import_document_embeddings_async(flow, embeddings))
|
self._run_async(self._import_document_embeddings_async(flow, embeddings))
|
||||||
|
|
||||||
async def _import_document_embeddings_async(self, flow: str, embeddings: Iterator[Dict[str, Any]]) -> None:
|
async def _import_document_embeddings_async(self, flow: str, embeddings: Iterator[Dict[str, Any]]) -> None:
|
||||||
|
|
@ -165,7 +305,29 @@ class BulkClient:
|
||||||
await websocket.send(json.dumps(embedding))
|
await websocket.send(json.dumps(embedding))
|
||||||
|
|
||||||
def export_document_embeddings(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]:
|
def export_document_embeddings(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]:
|
||||||
"""Bulk export document embeddings via WebSocket"""
|
"""
|
||||||
|
Bulk export document embeddings from a flow.
|
||||||
|
|
||||||
|
Efficiently downloads all document chunk embeddings via WebSocket streaming.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
flow: Flow identifier
|
||||||
|
**kwargs: Additional parameters (reserved for future use)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Iterator[Dict[str, Any]]: Stream of embedding dictionaries
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
bulk = api.bulk()
|
||||||
|
|
||||||
|
# Export and process document embeddings
|
||||||
|
for embedding in bulk.export_document_embeddings(flow="default"):
|
||||||
|
doc_id = embedding.get("id")
|
||||||
|
vector = embedding.get("embedding")
|
||||||
|
print(f"{doc_id}: {len(vector)} dimensions")
|
||||||
|
```
|
||||||
|
"""
|
||||||
async_gen = self._export_document_embeddings_async(flow)
|
async_gen = self._export_document_embeddings_async(flow)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -201,7 +363,34 @@ class BulkClient:
|
||||||
yield json.loads(raw_message)
|
yield json.loads(raw_message)
|
||||||
|
|
||||||
def import_entity_contexts(self, flow: str, contexts: Iterator[Dict[str, Any]], **kwargs: Any) -> None:
|
def import_entity_contexts(self, flow: str, contexts: Iterator[Dict[str, Any]], **kwargs: Any) -> None:
|
||||||
"""Bulk import entity contexts via WebSocket"""
|
"""
|
||||||
|
Bulk import entity contexts into a flow.
|
||||||
|
|
||||||
|
Efficiently uploads entity context information via WebSocket streaming.
|
||||||
|
Entity contexts provide additional textual context about graph entities
|
||||||
|
for improved RAG performance.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
flow: Flow identifier
|
||||||
|
contexts: Iterator yielding context dictionaries
|
||||||
|
**kwargs: Additional parameters (reserved for future use)
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
bulk = api.bulk()
|
||||||
|
|
||||||
|
# Generate entity contexts to import
|
||||||
|
def context_generator():
|
||||||
|
yield {"entity": "entity1", "context": "Description of entity1..."}
|
||||||
|
yield {"entity": "entity2", "context": "Description of entity2..."}
|
||||||
|
# ... more contexts
|
||||||
|
|
||||||
|
bulk.import_entity_contexts(
|
||||||
|
flow="default",
|
||||||
|
contexts=context_generator()
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
self._run_async(self._import_entity_contexts_async(flow, contexts))
|
self._run_async(self._import_entity_contexts_async(flow, contexts))
|
||||||
|
|
||||||
async def _import_entity_contexts_async(self, flow: str, contexts: Iterator[Dict[str, Any]]) -> None:
|
async def _import_entity_contexts_async(self, flow: str, contexts: Iterator[Dict[str, Any]]) -> None:
|
||||||
|
|
@ -215,7 +404,29 @@ class BulkClient:
|
||||||
await websocket.send(json.dumps(context))
|
await websocket.send(json.dumps(context))
|
||||||
|
|
||||||
def export_entity_contexts(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]:
|
def export_entity_contexts(self, flow: str, **kwargs: Any) -> Iterator[Dict[str, Any]]:
|
||||||
"""Bulk export entity contexts via WebSocket"""
|
"""
|
||||||
|
Bulk export entity contexts from a flow.
|
||||||
|
|
||||||
|
Efficiently downloads all entity context information via WebSocket streaming.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
flow: Flow identifier
|
||||||
|
**kwargs: Additional parameters (reserved for future use)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Iterator[Dict[str, Any]]: Stream of context dictionaries
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
bulk = api.bulk()
|
||||||
|
|
||||||
|
# Export and process entity contexts
|
||||||
|
for context in bulk.export_entity_contexts(flow="default"):
|
||||||
|
entity = context.get("entity")
|
||||||
|
text = context.get("context")
|
||||||
|
print(f"{entity}: {text[:100]}...")
|
||||||
|
```
|
||||||
|
"""
|
||||||
async_gen = self._export_entity_contexts_async(flow)
|
async_gen = self._export_entity_contexts_async(flow)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -251,7 +462,33 @@ class BulkClient:
|
||||||
yield json.loads(raw_message)
|
yield json.loads(raw_message)
|
||||||
|
|
||||||
def import_objects(self, flow: str, objects: Iterator[Dict[str, Any]], **kwargs: Any) -> None:
|
def import_objects(self, flow: str, objects: Iterator[Dict[str, Any]], **kwargs: Any) -> None:
|
||||||
"""Bulk import objects via WebSocket"""
|
"""
|
||||||
|
Bulk import structured objects into a flow.
|
||||||
|
|
||||||
|
Efficiently uploads structured data objects via WebSocket streaming
|
||||||
|
for use in GraphQL queries.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
flow: Flow identifier
|
||||||
|
objects: Iterator yielding object dictionaries
|
||||||
|
**kwargs: Additional parameters (reserved for future use)
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
bulk = api.bulk()
|
||||||
|
|
||||||
|
# Generate objects to import
|
||||||
|
def object_generator():
|
||||||
|
yield {"id": "obj1", "name": "Object 1", "value": 100}
|
||||||
|
yield {"id": "obj2", "name": "Object 2", "value": 200}
|
||||||
|
# ... more objects
|
||||||
|
|
||||||
|
bulk.import_objects(
|
||||||
|
flow="default",
|
||||||
|
objects=object_generator()
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
self._run_async(self._import_objects_async(flow, objects))
|
self._run_async(self._import_objects_async(flow, objects))
|
||||||
|
|
||||||
async def _import_objects_async(self, flow: str, objects: Iterator[Dict[str, Any]]) -> None:
|
async def _import_objects_async(self, flow: str, objects: Iterator[Dict[str, Any]]) -> None:
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,11 @@
|
||||||
|
"""
|
||||||
|
TrustGraph Collection Management
|
||||||
|
|
||||||
|
This module provides interfaces for managing data collections in TrustGraph.
|
||||||
|
Collections provide logical grouping and isolation for documents and knowledge
|
||||||
|
graph data.
|
||||||
|
"""
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
@ -7,14 +15,71 @@ from . exceptions import *
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class Collection:
|
class Collection:
|
||||||
|
"""
|
||||||
|
Collection management client.
|
||||||
|
|
||||||
|
Provides methods for managing data collections, including listing,
|
||||||
|
updating metadata, and deleting collections. Collections organize
|
||||||
|
documents and knowledge graph data into logical groupings for
|
||||||
|
isolation and access control.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, api):
|
def __init__(self, api):
|
||||||
|
"""
|
||||||
|
Initialize Collection client.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
api: Parent Api instance for making requests
|
||||||
|
"""
|
||||||
self.api = api
|
self.api = api
|
||||||
|
|
||||||
def request(self, request):
|
def request(self, request):
|
||||||
|
"""
|
||||||
|
Make a collection-scoped API request.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request: Request payload dictionary
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Response object
|
||||||
|
"""
|
||||||
return self.api.request(f"collection-management", request)
|
return self.api.request(f"collection-management", request)
|
||||||
|
|
||||||
def list_collections(self, user, tag_filter=None):
|
def list_collections(self, user, tag_filter=None):
|
||||||
|
"""
|
||||||
|
List all collections for a user.
|
||||||
|
|
||||||
|
Retrieves metadata for all collections owned by the specified user,
|
||||||
|
with optional filtering by tags.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user: User identifier
|
||||||
|
tag_filter: Optional list of tags to filter collections (default: None)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[CollectionMetadata]: List of collection metadata objects
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ProtocolException: If response format is invalid
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
collection = api.collection()
|
||||||
|
|
||||||
|
# List all collections
|
||||||
|
all_colls = collection.list_collections(user="trustgraph")
|
||||||
|
for coll in all_colls:
|
||||||
|
print(f"{coll.collection}: {coll.name}")
|
||||||
|
print(f" Description: {coll.description}")
|
||||||
|
print(f" Tags: {', '.join(coll.tags)}")
|
||||||
|
|
||||||
|
# List collections with specific tags
|
||||||
|
research_colls = collection.list_collections(
|
||||||
|
user="trustgraph",
|
||||||
|
tag_filter=["research", "published"]
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
input = {
|
input = {
|
||||||
"operation": "list-collections",
|
"operation": "list-collections",
|
||||||
|
|
@ -50,6 +115,46 @@ class Collection:
|
||||||
raise ProtocolException(f"Response not formatted correctly")
|
raise ProtocolException(f"Response not formatted correctly")
|
||||||
|
|
||||||
def update_collection(self, user, collection, name=None, description=None, tags=None):
|
def update_collection(self, user, collection, name=None, description=None, tags=None):
|
||||||
|
"""
|
||||||
|
Update collection metadata.
|
||||||
|
|
||||||
|
Updates the name, description, and/or tags for an existing collection.
|
||||||
|
Only provided fields are updated; others remain unchanged.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user: User identifier
|
||||||
|
collection: Collection identifier
|
||||||
|
name: New collection name (optional)
|
||||||
|
description: New collection description (optional)
|
||||||
|
tags: New list of tags (optional)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
CollectionMetadata: Updated collection metadata, or None if not found
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ProtocolException: If response format is invalid
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
collection_api = api.collection()
|
||||||
|
|
||||||
|
# Update collection metadata
|
||||||
|
updated = collection_api.update_collection(
|
||||||
|
user="trustgraph",
|
||||||
|
collection="default",
|
||||||
|
name="Default Collection",
|
||||||
|
description="Main data collection for general use",
|
||||||
|
tags=["default", "production"]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Update only specific fields
|
||||||
|
updated = collection_api.update_collection(
|
||||||
|
user="trustgraph",
|
||||||
|
collection="research",
|
||||||
|
description="Updated description"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
input = {
|
input = {
|
||||||
"operation": "update-collection",
|
"operation": "update-collection",
|
||||||
|
|
@ -82,6 +187,29 @@ class Collection:
|
||||||
raise ProtocolException(f"Response not formatted correctly")
|
raise ProtocolException(f"Response not formatted correctly")
|
||||||
|
|
||||||
def delete_collection(self, user, collection):
|
def delete_collection(self, user, collection):
|
||||||
|
"""
|
||||||
|
Delete a collection.
|
||||||
|
|
||||||
|
Removes a collection and all its associated data from the system.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user: User identifier
|
||||||
|
collection: Collection identifier to delete
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Empty response object
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
collection_api = api.collection()
|
||||||
|
|
||||||
|
# Delete a collection
|
||||||
|
collection_api.delete_collection(
|
||||||
|
user="trustgraph",
|
||||||
|
collection="old-collection"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
input = {
|
input = {
|
||||||
"operation": "delete-collection",
|
"operation": "delete-collection",
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,9 @@
|
||||||
|
"""
|
||||||
|
TrustGraph Configuration Management
|
||||||
|
|
||||||
|
This module provides interfaces for managing TrustGraph configuration settings,
|
||||||
|
including retrieving, updating, and deleting configuration values.
|
||||||
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
@ -7,14 +13,67 @@ from . types import ConfigValue
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
|
"""
|
||||||
|
Configuration management client.
|
||||||
|
|
||||||
|
Provides methods for managing TrustGraph configuration settings across
|
||||||
|
different types (llm, embedding, etc.), with support for get, put, delete,
|
||||||
|
and list operations.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, api):
|
def __init__(self, api):
|
||||||
|
"""
|
||||||
|
Initialize Config client.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
api: Parent Api instance for making requests
|
||||||
|
"""
|
||||||
self.api = api
|
self.api = api
|
||||||
|
|
||||||
def request(self, request):
|
def request(self, request):
|
||||||
|
"""
|
||||||
|
Make a configuration-scoped API request.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request: Request payload dictionary
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Response object
|
||||||
|
"""
|
||||||
return self.api.request("config", request)
|
return self.api.request("config", request)
|
||||||
|
|
||||||
def get(self, keys):
|
def get(self, keys):
|
||||||
|
"""
|
||||||
|
Get configuration values for specified keys.
|
||||||
|
|
||||||
|
Retrieves the configuration values for one or more configuration keys.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
keys: List of ConfigKey objects specifying which values to retrieve
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[ConfigValue]: List of configuration values
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ProtocolException: If response format is invalid
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
from trustgraph.api import ConfigKey
|
||||||
|
|
||||||
|
config = api.config()
|
||||||
|
|
||||||
|
# Get specific configuration values
|
||||||
|
values = config.get([
|
||||||
|
ConfigKey(type="llm", key="model"),
|
||||||
|
ConfigKey(type="llm", key="temperature"),
|
||||||
|
ConfigKey(type="embedding", key="model")
|
||||||
|
])
|
||||||
|
|
||||||
|
for val in values:
|
||||||
|
print(f"{val.type}.{val.key} = {val.value}")
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of system and prompt strings
|
# The input consists of system and prompt strings
|
||||||
input = {
|
input = {
|
||||||
|
|
@ -41,6 +100,28 @@ class Config:
|
||||||
raise ProtocolException("Response not formatted correctly")
|
raise ProtocolException("Response not formatted correctly")
|
||||||
|
|
||||||
def put(self, values):
|
def put(self, values):
|
||||||
|
"""
|
||||||
|
Set configuration values.
|
||||||
|
|
||||||
|
Updates or creates configuration values for the specified keys.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
values: List of ConfigValue objects with type, key, and value
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
from trustgraph.api import ConfigValue
|
||||||
|
|
||||||
|
config = api.config()
|
||||||
|
|
||||||
|
# Set configuration values
|
||||||
|
config.put([
|
||||||
|
ConfigValue(type="llm", key="model", value="gpt-4"),
|
||||||
|
ConfigValue(type="llm", key="temperature", value="0.7"),
|
||||||
|
ConfigValue(type="embedding", key="model", value="text-embedding-3-small")
|
||||||
|
])
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of system and prompt strings
|
# The input consists of system and prompt strings
|
||||||
input = {
|
input = {
|
||||||
|
|
@ -54,6 +135,27 @@ class Config:
|
||||||
self.request(input)
|
self.request(input)
|
||||||
|
|
||||||
def delete(self, keys):
|
def delete(self, keys):
|
||||||
|
"""
|
||||||
|
Delete configuration values.
|
||||||
|
|
||||||
|
Removes configuration values for the specified keys.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
keys: List of ConfigKey objects specifying which values to delete
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
from trustgraph.api import ConfigKey
|
||||||
|
|
||||||
|
config = api.config()
|
||||||
|
|
||||||
|
# Delete configuration values
|
||||||
|
config.delete([
|
||||||
|
ConfigKey(type="llm", key="old-setting"),
|
||||||
|
ConfigKey(type="embedding", key="deprecated")
|
||||||
|
])
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of system and prompt strings
|
# The input consists of system and prompt strings
|
||||||
input = {
|
input = {
|
||||||
|
|
@ -67,6 +169,31 @@ class Config:
|
||||||
self.request(input)
|
self.request(input)
|
||||||
|
|
||||||
def list(self, type):
|
def list(self, type):
|
||||||
|
"""
|
||||||
|
List all configuration keys for a given type.
|
||||||
|
|
||||||
|
Retrieves a list of all configuration key names within a specific
|
||||||
|
configuration type.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
type: Configuration type (e.g., "llm", "embedding", "storage")
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[str]: List of configuration key names
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
config = api.config()
|
||||||
|
|
||||||
|
# List all LLM configuration keys
|
||||||
|
llm_keys = config.list(type="llm")
|
||||||
|
print(f"LLM configuration keys: {llm_keys}")
|
||||||
|
|
||||||
|
# List all embedding configuration keys
|
||||||
|
embedding_keys = config.list(type="embedding")
|
||||||
|
print(f"Embedding configuration keys: {embedding_keys}")
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of system and prompt strings
|
# The input consists of system and prompt strings
|
||||||
input = {
|
input = {
|
||||||
|
|
@ -77,6 +204,36 @@ class Config:
|
||||||
return self.request(input)["directory"]
|
return self.request(input)["directory"]
|
||||||
|
|
||||||
def get_values(self, type):
|
def get_values(self, type):
|
||||||
|
"""
|
||||||
|
Get all configuration values for a given type.
|
||||||
|
|
||||||
|
Retrieves all configuration key-value pairs within a specific
|
||||||
|
configuration type.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
type: Configuration type (e.g., "llm", "embedding", "storage")
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[ConfigValue]: List of all configuration values for the type
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ProtocolException: If response format is invalid
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
config = api.config()
|
||||||
|
|
||||||
|
# Get all LLM configuration
|
||||||
|
llm_config = config.get_values(type="llm")
|
||||||
|
for val in llm_config:
|
||||||
|
print(f"{val.key} = {val.value}")
|
||||||
|
|
||||||
|
# Get all embedding configuration
|
||||||
|
embedding_config = config.get_values(type="embedding")
|
||||||
|
for val in embedding_config:
|
||||||
|
print(f"{val.key} = {val.value}")
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of system and prompt strings
|
# The input consists of system and prompt strings
|
||||||
input = {
|
input = {
|
||||||
|
|
@ -99,6 +256,28 @@ class Config:
|
||||||
raise ProtocolException(f"Response not formatted correctly")
|
raise ProtocolException(f"Response not formatted correctly")
|
||||||
|
|
||||||
def all(self):
|
def all(self):
|
||||||
|
"""
|
||||||
|
Get complete configuration and version.
|
||||||
|
|
||||||
|
Retrieves the entire configuration object along with its version number.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple: (config_dict, version_string) - Complete configuration and version
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ProtocolException: If response format is invalid
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
config = api.config()
|
||||||
|
|
||||||
|
# Get complete configuration
|
||||||
|
config_data, version = config.all()
|
||||||
|
|
||||||
|
print(f"Configuration version: {version}")
|
||||||
|
print(f"Configuration: {config_data}")
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of system and prompt strings
|
# The input consists of system and prompt strings
|
||||||
input = {
|
input = {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,10 @@
|
||||||
|
"""
|
||||||
|
TrustGraph Flow Management
|
||||||
|
|
||||||
|
This module provides interfaces for managing and executing TrustGraph flows.
|
||||||
|
Flows are the primary execution units that provide access to various services
|
||||||
|
including LLM operations, RAG queries, knowledge graph management, and more.
|
||||||
|
"""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import base64
|
import base64
|
||||||
|
|
@ -11,11 +18,38 @@ def to_value(x):
|
||||||
return Literal(x["v"])
|
return Literal(x["v"])
|
||||||
|
|
||||||
class Flow:
|
class Flow:
|
||||||
|
"""
|
||||||
|
Flow management client for blueprint and flow instance operations.
|
||||||
|
|
||||||
|
This class provides methods for managing flow blueprints (templates) and
|
||||||
|
flow instances (running flows). Blueprints define the structure and
|
||||||
|
parameters of flows, while instances represent active flows that can
|
||||||
|
execute services.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, api):
|
def __init__(self, api):
|
||||||
|
"""
|
||||||
|
Initialize Flow client.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
api: Parent Api instance for making requests
|
||||||
|
"""
|
||||||
self.api = api
|
self.api = api
|
||||||
|
|
||||||
def request(self, path=None, request=None):
|
def request(self, path=None, request=None):
|
||||||
|
"""
|
||||||
|
Make a flow-scoped API request.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path: Optional path suffix for flow endpoints
|
||||||
|
request: Request payload dictionary
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Response object
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
RuntimeError: If request parameter is not specified
|
||||||
|
"""
|
||||||
|
|
||||||
if request is None:
|
if request is None:
|
||||||
raise RuntimeError("request must be specified")
|
raise RuntimeError("request must be specified")
|
||||||
|
|
@ -26,9 +60,39 @@ class Flow:
|
||||||
return self.api.request(f"flow", request)
|
return self.api.request(f"flow", request)
|
||||||
|
|
||||||
def id(self, id="default"):
|
def id(self, id="default"):
|
||||||
|
"""
|
||||||
|
Get a FlowInstance for executing operations on a specific flow.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id: Flow identifier (default: "default")
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
FlowInstance: Flow instance for service operations
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
flow = api.flow().id("my-flow")
|
||||||
|
response = flow.text_completion(
|
||||||
|
system="You are helpful",
|
||||||
|
prompt="Hello"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
return FlowInstance(api=self, id=id)
|
return FlowInstance(api=self, id=id)
|
||||||
|
|
||||||
def list_blueprints(self):
|
def list_blueprints(self):
|
||||||
|
"""
|
||||||
|
List all available flow blueprints.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[str]: List of blueprint names
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
blueprints = api.flow().list_blueprints()
|
||||||
|
print(blueprints) # ['default', 'custom-flow', ...]
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of system and prompt strings
|
# The input consists of system and prompt strings
|
||||||
input = {
|
input = {
|
||||||
|
|
@ -38,6 +102,21 @@ class Flow:
|
||||||
return self.request(request = input)["blueprint-names"]
|
return self.request(request = input)["blueprint-names"]
|
||||||
|
|
||||||
def get_blueprint(self, blueprint_name):
|
def get_blueprint(self, blueprint_name):
|
||||||
|
"""
|
||||||
|
Get a flow blueprint definition by name.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
blueprint_name: Name of the blueprint to retrieve
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Blueprint definition as a dictionary
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
blueprint = api.flow().get_blueprint("default")
|
||||||
|
print(blueprint) # Blueprint configuration
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of system and prompt strings
|
# The input consists of system and prompt strings
|
||||||
input = {
|
input = {
|
||||||
|
|
@ -48,6 +127,22 @@ class Flow:
|
||||||
return json.loads(self.request(request = input)["blueprint-definition"])
|
return json.loads(self.request(request = input)["blueprint-definition"])
|
||||||
|
|
||||||
def put_blueprint(self, blueprint_name, definition):
|
def put_blueprint(self, blueprint_name, definition):
|
||||||
|
"""
|
||||||
|
Create or update a flow blueprint.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
blueprint_name: Name for the blueprint
|
||||||
|
definition: Blueprint definition dictionary
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
definition = {
|
||||||
|
"services": ["text-completion", "graph-rag"],
|
||||||
|
"parameters": {"model": "gpt-4"}
|
||||||
|
}
|
||||||
|
api.flow().put_blueprint("my-blueprint", definition)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of system and prompt strings
|
# The input consists of system and prompt strings
|
||||||
input = {
|
input = {
|
||||||
|
|
@ -59,6 +154,17 @@ class Flow:
|
||||||
self.request(request = input)
|
self.request(request = input)
|
||||||
|
|
||||||
def delete_blueprint(self, blueprint_name):
|
def delete_blueprint(self, blueprint_name):
|
||||||
|
"""
|
||||||
|
Delete a flow blueprint.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
blueprint_name: Name of the blueprint to delete
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
api.flow().delete_blueprint("old-blueprint")
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of system and prompt strings
|
# The input consists of system and prompt strings
|
||||||
input = {
|
input = {
|
||||||
|
|
@ -69,6 +175,18 @@ class Flow:
|
||||||
self.request(request = input)
|
self.request(request = input)
|
||||||
|
|
||||||
def list(self):
|
def list(self):
|
||||||
|
"""
|
||||||
|
List all active flow instances.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[str]: List of flow instance IDs
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
flows = api.flow().list()
|
||||||
|
print(flows) # ['default', 'flow-1', 'flow-2', ...]
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of system and prompt strings
|
# The input consists of system and prompt strings
|
||||||
input = {
|
input = {
|
||||||
|
|
@ -78,6 +196,21 @@ class Flow:
|
||||||
return self.request(request = input)["flow-ids"]
|
return self.request(request = input)["flow-ids"]
|
||||||
|
|
||||||
def get(self, id):
|
def get(self, id):
|
||||||
|
"""
|
||||||
|
Get the definition of a running flow instance.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id: Flow instance ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Flow instance definition
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
flow_def = api.flow().get("default")
|
||||||
|
print(flow_def)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of system and prompt strings
|
# The input consists of system and prompt strings
|
||||||
input = {
|
input = {
|
||||||
|
|
@ -88,6 +221,25 @@ class Flow:
|
||||||
return json.loads(self.request(request = input)["flow"])
|
return json.loads(self.request(request = input)["flow"])
|
||||||
|
|
||||||
def start(self, blueprint_name, id, description, parameters=None):
|
def start(self, blueprint_name, id, description, parameters=None):
|
||||||
|
"""
|
||||||
|
Start a new flow instance from a blueprint.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
blueprint_name: Name of the blueprint to instantiate
|
||||||
|
id: Unique identifier for the flow instance
|
||||||
|
description: Human-readable description
|
||||||
|
parameters: Optional parameters dictionary
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
api.flow().start(
|
||||||
|
blueprint_name="default",
|
||||||
|
id="my-flow",
|
||||||
|
description="My custom flow",
|
||||||
|
parameters={"model": "gpt-4"}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of system and prompt strings
|
# The input consists of system and prompt strings
|
||||||
input = {
|
input = {
|
||||||
|
|
@ -103,6 +255,17 @@ class Flow:
|
||||||
self.request(request = input)
|
self.request(request = input)
|
||||||
|
|
||||||
def stop(self, id):
|
def stop(self, id):
|
||||||
|
"""
|
||||||
|
Stop a running flow instance.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id: Flow instance ID to stop
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
api.flow().stop("my-flow")
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of system and prompt strings
|
# The input consists of system and prompt strings
|
||||||
input = {
|
input = {
|
||||||
|
|
@ -111,18 +274,70 @@ class Flow:
|
||||||
}
|
}
|
||||||
|
|
||||||
self.request(request = input)
|
self.request(request = input)
|
||||||
|
|
||||||
class FlowInstance:
|
class FlowInstance:
|
||||||
|
"""
|
||||||
|
Flow instance client for executing services on a specific flow.
|
||||||
|
|
||||||
|
This class provides access to all TrustGraph services including:
|
||||||
|
- Text completion and embeddings
|
||||||
|
- Agent operations with state management
|
||||||
|
- Graph and document RAG queries
|
||||||
|
- Knowledge graph operations (triples, objects)
|
||||||
|
- Document loading and processing
|
||||||
|
- Natural language to GraphQL query conversion
|
||||||
|
- Structured data analysis and schema detection
|
||||||
|
- MCP tool execution
|
||||||
|
- Prompt templating
|
||||||
|
|
||||||
|
Services are accessed through a running flow instance identified by ID.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, api, id):
|
def __init__(self, api, id):
|
||||||
|
"""
|
||||||
|
Initialize FlowInstance.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
api: Parent Flow client
|
||||||
|
id: Flow instance identifier
|
||||||
|
"""
|
||||||
self.api = api
|
self.api = api
|
||||||
self.id = id
|
self.id = id
|
||||||
|
|
||||||
def request(self, path, request):
|
def request(self, path, request):
|
||||||
|
"""
|
||||||
|
Make a service request on this flow instance.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path: Service path (e.g., "service/text-completion")
|
||||||
|
request: Request payload dictionary
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Service response
|
||||||
|
"""
|
||||||
return self.api.request(path = f"{self.id}/{path}", request = request)
|
return self.api.request(path = f"{self.id}/{path}", request = request)
|
||||||
|
|
||||||
def text_completion(self, system, prompt):
|
def text_completion(self, system, prompt):
|
||||||
|
"""
|
||||||
|
Execute text completion using the flow's LLM.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
system: System prompt defining the assistant's behavior
|
||||||
|
prompt: User prompt/question
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Generated response text
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
flow = api.flow().id("default")
|
||||||
|
response = flow.text_completion(
|
||||||
|
system="You are a helpful assistant",
|
||||||
|
prompt="What is quantum computing?"
|
||||||
|
)
|
||||||
|
print(response)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of system and prompt strings
|
# The input consists of system and prompt strings
|
||||||
input = {
|
input = {
|
||||||
|
|
@ -136,6 +351,44 @@ class FlowInstance:
|
||||||
)["response"]
|
)["response"]
|
||||||
|
|
||||||
def agent(self, question, user="trustgraph", state=None, group=None, history=None):
|
def agent(self, question, user="trustgraph", state=None, group=None, history=None):
|
||||||
|
"""
|
||||||
|
Execute an agent operation with reasoning and tool use capabilities.
|
||||||
|
|
||||||
|
Agents can perform multi-step reasoning, use tools, and maintain conversation
|
||||||
|
state across interactions. This is a synchronous non-streaming version.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
question: User question or instruction
|
||||||
|
user: User identifier (default: "trustgraph")
|
||||||
|
state: Optional state dictionary for stateful conversations
|
||||||
|
group: Optional group identifier for multi-user contexts
|
||||||
|
history: Optional conversation history as list of message dicts
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Agent's final answer
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
flow = api.flow().id("default")
|
||||||
|
|
||||||
|
# Simple question
|
||||||
|
answer = flow.agent(
|
||||||
|
question="What is the capital of France?",
|
||||||
|
user="trustgraph"
|
||||||
|
)
|
||||||
|
|
||||||
|
# With conversation history
|
||||||
|
history = [
|
||||||
|
{"role": "user", "content": "Hello"},
|
||||||
|
{"role": "assistant", "content": "Hi! How can I help?"}
|
||||||
|
]
|
||||||
|
answer = flow.agent(
|
||||||
|
question="Tell me about Paris",
|
||||||
|
user="trustgraph",
|
||||||
|
history=history
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of a question and optional context
|
# The input consists of a question and optional context
|
||||||
input = {
|
input = {
|
||||||
|
|
@ -164,6 +417,37 @@ class FlowInstance:
|
||||||
entity_limit=50, triple_limit=30, max_subgraph_size=150,
|
entity_limit=50, triple_limit=30, max_subgraph_size=150,
|
||||||
max_path_length=2,
|
max_path_length=2,
|
||||||
):
|
):
|
||||||
|
"""
|
||||||
|
Execute graph-based Retrieval-Augmented Generation (RAG) query.
|
||||||
|
|
||||||
|
Graph RAG uses knowledge graph structure to find relevant context by
|
||||||
|
traversing entity relationships, then generates a response using an LLM.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query: Natural language query
|
||||||
|
user: User/keyspace identifier (default: "trustgraph")
|
||||||
|
collection: Collection identifier (default: "default")
|
||||||
|
entity_limit: Maximum entities to retrieve (default: 50)
|
||||||
|
triple_limit: Maximum triples per entity (default: 30)
|
||||||
|
max_subgraph_size: Maximum total triples in subgraph (default: 150)
|
||||||
|
max_path_length: Maximum traversal depth (default: 2)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Generated response incorporating graph context
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
flow = api.flow().id("default")
|
||||||
|
response = flow.graph_rag(
|
||||||
|
query="Tell me about Marie Curie's discoveries",
|
||||||
|
user="trustgraph",
|
||||||
|
collection="scientists",
|
||||||
|
entity_limit=20,
|
||||||
|
max_path_length=3
|
||||||
|
)
|
||||||
|
print(response)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of a question
|
# The input consists of a question
|
||||||
input = {
|
input = {
|
||||||
|
|
@ -185,6 +469,33 @@ class FlowInstance:
|
||||||
self, query, user="trustgraph", collection="default",
|
self, query, user="trustgraph", collection="default",
|
||||||
doc_limit=10,
|
doc_limit=10,
|
||||||
):
|
):
|
||||||
|
"""
|
||||||
|
Execute document-based Retrieval-Augmented Generation (RAG) query.
|
||||||
|
|
||||||
|
Document RAG uses vector embeddings to find relevant document chunks,
|
||||||
|
then generates a response using an LLM with those chunks as context.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query: Natural language query
|
||||||
|
user: User/keyspace identifier (default: "trustgraph")
|
||||||
|
collection: Collection identifier (default: "default")
|
||||||
|
doc_limit: Maximum document chunks to retrieve (default: 10)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Generated response incorporating document context
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
flow = api.flow().id("default")
|
||||||
|
response = flow.document_rag(
|
||||||
|
query="Summarize the key findings",
|
||||||
|
user="trustgraph",
|
||||||
|
collection="research-papers",
|
||||||
|
doc_limit=5
|
||||||
|
)
|
||||||
|
print(response)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of a question
|
# The input consists of a question
|
||||||
input = {
|
input = {
|
||||||
|
|
@ -200,6 +511,25 @@ class FlowInstance:
|
||||||
)["response"]
|
)["response"]
|
||||||
|
|
||||||
def embeddings(self, text):
|
def embeddings(self, text):
|
||||||
|
"""
|
||||||
|
Generate vector embeddings for text.
|
||||||
|
|
||||||
|
Converts text into dense vector representations suitable for semantic
|
||||||
|
search and similarity comparison.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text: Input text to embed
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[float]: Vector embedding
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
flow = api.flow().id("default")
|
||||||
|
vectors = flow.embeddings("quantum computing")
|
||||||
|
print(f"Embedding dimension: {len(vectors)}")
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of a text block
|
# The input consists of a text block
|
||||||
input = {
|
input = {
|
||||||
|
|
@ -212,6 +542,32 @@ class FlowInstance:
|
||||||
)["vectors"]
|
)["vectors"]
|
||||||
|
|
||||||
def graph_embeddings_query(self, text, user, collection, limit=10):
|
def graph_embeddings_query(self, text, user, collection, limit=10):
|
||||||
|
"""
|
||||||
|
Query knowledge graph entities using semantic similarity.
|
||||||
|
|
||||||
|
Finds entities in the knowledge graph whose descriptions are semantically
|
||||||
|
similar to the input text, using vector embeddings.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text: Query text for semantic search
|
||||||
|
user: User/keyspace identifier
|
||||||
|
collection: Collection identifier
|
||||||
|
limit: Maximum number of results (default: 10)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Query results with similar entities
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
flow = api.flow().id("default")
|
||||||
|
results = flow.graph_embeddings_query(
|
||||||
|
text="physicist who discovered radioactivity",
|
||||||
|
user="trustgraph",
|
||||||
|
collection="scientists",
|
||||||
|
limit=5
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# Query graph embeddings for semantic search
|
# Query graph embeddings for semantic search
|
||||||
input = {
|
input = {
|
||||||
|
|
@ -227,6 +583,39 @@ class FlowInstance:
|
||||||
)
|
)
|
||||||
|
|
||||||
def prompt(self, id, variables):
|
def prompt(self, id, variables):
|
||||||
|
"""
|
||||||
|
Execute a prompt template with variable substitution.
|
||||||
|
|
||||||
|
Prompt templates allow reusable prompt patterns with dynamic variable
|
||||||
|
substitution, useful for consistent prompt engineering.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id: Prompt template identifier
|
||||||
|
variables: Dictionary of variable name to value mappings
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str or dict: Rendered prompt result (text or structured object)
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ProtocolException: If response format is invalid
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
flow = api.flow().id("default")
|
||||||
|
|
||||||
|
# Text template
|
||||||
|
result = flow.prompt(
|
||||||
|
id="summarize-template",
|
||||||
|
variables={"topic": "quantum computing", "length": "brief"}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Structured template
|
||||||
|
result = flow.prompt(
|
||||||
|
id="extract-entities",
|
||||||
|
variables={"text": "Marie Curie won Nobel Prizes"}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
input = {
|
input = {
|
||||||
"id": id,
|
"id": id,
|
||||||
|
|
@ -252,6 +641,33 @@ class FlowInstance:
|
||||||
raise ProtocolException("Response not formatted correctly")
|
raise ProtocolException("Response not formatted correctly")
|
||||||
|
|
||||||
def mcp_tool(self, name, parameters={}):
|
def mcp_tool(self, name, parameters={}):
|
||||||
|
"""
|
||||||
|
Execute a Model Context Protocol (MCP) tool.
|
||||||
|
|
||||||
|
MCP tools provide extensible functionality for agents and workflows,
|
||||||
|
allowing integration with external systems and services.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: Tool name/identifier
|
||||||
|
parameters: Tool parameters dictionary (default: {})
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str or dict: Tool execution result
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ProtocolException: If response format is invalid
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
flow = api.flow().id("default")
|
||||||
|
|
||||||
|
# Execute a tool
|
||||||
|
result = flow.mcp_tool(
|
||||||
|
name="search-web",
|
||||||
|
parameters={"query": "latest AI news", "limit": 5}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of name and parameters
|
# The input consists of name and parameters
|
||||||
input = {
|
input = {
|
||||||
|
|
@ -281,6 +697,46 @@ class FlowInstance:
|
||||||
self, s=None, p=None, o=None,
|
self, s=None, p=None, o=None,
|
||||||
user=None, collection=None, limit=10000
|
user=None, collection=None, limit=10000
|
||||||
):
|
):
|
||||||
|
"""
|
||||||
|
Query knowledge graph triples using pattern matching.
|
||||||
|
|
||||||
|
Searches for RDF triples matching the given subject, predicate, and/or
|
||||||
|
object patterns. Unspecified parameters act as wildcards.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
s: Subject URI (optional, use None for wildcard)
|
||||||
|
p: Predicate URI (optional, use None for wildcard)
|
||||||
|
o: Object URI or Literal (optional, use None for wildcard)
|
||||||
|
user: User/keyspace identifier (optional)
|
||||||
|
collection: Collection identifier (optional)
|
||||||
|
limit: Maximum results to return (default: 10000)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[Triple]: List of matching Triple objects
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
RuntimeError: If s or p is not a Uri, or o is not Uri/Literal
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
from trustgraph.knowledge import Uri, Literal
|
||||||
|
|
||||||
|
flow = api.flow().id("default")
|
||||||
|
|
||||||
|
# Find all triples about a specific subject
|
||||||
|
triples = flow.triples_query(
|
||||||
|
s=Uri("http://example.org/person/marie-curie"),
|
||||||
|
user="trustgraph",
|
||||||
|
collection="scientists"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Find all instances of a specific relationship
|
||||||
|
triples = flow.triples_query(
|
||||||
|
p=Uri("http://example.org/ontology/discovered"),
|
||||||
|
limit=100
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
input = {
|
input = {
|
||||||
"limit": limit
|
"limit": limit
|
||||||
|
|
@ -325,6 +781,39 @@ class FlowInstance:
|
||||||
self, document, id=None, metadata=None, user=None,
|
self, document, id=None, metadata=None, user=None,
|
||||||
collection=None,
|
collection=None,
|
||||||
):
|
):
|
||||||
|
"""
|
||||||
|
Load a binary document for processing.
|
||||||
|
|
||||||
|
Uploads a document (PDF, DOCX, images, etc.) for extraction and
|
||||||
|
processing through the flow's document pipeline.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
document: Document content as bytes
|
||||||
|
id: Optional document identifier (auto-generated if None)
|
||||||
|
metadata: Optional metadata (list of Triples or object with emit method)
|
||||||
|
user: User/keyspace identifier (optional)
|
||||||
|
collection: Collection identifier (optional)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Processing response
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
RuntimeError: If metadata is provided without id
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
flow = api.flow().id("default")
|
||||||
|
|
||||||
|
# Load a PDF document
|
||||||
|
with open("research.pdf", "rb") as f:
|
||||||
|
result = flow.load_document(
|
||||||
|
document=f.read(),
|
||||||
|
id="research-001",
|
||||||
|
user="trustgraph",
|
||||||
|
collection="papers"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
if id is None:
|
if id is None:
|
||||||
|
|
||||||
|
|
@ -372,6 +861,41 @@ class FlowInstance:
|
||||||
self, text, id=None, metadata=None, charset="utf-8",
|
self, text, id=None, metadata=None, charset="utf-8",
|
||||||
user=None, collection=None,
|
user=None, collection=None,
|
||||||
):
|
):
|
||||||
|
"""
|
||||||
|
Load text content for processing.
|
||||||
|
|
||||||
|
Uploads text content for extraction and processing through the flow's
|
||||||
|
text pipeline.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text: Text content as bytes
|
||||||
|
id: Optional document identifier (auto-generated if None)
|
||||||
|
metadata: Optional metadata (list of Triples or object with emit method)
|
||||||
|
charset: Character encoding (default: "utf-8")
|
||||||
|
user: User/keyspace identifier (optional)
|
||||||
|
collection: Collection identifier (optional)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Processing response
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
RuntimeError: If metadata is provided without id
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
flow = api.flow().id("default")
|
||||||
|
|
||||||
|
# Load text content
|
||||||
|
text_content = b"This is the document content..."
|
||||||
|
result = flow.load_text(
|
||||||
|
text=text_content,
|
||||||
|
id="text-001",
|
||||||
|
charset="utf-8",
|
||||||
|
user="trustgraph",
|
||||||
|
collection="documents"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
if id is None:
|
if id is None:
|
||||||
|
|
||||||
|
|
@ -417,6 +941,60 @@ class FlowInstance:
|
||||||
self, query, user="trustgraph", collection="default",
|
self, query, user="trustgraph", collection="default",
|
||||||
variables=None, operation_name=None
|
variables=None, operation_name=None
|
||||||
):
|
):
|
||||||
|
"""
|
||||||
|
Execute a GraphQL query against structured objects in the knowledge graph.
|
||||||
|
|
||||||
|
Queries structured data using GraphQL syntax, allowing complex queries
|
||||||
|
with filtering, aggregation, and relationship traversal.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query: GraphQL query string
|
||||||
|
user: User/keyspace identifier (default: "trustgraph")
|
||||||
|
collection: Collection identifier (default: "default")
|
||||||
|
variables: Optional query variables dictionary
|
||||||
|
operation_name: Optional operation name for multi-operation documents
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: GraphQL response with 'data', 'errors', and/or 'extensions' fields
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ProtocolException: If system-level error occurs
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
flow = api.flow().id("default")
|
||||||
|
|
||||||
|
# Simple query
|
||||||
|
query = '''
|
||||||
|
{
|
||||||
|
scientists(limit: 10) {
|
||||||
|
name
|
||||||
|
field
|
||||||
|
discoveries
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
result = flow.objects_query(
|
||||||
|
query=query,
|
||||||
|
user="trustgraph",
|
||||||
|
collection="scientists"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Query with variables
|
||||||
|
query = '''
|
||||||
|
query GetScientist($name: String!) {
|
||||||
|
scientists(name: $name) {
|
||||||
|
name
|
||||||
|
nobelPrizes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
result = flow.objects_query(
|
||||||
|
query=query,
|
||||||
|
variables={"name": "Marie Curie"}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of a GraphQL query and optional variables
|
# The input consists of a GraphQL query and optional variables
|
||||||
input = {
|
input = {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,10 @@
|
||||||
|
"""
|
||||||
|
TrustGraph Knowledge Graph Core Management
|
||||||
|
|
||||||
|
This module provides interfaces for managing knowledge graph cores in TrustGraph.
|
||||||
|
KG cores are pre-built knowledge graph datasets that can be loaded and unloaded
|
||||||
|
into flows for use in queries and RAG operations.
|
||||||
|
"""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import base64
|
import base64
|
||||||
|
|
@ -10,15 +17,56 @@ def to_value(x):
|
||||||
return Literal(x["v"])
|
return Literal(x["v"])
|
||||||
|
|
||||||
class Knowledge:
|
class Knowledge:
|
||||||
|
"""
|
||||||
|
Knowledge graph core management client.
|
||||||
|
|
||||||
|
Provides methods for managing knowledge graph cores, including listing
|
||||||
|
available cores, loading them into flows, and unloading them. KG cores
|
||||||
|
are pre-built knowledge graph datasets that enhance RAG capabilities.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, api):
|
def __init__(self, api):
|
||||||
|
"""
|
||||||
|
Initialize Knowledge client.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
api: Parent Api instance for making requests
|
||||||
|
"""
|
||||||
self.api = api
|
self.api = api
|
||||||
|
|
||||||
def request(self, request):
|
def request(self, request):
|
||||||
|
"""
|
||||||
|
Make a knowledge-scoped API request.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request: Request payload dictionary
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Response object
|
||||||
|
"""
|
||||||
return self.api.request(f"knowledge", request)
|
return self.api.request(f"knowledge", request)
|
||||||
|
|
||||||
def list_kg_cores(self, user="trustgraph"):
|
def list_kg_cores(self, user="trustgraph"):
|
||||||
|
"""
|
||||||
|
List all available knowledge graph cores.
|
||||||
|
|
||||||
|
Retrieves the IDs of all KG cores available for the specified user.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user: User identifier (default: "trustgraph")
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[str]: List of KG core identifiers
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
knowledge = api.knowledge()
|
||||||
|
|
||||||
|
# List available KG cores
|
||||||
|
cores = knowledge.list_kg_cores(user="trustgraph")
|
||||||
|
print(f"Available KG cores: {cores}")
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of system and prompt strings
|
# The input consists of system and prompt strings
|
||||||
input = {
|
input = {
|
||||||
|
|
@ -29,6 +77,24 @@ class Knowledge:
|
||||||
return self.request(request = input)["ids"]
|
return self.request(request = input)["ids"]
|
||||||
|
|
||||||
def delete_kg_core(self, id, user="trustgraph"):
|
def delete_kg_core(self, id, user="trustgraph"):
|
||||||
|
"""
|
||||||
|
Delete a knowledge graph core.
|
||||||
|
|
||||||
|
Removes a KG core from storage. This does not affect currently loaded
|
||||||
|
cores in flows.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id: KG core identifier to delete
|
||||||
|
user: User identifier (default: "trustgraph")
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
knowledge = api.knowledge()
|
||||||
|
|
||||||
|
# Delete a KG core
|
||||||
|
knowledge.delete_kg_core(id="medical-kb-v1", user="trustgraph")
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of system and prompt strings
|
# The input consists of system and prompt strings
|
||||||
input = {
|
input = {
|
||||||
|
|
@ -41,6 +107,39 @@ class Knowledge:
|
||||||
|
|
||||||
def load_kg_core(self, id, user="trustgraph", flow="default",
|
def load_kg_core(self, id, user="trustgraph", flow="default",
|
||||||
collection="default"):
|
collection="default"):
|
||||||
|
"""
|
||||||
|
Load a knowledge graph core into a flow.
|
||||||
|
|
||||||
|
Makes a KG core available for use in queries and RAG operations within
|
||||||
|
the specified flow and collection.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id: KG core identifier to load
|
||||||
|
user: User identifier (default: "trustgraph")
|
||||||
|
flow: Flow instance to load into (default: "default")
|
||||||
|
collection: Collection to associate with (default: "default")
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
knowledge = api.knowledge()
|
||||||
|
|
||||||
|
# Load a medical knowledge base into the default flow
|
||||||
|
knowledge.load_kg_core(
|
||||||
|
id="medical-kb-v1",
|
||||||
|
user="trustgraph",
|
||||||
|
flow="default",
|
||||||
|
collection="medical"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Now the flow can use this KG core for RAG queries
|
||||||
|
flow = api.flow().id("default")
|
||||||
|
response = flow.graph_rag(
|
||||||
|
query="What are the symptoms of diabetes?",
|
||||||
|
user="trustgraph",
|
||||||
|
collection="medical"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of system and prompt strings
|
# The input consists of system and prompt strings
|
||||||
input = {
|
input = {
|
||||||
|
|
@ -54,6 +153,29 @@ class Knowledge:
|
||||||
self.request(request = input)
|
self.request(request = input)
|
||||||
|
|
||||||
def unload_kg_core(self, id, user="trustgraph", flow="default"):
|
def unload_kg_core(self, id, user="trustgraph", flow="default"):
|
||||||
|
"""
|
||||||
|
Unload a knowledge graph core from a flow.
|
||||||
|
|
||||||
|
Removes a KG core from active use in the specified flow, freeing
|
||||||
|
resources while keeping the core available in storage.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id: KG core identifier to unload
|
||||||
|
user: User identifier (default: "trustgraph")
|
||||||
|
flow: Flow instance to unload from (default: "default")
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
knowledge = api.knowledge()
|
||||||
|
|
||||||
|
# Unload a KG core when no longer needed
|
||||||
|
knowledge.unload_kg_core(
|
||||||
|
id="medical-kb-v1",
|
||||||
|
user="trustgraph",
|
||||||
|
flow="default"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
# The input consists of system and prompt strings
|
# The input consists of system and prompt strings
|
||||||
input = {
|
input = {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,9 @@
|
||||||
|
"""
|
||||||
|
TrustGraph Document Library Management
|
||||||
|
|
||||||
|
This module provides interfaces for managing documents in the TrustGraph library,
|
||||||
|
including document storage, metadata management, and processing workflow coordination.
|
||||||
|
"""
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import time
|
import time
|
||||||
|
|
@ -15,17 +21,79 @@ def to_value(x):
|
||||||
return Literal(x["v"])
|
return Literal(x["v"])
|
||||||
|
|
||||||
class Library:
|
class Library:
|
||||||
|
"""
|
||||||
|
Document library management client.
|
||||||
|
|
||||||
|
Provides methods for managing documents in the TrustGraph library, including
|
||||||
|
adding, retrieving, updating, and removing documents, as well as managing
|
||||||
|
document processing workflows.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, api):
|
def __init__(self, api):
|
||||||
|
"""
|
||||||
|
Initialize Library client.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
api: Parent Api instance for making requests
|
||||||
|
"""
|
||||||
self.api = api
|
self.api = api
|
||||||
|
|
||||||
def request(self, request):
|
def request(self, request):
|
||||||
|
"""
|
||||||
|
Make a library-scoped API request.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request: Request payload dictionary
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Response object
|
||||||
|
"""
|
||||||
return self.api.request(f"librarian", request)
|
return self.api.request(f"librarian", request)
|
||||||
|
|
||||||
def add_document(
|
def add_document(
|
||||||
self, document, id, metadata, user, title, comments,
|
self, document, id, metadata, user, title, comments,
|
||||||
kind="text/plain", tags=[],
|
kind="text/plain", tags=[],
|
||||||
):
|
):
|
||||||
|
"""
|
||||||
|
Add a document to the library.
|
||||||
|
|
||||||
|
Stores a document with associated metadata in the library for
|
||||||
|
retrieval and processing.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
document: Document content as bytes
|
||||||
|
id: Document identifier (auto-generated if None)
|
||||||
|
metadata: Document metadata as list of Triple objects or object with emit method
|
||||||
|
user: User/owner identifier
|
||||||
|
title: Document title
|
||||||
|
comments: Document description or comments
|
||||||
|
kind: MIME type of the document (default: "text/plain")
|
||||||
|
tags: List of tags for categorization (default: [])
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Response from the add operation
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
RuntimeError: If metadata is provided without an id
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
library = api.library()
|
||||||
|
|
||||||
|
# Add a PDF document
|
||||||
|
with open("research.pdf", "rb") as f:
|
||||||
|
library.add_document(
|
||||||
|
document=f.read(),
|
||||||
|
id="research-001",
|
||||||
|
metadata=[],
|
||||||
|
user="trustgraph",
|
||||||
|
title="Research Paper",
|
||||||
|
comments="Key findings in quantum computing",
|
||||||
|
kind="application/pdf",
|
||||||
|
tags=["research", "physics"]
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
if id is None:
|
if id is None:
|
||||||
|
|
||||||
|
|
@ -85,6 +153,31 @@ class Library:
|
||||||
return self.request(input)
|
return self.request(input)
|
||||||
|
|
||||||
def get_documents(self, user):
|
def get_documents(self, user):
|
||||||
|
"""
|
||||||
|
List all documents for a user.
|
||||||
|
|
||||||
|
Retrieves metadata for all documents owned by the specified user.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user: User identifier
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[DocumentMetadata]: List of document metadata objects
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ProtocolException: If response format is invalid
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
library = api.library()
|
||||||
|
docs = library.get_documents(user="trustgraph")
|
||||||
|
|
||||||
|
for doc in docs:
|
||||||
|
print(f"{doc.id}: {doc.title} ({doc.kind})")
|
||||||
|
print(f" Uploaded: {doc.time}")
|
||||||
|
print(f" Tags: {', '.join(doc.tags)}")
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
input = {
|
input = {
|
||||||
"operation": "list-documents",
|
"operation": "list-documents",
|
||||||
|
|
@ -119,6 +212,29 @@ class Library:
|
||||||
raise ProtocolException(f"Response not formatted correctly")
|
raise ProtocolException(f"Response not formatted correctly")
|
||||||
|
|
||||||
def get_document(self, user, id):
|
def get_document(self, user, id):
|
||||||
|
"""
|
||||||
|
Get metadata for a specific document.
|
||||||
|
|
||||||
|
Retrieves the metadata for a single document by ID.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user: User identifier
|
||||||
|
id: Document identifier
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
DocumentMetadata: Document metadata object
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ProtocolException: If response format is invalid
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
library = api.library()
|
||||||
|
doc = library.get_document(user="trustgraph", id="doc-123")
|
||||||
|
print(f"Title: {doc.title}")
|
||||||
|
print(f"Comments: {doc.comments}")
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
input = {
|
input = {
|
||||||
"operation": "get-document",
|
"operation": "get-document",
|
||||||
|
|
@ -152,6 +268,42 @@ class Library:
|
||||||
raise ProtocolException(f"Response not formatted correctly")
|
raise ProtocolException(f"Response not formatted correctly")
|
||||||
|
|
||||||
def update_document(self, user, id, metadata):
|
def update_document(self, user, id, metadata):
|
||||||
|
"""
|
||||||
|
Update document metadata.
|
||||||
|
|
||||||
|
Updates the metadata for an existing document in the library.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user: User identifier
|
||||||
|
id: Document identifier
|
||||||
|
metadata: Updated DocumentMetadata object
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
DocumentMetadata: Updated document metadata
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ProtocolException: If response format is invalid
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
library = api.library()
|
||||||
|
|
||||||
|
# Get existing document
|
||||||
|
doc = library.get_document(user="trustgraph", id="doc-123")
|
||||||
|
|
||||||
|
# Update metadata
|
||||||
|
doc.title = "Updated Title"
|
||||||
|
doc.comments = "Updated description"
|
||||||
|
doc.tags.append("reviewed")
|
||||||
|
|
||||||
|
# Save changes
|
||||||
|
updated_doc = library.update_document(
|
||||||
|
user="trustgraph",
|
||||||
|
id="doc-123",
|
||||||
|
metadata=doc
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
input = {
|
input = {
|
||||||
"operation": "update-document",
|
"operation": "update-document",
|
||||||
|
|
@ -199,6 +351,24 @@ class Library:
|
||||||
raise ProtocolException(f"Response not formatted correctly")
|
raise ProtocolException(f"Response not formatted correctly")
|
||||||
|
|
||||||
def remove_document(self, user, id):
|
def remove_document(self, user, id):
|
||||||
|
"""
|
||||||
|
Remove a document from the library.
|
||||||
|
|
||||||
|
Deletes a document and its metadata from the library.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user: User identifier
|
||||||
|
id: Document identifier to remove
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Empty response object
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
library = api.library()
|
||||||
|
library.remove_document(user="trustgraph", id="doc-123")
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
input = {
|
input = {
|
||||||
"operation": "remove-document",
|
"operation": "remove-document",
|
||||||
|
|
@ -214,6 +384,38 @@ class Library:
|
||||||
self, id, document_id, flow="default",
|
self, id, document_id, flow="default",
|
||||||
user="trustgraph", collection="default", tags=[],
|
user="trustgraph", collection="default", tags=[],
|
||||||
):
|
):
|
||||||
|
"""
|
||||||
|
Start a document processing workflow.
|
||||||
|
|
||||||
|
Initiates processing of a document through a specified flow, tracking
|
||||||
|
the processing job with metadata.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id: Unique processing job identifier
|
||||||
|
document_id: ID of the document to process
|
||||||
|
flow: Flow instance to use for processing (default: "default")
|
||||||
|
user: User identifier (default: "trustgraph")
|
||||||
|
collection: Target collection for processed data (default: "default")
|
||||||
|
tags: List of tags for the processing job (default: [])
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Empty response object
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
library = api.library()
|
||||||
|
|
||||||
|
# Start processing a document
|
||||||
|
library.start_processing(
|
||||||
|
id="proc-001",
|
||||||
|
document_id="doc-123",
|
||||||
|
flow="default",
|
||||||
|
user="trustgraph",
|
||||||
|
collection="research",
|
||||||
|
tags=["automated", "extract"]
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
input = {
|
input = {
|
||||||
"operation": "add-processing",
|
"operation": "add-processing",
|
||||||
|
|
@ -233,8 +435,26 @@ class Library:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def stop_processing(
|
def stop_processing(
|
||||||
self, id, user="trustgraph",
|
self, id, user="trustgraph",
|
||||||
):
|
):
|
||||||
|
"""
|
||||||
|
Stop a running document processing job.
|
||||||
|
|
||||||
|
Terminates an active document processing workflow and removes its metadata.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id: Processing job identifier to stop
|
||||||
|
user: User identifier (default: "trustgraph")
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Empty response object
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
library = api.library()
|
||||||
|
library.stop_processing(id="proc-001", user="trustgraph")
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
input = {
|
input = {
|
||||||
"operation": "remove-processing",
|
"operation": "remove-processing",
|
||||||
|
|
@ -247,6 +467,34 @@ class Library:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def get_processings(self, user="trustgraph"):
|
def get_processings(self, user="trustgraph"):
|
||||||
|
"""
|
||||||
|
List all active document processing jobs.
|
||||||
|
|
||||||
|
Retrieves metadata for all currently running document processing workflows
|
||||||
|
for the specified user.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user: User identifier (default: "trustgraph")
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[ProcessingMetadata]: List of processing job metadata objects
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ProtocolException: If response format is invalid
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
library = api.library()
|
||||||
|
jobs = library.get_processings(user="trustgraph")
|
||||||
|
|
||||||
|
for job in jobs:
|
||||||
|
print(f"Job {job.id}:")
|
||||||
|
print(f" Document: {job.document_id}")
|
||||||
|
print(f" Flow: {job.flow}")
|
||||||
|
print(f" Collection: {job.collection}")
|
||||||
|
print(f" Started: {job.time}")
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
input = {
|
input = {
|
||||||
"operation": "list-processing",
|
"operation": "list-processing",
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,9 @@
|
||||||
|
"""
|
||||||
|
TrustGraph Synchronous WebSocket Client
|
||||||
|
|
||||||
|
This module provides synchronous WebSocket-based access to TrustGraph services with
|
||||||
|
streaming support for real-time responses from agents, RAG queries, and text completions.
|
||||||
|
"""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
@ -10,9 +16,26 @@ from . exceptions import ProtocolException, raise_from_error_dict
|
||||||
|
|
||||||
|
|
||||||
class SocketClient:
|
class SocketClient:
|
||||||
"""Synchronous WebSocket client (wraps async websockets library)"""
|
"""
|
||||||
|
Synchronous WebSocket client for streaming operations.
|
||||||
|
|
||||||
|
Provides a synchronous interface to WebSocket-based TrustGraph services,
|
||||||
|
wrapping async websockets library with synchronous generators for ease of use.
|
||||||
|
Supports streaming responses from agents, RAG queries, and text completions.
|
||||||
|
|
||||||
|
Note: This is a synchronous wrapper around async WebSocket operations. For
|
||||||
|
true async support, use AsyncSocketClient instead.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, url: str, timeout: int, token: Optional[str]) -> None:
|
def __init__(self, url: str, timeout: int, token: Optional[str]) -> None:
|
||||||
|
"""
|
||||||
|
Initialize synchronous WebSocket client.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
url: Base URL for TrustGraph API (HTTP/HTTPS will be converted to WS/WSS)
|
||||||
|
timeout: WebSocket timeout in seconds
|
||||||
|
token: Optional bearer token for authentication
|
||||||
|
"""
|
||||||
self.url: str = self._convert_to_ws_url(url)
|
self.url: str = self._convert_to_ws_url(url)
|
||||||
self.timeout: int = timeout
|
self.timeout: int = timeout
|
||||||
self.token: Optional[str] = token
|
self.token: Optional[str] = token
|
||||||
|
|
@ -22,7 +45,15 @@ class SocketClient:
|
||||||
self._loop: Optional[asyncio.AbstractEventLoop] = None
|
self._loop: Optional[asyncio.AbstractEventLoop] = None
|
||||||
|
|
||||||
def _convert_to_ws_url(self, url: str) -> str:
|
def _convert_to_ws_url(self, url: str) -> str:
|
||||||
"""Convert HTTP URL to WebSocket URL"""
|
"""
|
||||||
|
Convert HTTP URL to WebSocket URL.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
url: HTTP/HTTPS or WS/WSS URL
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: WebSocket URL (ws:// or wss://)
|
||||||
|
"""
|
||||||
if url.startswith("http://"):
|
if url.startswith("http://"):
|
||||||
return url.replace("http://", "ws://", 1)
|
return url.replace("http://", "ws://", 1)
|
||||||
elif url.startswith("https://"):
|
elif url.startswith("https://"):
|
||||||
|
|
@ -34,7 +65,25 @@ class SocketClient:
|
||||||
return f"ws://{url}"
|
return f"ws://{url}"
|
||||||
|
|
||||||
def flow(self, flow_id: str) -> "SocketFlowInstance":
|
def flow(self, flow_id: str) -> "SocketFlowInstance":
|
||||||
"""Get flow instance for WebSocket operations"""
|
"""
|
||||||
|
Get a flow instance for WebSocket streaming operations.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
flow_id: Flow identifier
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
SocketFlowInstance: Flow instance with streaming methods
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
socket = api.socket()
|
||||||
|
flow = socket.flow("default")
|
||||||
|
|
||||||
|
# Stream agent responses
|
||||||
|
for chunk in flow.agent(question="Hello", user="trustgraph", streaming=True):
|
||||||
|
print(chunk.content, end='', flush=True)
|
||||||
|
```
|
||||||
|
"""
|
||||||
return SocketFlowInstance(self, flow_id)
|
return SocketFlowInstance(self, flow_id)
|
||||||
|
|
||||||
def _send_request_sync(
|
def _send_request_sync(
|
||||||
|
|
@ -242,15 +291,32 @@ class SocketClient:
|
||||||
)
|
)
|
||||||
|
|
||||||
def close(self) -> None:
|
def close(self) -> None:
|
||||||
"""Close WebSocket connection"""
|
"""
|
||||||
|
Close WebSocket connections.
|
||||||
|
|
||||||
|
Note: Cleanup is handled automatically by context managers in async code.
|
||||||
|
"""
|
||||||
# Cleanup handled by context manager in async code
|
# Cleanup handled by context manager in async code
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class SocketFlowInstance:
|
class SocketFlowInstance:
|
||||||
"""Synchronous WebSocket flow instance with same interface as REST FlowInstance"""
|
"""
|
||||||
|
Synchronous WebSocket flow instance for streaming operations.
|
||||||
|
|
||||||
|
Provides the same interface as REST FlowInstance but with WebSocket-based
|
||||||
|
streaming support for real-time responses. All methods support an optional
|
||||||
|
`streaming` parameter to enable incremental result delivery.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, client: SocketClient, flow_id: str) -> None:
|
def __init__(self, client: SocketClient, flow_id: str) -> None:
|
||||||
|
"""
|
||||||
|
Initialize socket flow instance.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
client: Parent SocketClient
|
||||||
|
flow_id: Flow identifier
|
||||||
|
"""
|
||||||
self.client: SocketClient = client
|
self.client: SocketClient = client
|
||||||
self.flow_id: str = flow_id
|
self.flow_id: str = flow_id
|
||||||
|
|
||||||
|
|
@ -264,7 +330,44 @@ class SocketFlowInstance:
|
||||||
streaming: bool = False,
|
streaming: bool = False,
|
||||||
**kwargs: Any
|
**kwargs: Any
|
||||||
) -> Union[Dict[str, Any], Iterator[StreamingChunk]]:
|
) -> Union[Dict[str, Any], Iterator[StreamingChunk]]:
|
||||||
"""Agent with optional streaming"""
|
"""
|
||||||
|
Execute an agent operation with streaming support.
|
||||||
|
|
||||||
|
Agents can perform multi-step reasoning with tool use. This method always
|
||||||
|
returns streaming chunks (thoughts, observations, answers) even when
|
||||||
|
streaming=False, to show the agent's reasoning process.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
question: User question or instruction
|
||||||
|
user: User identifier
|
||||||
|
state: Optional state dictionary for stateful conversations
|
||||||
|
group: Optional group identifier for multi-user contexts
|
||||||
|
history: Optional conversation history as list of message dicts
|
||||||
|
streaming: Enable streaming mode (default: False)
|
||||||
|
**kwargs: Additional parameters passed to the agent service
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Iterator[StreamingChunk]: Stream of agent thoughts, observations, and answers
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
socket = api.socket()
|
||||||
|
flow = socket.flow("default")
|
||||||
|
|
||||||
|
# Stream agent reasoning
|
||||||
|
for chunk in flow.agent(
|
||||||
|
question="What is quantum computing?",
|
||||||
|
user="trustgraph",
|
||||||
|
streaming=True
|
||||||
|
):
|
||||||
|
if isinstance(chunk, AgentThought):
|
||||||
|
print(f"[Thinking] {chunk.content}")
|
||||||
|
elif isinstance(chunk, AgentObservation):
|
||||||
|
print(f"[Observation] {chunk.content}")
|
||||||
|
elif isinstance(chunk, AgentAnswer):
|
||||||
|
print(f"[Answer] {chunk.content}")
|
||||||
|
```
|
||||||
|
"""
|
||||||
request = {
|
request = {
|
||||||
"question": question,
|
"question": question,
|
||||||
"user": user,
|
"user": user,
|
||||||
|
|
@ -283,7 +386,40 @@ class SocketFlowInstance:
|
||||||
return self.client._send_request_sync("agent", self.flow_id, request, streaming=True)
|
return self.client._send_request_sync("agent", self.flow_id, request, streaming=True)
|
||||||
|
|
||||||
def text_completion(self, system: str, prompt: str, streaming: bool = False, **kwargs) -> Union[str, Iterator[str]]:
|
def text_completion(self, system: str, prompt: str, streaming: bool = False, **kwargs) -> Union[str, Iterator[str]]:
|
||||||
"""Text completion with optional streaming"""
|
"""
|
||||||
|
Execute text completion with optional streaming.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
system: System prompt defining the assistant's behavior
|
||||||
|
prompt: User prompt/question
|
||||||
|
streaming: Enable streaming mode (default: False)
|
||||||
|
**kwargs: Additional parameters passed to the service
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Union[str, Iterator[str]]: Complete response or stream of text chunks
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
socket = api.socket()
|
||||||
|
flow = socket.flow("default")
|
||||||
|
|
||||||
|
# Non-streaming
|
||||||
|
response = flow.text_completion(
|
||||||
|
system="You are helpful",
|
||||||
|
prompt="Explain quantum computing",
|
||||||
|
streaming=False
|
||||||
|
)
|
||||||
|
print(response)
|
||||||
|
|
||||||
|
# Streaming
|
||||||
|
for chunk in flow.text_completion(
|
||||||
|
system="You are helpful",
|
||||||
|
prompt="Explain quantum computing",
|
||||||
|
streaming=True
|
||||||
|
):
|
||||||
|
print(chunk, end='', flush=True)
|
||||||
|
```
|
||||||
|
"""
|
||||||
request = {
|
request = {
|
||||||
"system": system,
|
"system": system,
|
||||||
"prompt": prompt,
|
"prompt": prompt,
|
||||||
|
|
@ -316,7 +452,40 @@ class SocketFlowInstance:
|
||||||
streaming: bool = False,
|
streaming: bool = False,
|
||||||
**kwargs: Any
|
**kwargs: Any
|
||||||
) -> Union[str, Iterator[str]]:
|
) -> Union[str, Iterator[str]]:
|
||||||
"""Graph RAG with optional streaming"""
|
"""
|
||||||
|
Execute graph-based RAG query with optional streaming.
|
||||||
|
|
||||||
|
Uses knowledge graph structure to find relevant context, then generates
|
||||||
|
a response using an LLM. Streaming mode delivers results incrementally.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query: Natural language query
|
||||||
|
user: User/keyspace identifier
|
||||||
|
collection: Collection identifier
|
||||||
|
max_subgraph_size: Maximum total triples in subgraph (default: 1000)
|
||||||
|
max_subgraph_count: Maximum number of subgraphs (default: 5)
|
||||||
|
max_entity_distance: Maximum traversal depth (default: 3)
|
||||||
|
streaming: Enable streaming mode (default: False)
|
||||||
|
**kwargs: Additional parameters passed to the service
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Union[str, Iterator[str]]: Complete response or stream of text chunks
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
socket = api.socket()
|
||||||
|
flow = socket.flow("default")
|
||||||
|
|
||||||
|
# Streaming graph RAG
|
||||||
|
for chunk in flow.graph_rag(
|
||||||
|
query="Tell me about Marie Curie",
|
||||||
|
user="trustgraph",
|
||||||
|
collection="scientists",
|
||||||
|
streaming=True
|
||||||
|
):
|
||||||
|
print(chunk, end='', flush=True)
|
||||||
|
```
|
||||||
|
"""
|
||||||
request = {
|
request = {
|
||||||
"query": query,
|
"query": query,
|
||||||
"user": user,
|
"user": user,
|
||||||
|
|
@ -344,7 +513,39 @@ class SocketFlowInstance:
|
||||||
streaming: bool = False,
|
streaming: bool = False,
|
||||||
**kwargs: Any
|
**kwargs: Any
|
||||||
) -> Union[str, Iterator[str]]:
|
) -> Union[str, Iterator[str]]:
|
||||||
"""Document RAG with optional streaming"""
|
"""
|
||||||
|
Execute document-based RAG query with optional streaming.
|
||||||
|
|
||||||
|
Uses vector embeddings to find relevant document chunks, then generates
|
||||||
|
a response using an LLM. Streaming mode delivers results incrementally.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query: Natural language query
|
||||||
|
user: User/keyspace identifier
|
||||||
|
collection: Collection identifier
|
||||||
|
doc_limit: Maximum document chunks to retrieve (default: 10)
|
||||||
|
streaming: Enable streaming mode (default: False)
|
||||||
|
**kwargs: Additional parameters passed to the service
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Union[str, Iterator[str]]: Complete response or stream of text chunks
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
socket = api.socket()
|
||||||
|
flow = socket.flow("default")
|
||||||
|
|
||||||
|
# Streaming document RAG
|
||||||
|
for chunk in flow.document_rag(
|
||||||
|
query="Summarize the key findings",
|
||||||
|
user="trustgraph",
|
||||||
|
collection="research-papers",
|
||||||
|
doc_limit=5,
|
||||||
|
streaming=True
|
||||||
|
):
|
||||||
|
print(chunk, end='', flush=True)
|
||||||
|
```
|
||||||
|
"""
|
||||||
request = {
|
request = {
|
||||||
"query": query,
|
"query": query,
|
||||||
"user": user,
|
"user": user,
|
||||||
|
|
@ -374,7 +575,32 @@ class SocketFlowInstance:
|
||||||
streaming: bool = False,
|
streaming: bool = False,
|
||||||
**kwargs: Any
|
**kwargs: Any
|
||||||
) -> Union[str, Iterator[str]]:
|
) -> Union[str, Iterator[str]]:
|
||||||
"""Execute prompt with optional streaming"""
|
"""
|
||||||
|
Execute a prompt template with optional streaming.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id: Prompt template identifier
|
||||||
|
variables: Dictionary of variable name to value mappings
|
||||||
|
streaming: Enable streaming mode (default: False)
|
||||||
|
**kwargs: Additional parameters passed to the service
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Union[str, Iterator[str]]: Complete response or stream of text chunks
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
socket = api.socket()
|
||||||
|
flow = socket.flow("default")
|
||||||
|
|
||||||
|
# Streaming prompt execution
|
||||||
|
for chunk in flow.prompt(
|
||||||
|
id="summarize-template",
|
||||||
|
variables={"topic": "quantum computing", "length": "brief"},
|
||||||
|
streaming=True
|
||||||
|
):
|
||||||
|
print(chunk, end='', flush=True)
|
||||||
|
```
|
||||||
|
"""
|
||||||
request = {
|
request = {
|
||||||
"id": id,
|
"id": id,
|
||||||
"variables": variables,
|
"variables": variables,
|
||||||
|
|
@ -397,7 +623,32 @@ class SocketFlowInstance:
|
||||||
limit: int = 10,
|
limit: int = 10,
|
||||||
**kwargs: Any
|
**kwargs: Any
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""Query graph embeddings for semantic search"""
|
"""
|
||||||
|
Query knowledge graph entities using semantic similarity.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text: Query text for semantic search
|
||||||
|
user: User/keyspace identifier
|
||||||
|
collection: Collection identifier
|
||||||
|
limit: Maximum number of results (default: 10)
|
||||||
|
**kwargs: Additional parameters passed to the service
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Query results with similar entities
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
socket = api.socket()
|
||||||
|
flow = socket.flow("default")
|
||||||
|
|
||||||
|
results = flow.graph_embeddings_query(
|
||||||
|
text="physicist who discovered radioactivity",
|
||||||
|
user="trustgraph",
|
||||||
|
collection="scientists",
|
||||||
|
limit=5
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
request = {
|
request = {
|
||||||
"text": text,
|
"text": text,
|
||||||
"user": user,
|
"user": user,
|
||||||
|
|
@ -409,7 +660,25 @@ class SocketFlowInstance:
|
||||||
return self.client._send_request_sync("graph-embeddings", self.flow_id, request, False)
|
return self.client._send_request_sync("graph-embeddings", self.flow_id, request, False)
|
||||||
|
|
||||||
def embeddings(self, text: str, **kwargs: Any) -> Dict[str, Any]:
|
def embeddings(self, text: str, **kwargs: Any) -> Dict[str, Any]:
|
||||||
"""Generate text embeddings"""
|
"""
|
||||||
|
Generate vector embeddings for text.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text: Input text to embed
|
||||||
|
**kwargs: Additional parameters passed to the service
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Response containing vectors
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
socket = api.socket()
|
||||||
|
flow = socket.flow("default")
|
||||||
|
|
||||||
|
result = flow.embeddings("quantum computing")
|
||||||
|
vectors = result.get("vectors", [])
|
||||||
|
```
|
||||||
|
"""
|
||||||
request = {"text": text}
|
request = {"text": text}
|
||||||
request.update(kwargs)
|
request.update(kwargs)
|
||||||
|
|
||||||
|
|
@ -425,7 +694,34 @@ class SocketFlowInstance:
|
||||||
limit: int = 100,
|
limit: int = 100,
|
||||||
**kwargs: Any
|
**kwargs: Any
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""Triple pattern query"""
|
"""
|
||||||
|
Query knowledge graph triples using pattern matching.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
s: Subject URI (optional, use None for wildcard)
|
||||||
|
p: Predicate URI (optional, use None for wildcard)
|
||||||
|
o: Object URI or Literal (optional, use None for wildcard)
|
||||||
|
user: User/keyspace identifier (optional)
|
||||||
|
collection: Collection identifier (optional)
|
||||||
|
limit: Maximum results to return (default: 100)
|
||||||
|
**kwargs: Additional parameters passed to the service
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Query results with matching triples
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
socket = api.socket()
|
||||||
|
flow = socket.flow("default")
|
||||||
|
|
||||||
|
# Find all triples about a specific subject
|
||||||
|
result = flow.triples_query(
|
||||||
|
s="http://example.org/person/marie-curie",
|
||||||
|
user="trustgraph",
|
||||||
|
collection="scientists"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
request = {"limit": limit}
|
request = {"limit": limit}
|
||||||
if s is not None:
|
if s is not None:
|
||||||
request["s"] = str(s)
|
request["s"] = str(s)
|
||||||
|
|
@ -450,7 +746,41 @@ class SocketFlowInstance:
|
||||||
operation_name: Optional[str] = None,
|
operation_name: Optional[str] = None,
|
||||||
**kwargs: Any
|
**kwargs: Any
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""GraphQL query"""
|
"""
|
||||||
|
Execute a GraphQL query against structured objects.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query: GraphQL query string
|
||||||
|
user: User/keyspace identifier
|
||||||
|
collection: Collection identifier
|
||||||
|
variables: Optional query variables dictionary
|
||||||
|
operation_name: Optional operation name for multi-operation documents
|
||||||
|
**kwargs: Additional parameters passed to the service
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: GraphQL response with data, errors, and/or extensions
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
socket = api.socket()
|
||||||
|
flow = socket.flow("default")
|
||||||
|
|
||||||
|
query = '''
|
||||||
|
{
|
||||||
|
scientists(limit: 10) {
|
||||||
|
name
|
||||||
|
field
|
||||||
|
discoveries
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
result = flow.objects_query(
|
||||||
|
query=query,
|
||||||
|
user="trustgraph",
|
||||||
|
collection="scientists"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
request = {
|
request = {
|
||||||
"query": query,
|
"query": query,
|
||||||
"user": user,
|
"user": user,
|
||||||
|
|
@ -470,7 +800,28 @@ class SocketFlowInstance:
|
||||||
parameters: Dict[str, Any],
|
parameters: Dict[str, Any],
|
||||||
**kwargs: Any
|
**kwargs: Any
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""Execute MCP tool"""
|
"""
|
||||||
|
Execute a Model Context Protocol (MCP) tool.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: Tool name/identifier
|
||||||
|
parameters: Tool parameters dictionary
|
||||||
|
**kwargs: Additional parameters passed to the service
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Tool execution result
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
socket = api.socket()
|
||||||
|
flow = socket.flow("default")
|
||||||
|
|
||||||
|
result = flow.mcp_tool(
|
||||||
|
name="search-web",
|
||||||
|
parameters={"query": "latest AI news", "limit": 5}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
"""
|
||||||
request = {
|
request = {
|
||||||
"name": name,
|
"name": name,
|
||||||
"parameters": parameters
|
"parameters": parameters
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,9 @@
|
||||||
|
"""
|
||||||
|
TrustGraph API Type Definitions
|
||||||
|
|
||||||
|
Data classes and type definitions for TrustGraph API objects including knowledge
|
||||||
|
graph elements, metadata structures, and streaming response chunks.
|
||||||
|
"""
|
||||||
|
|
||||||
import dataclasses
|
import dataclasses
|
||||||
import datetime
|
import datetime
|
||||||
|
|
@ -6,23 +12,59 @@ from .. knowledge import hash, Uri, Literal
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
class Triple:
|
class Triple:
|
||||||
|
"""
|
||||||
|
RDF triple representing a knowledge graph statement.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
s: Subject (entity URI or value)
|
||||||
|
p: Predicate (relationship URI)
|
||||||
|
o: Object (entity URI, literal value, or typed value)
|
||||||
|
"""
|
||||||
s : str
|
s : str
|
||||||
p : str
|
p : str
|
||||||
o : str
|
o : str
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
class ConfigKey:
|
class ConfigKey:
|
||||||
|
"""
|
||||||
|
Configuration key identifier.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
type: Configuration type/category (e.g., "llm", "embedding")
|
||||||
|
key: Specific configuration key within the type
|
||||||
|
"""
|
||||||
type : str
|
type : str
|
||||||
key : str
|
key : str
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
class ConfigValue:
|
class ConfigValue:
|
||||||
|
"""
|
||||||
|
Configuration key-value pair.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
type: Configuration type/category
|
||||||
|
key: Specific configuration key
|
||||||
|
value: Configuration value as string
|
||||||
|
"""
|
||||||
type : str
|
type : str
|
||||||
key : str
|
key : str
|
||||||
value : str
|
value : str
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
class DocumentMetadata:
|
class DocumentMetadata:
|
||||||
|
"""
|
||||||
|
Metadata for a document in the library.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
id: Unique document identifier
|
||||||
|
time: Document creation/upload timestamp
|
||||||
|
kind: Document MIME type (e.g., "application/pdf", "text/plain")
|
||||||
|
title: Document title
|
||||||
|
comments: Additional comments or description
|
||||||
|
metadata: List of RDF triples providing structured metadata
|
||||||
|
user: User/owner identifier
|
||||||
|
tags: List of tags for categorization
|
||||||
|
"""
|
||||||
id : str
|
id : str
|
||||||
time : datetime.datetime
|
time : datetime.datetime
|
||||||
kind : str
|
kind : str
|
||||||
|
|
@ -34,6 +76,18 @@ class DocumentMetadata:
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
class ProcessingMetadata:
|
class ProcessingMetadata:
|
||||||
|
"""
|
||||||
|
Metadata for an active document processing job.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
id: Unique processing job identifier
|
||||||
|
document_id: ID of the document being processed
|
||||||
|
time: Processing start timestamp
|
||||||
|
flow: Flow instance handling the processing
|
||||||
|
user: User identifier
|
||||||
|
collection: Target collection for processed data
|
||||||
|
tags: List of tags for categorization
|
||||||
|
"""
|
||||||
id : str
|
id : str
|
||||||
document_id : str
|
document_id : str
|
||||||
time : datetime.datetime
|
time : datetime.datetime
|
||||||
|
|
@ -44,6 +98,19 @@ class ProcessingMetadata:
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
class CollectionMetadata:
|
class CollectionMetadata:
|
||||||
|
"""
|
||||||
|
Metadata for a data collection.
|
||||||
|
|
||||||
|
Collections provide logical grouping and isolation for documents and
|
||||||
|
knowledge graph data.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
user: User/owner identifier
|
||||||
|
collection: Collection identifier
|
||||||
|
name: Human-readable collection name
|
||||||
|
description: Collection description
|
||||||
|
tags: List of tags for categorization
|
||||||
|
"""
|
||||||
user : str
|
user : str
|
||||||
collection : str
|
collection : str
|
||||||
name : str
|
name : str
|
||||||
|
|
@ -54,29 +121,80 @@ class CollectionMetadata:
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
class StreamingChunk:
|
class StreamingChunk:
|
||||||
"""Base class for streaming chunks"""
|
"""
|
||||||
|
Base class for streaming response chunks.
|
||||||
|
|
||||||
|
Used for WebSocket-based streaming operations where responses are delivered
|
||||||
|
incrementally as they are generated.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
content: The text content of this chunk
|
||||||
|
end_of_message: True if this is the final chunk of a message segment
|
||||||
|
"""
|
||||||
content: str
|
content: str
|
||||||
end_of_message: bool = False
|
end_of_message: bool = False
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
class AgentThought(StreamingChunk):
|
class AgentThought(StreamingChunk):
|
||||||
"""Agent reasoning chunk"""
|
"""
|
||||||
|
Agent reasoning/thought process chunk.
|
||||||
|
|
||||||
|
Represents the agent's internal reasoning or planning steps during execution.
|
||||||
|
These chunks show how the agent is thinking about the problem.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
content: Agent's thought text
|
||||||
|
end_of_message: True if this completes the current thought
|
||||||
|
chunk_type: Always "thought"
|
||||||
|
"""
|
||||||
chunk_type: str = "thought"
|
chunk_type: str = "thought"
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
class AgentObservation(StreamingChunk):
|
class AgentObservation(StreamingChunk):
|
||||||
"""Agent tool observation chunk"""
|
"""
|
||||||
|
Agent tool execution observation chunk.
|
||||||
|
|
||||||
|
Represents the result or observation from executing a tool or action.
|
||||||
|
These chunks show what the agent learned from using tools.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
content: Observation text describing tool results
|
||||||
|
end_of_message: True if this completes the current observation
|
||||||
|
chunk_type: Always "observation"
|
||||||
|
"""
|
||||||
chunk_type: str = "observation"
|
chunk_type: str = "observation"
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
class AgentAnswer(StreamingChunk):
|
class AgentAnswer(StreamingChunk):
|
||||||
"""Agent final answer chunk"""
|
"""
|
||||||
|
Agent final answer chunk.
|
||||||
|
|
||||||
|
Represents the agent's final response to the user's query after completing
|
||||||
|
its reasoning and tool use.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
content: Answer text
|
||||||
|
end_of_message: True if this completes the current answer segment
|
||||||
|
end_of_dialog: True if this completes the entire agent interaction
|
||||||
|
chunk_type: Always "final-answer"
|
||||||
|
"""
|
||||||
chunk_type: str = "final-answer"
|
chunk_type: str = "final-answer"
|
||||||
end_of_dialog: bool = False
|
end_of_dialog: bool = False
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
class RAGChunk(StreamingChunk):
|
class RAGChunk(StreamingChunk):
|
||||||
"""RAG streaming chunk"""
|
"""
|
||||||
|
RAG (Retrieval-Augmented Generation) streaming chunk.
|
||||||
|
|
||||||
|
Used for streaming responses from graph RAG, document RAG, text completion,
|
||||||
|
and other generative services.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
content: Generated text content
|
||||||
|
end_of_stream: True if this is the final chunk of the stream
|
||||||
|
error: Optional error information if an error occurred
|
||||||
|
chunk_type: Always "rag"
|
||||||
|
"""
|
||||||
chunk_type: str = "rag"
|
chunk_type: str = "rag"
|
||||||
end_of_stream: bool = False
|
end_of_stream: bool = False
|
||||||
error: Optional[Dict[str, str]] = None
|
error: Optional[Dict[str, str]] = None
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue