API Reference
February 9, 2026 · View on GitHub
Last Updated: 2026-01-09
Django Models
Source: opencontractserver/extracts/models.py
Extraction Models
Fieldset
Defines a collection of fields to extract from documents.
| Field | Type | Description |
|---|---|---|
name | CharField(256) | Fieldset name |
description | TextField | Description of purpose |
corpus | OneToOneField(Corpus) | Optional link for metadata schemas (nullable) |
Permissions:
permission_fieldset- Base permissioncreate_fieldset- Create new fieldsetsread_fieldset- View fieldsetsupdate_fieldset- Modify fieldsetsremove_fieldset- Delete fieldsetscomment_fieldset- Comment on fieldsetspublish_fieldset- Publish fieldsets
Column
Defines individual data fields within a fieldset. Supports both automated extraction and manual entry modes.
| Field | Type | Description |
|---|---|---|
| Basic Fields | ||
name | CharField(256) | Column name |
fieldset | ForeignKey(Fieldset) | Parent fieldset |
| Extraction Configuration | ||
query | TextField | Extraction prompt (nullable) |
match_text | TextField | Alternative to query for text matching (nullable) |
must_contain_text | TextField | Required text constraint (nullable) |
limit_to_label | CharField(512) | Annotation label filter (nullable) |
instructions | TextField | Additional extraction instructions (nullable) |
| Output Configuration | ||
output_type | TextField | Python type as string (e.g., str, int, list[str]) |
extract_is_list | BooleanField | Wrap output in List[] (default: False) |
| Task Configuration | ||
task_name | CharField(1024) | Celery task path (default: doc_extract_query_task) |
| Manual Entry Fields | ||
is_manual_entry | BooleanField | True for manual metadata, False for extraction (default: False) |
data_type | CharField(32) | Structured data type for manual entry (see Data Types below) |
default_value | JSONField | Default value for manual entry fields (nullable) |
help_text | TextField | Help text to display for manual entry fields (nullable) |
display_order | IntegerField | Order in which to display manual entry fields (default: 0) |
validation_config | JSONField | Validation rules for manual entry (nullable) |
Data Types (for manual entry):
STRING- Single line textTEXT- Multi-line textBOOLEAN- True/FalseINTEGER- Whole numbersFLOAT- Decimal numbersDATE- Date only (YYYY-MM-DD format)DATETIME- Date and time (ISO format)URL- Web addressesEMAIL- Email addressesCHOICE- Single selection (requireschoicesinvalidation_config)MULTI_CHOICE- Multiple selections (requireschoicesinvalidation_config)JSON- JSON objects or arrays
Validation Config Structure:
{
"required": true,
"choices": ["option1", "option2"],
"min_value": 0,
"max_value": 100,
"min_length": 1,
"max_length": 500,
"regex_pattern": "^[A-Z]+"
}
Permissions:
permission_column- Base permissioncreate_column- Create new columnsread_column- View columnsupdate_column- Modify columnsremove_column- Delete columnscomment_column- Comment on columnspublish_column- Publish columns
Extract
Represents an extraction job.
| Field | Type | Description |
|---|---|---|
corpus | ForeignKey(Corpus) | Target corpus (nullable) |
documents | ManyToManyField(Document) | Documents to process |
name | CharField(512) | Extract name |
fieldset | ForeignKey(Fieldset) | Fields to extract |
corpus_action | ForeignKey(CorpusAction) | Associated CorpusAction if triggered by automation (nullable) |
| Status Fields | ||
created | DateTimeField | Creation time (auto-set) |
started | DateTimeField | Processing start time (nullable) |
finished | DateTimeField | Completion time (nullable) |
error | TextField | Error message if failed (nullable) |
Permissions:
permission_extract- Base permissioncreate_extract- Create new extractsread_extract- View extractsupdate_extract- Modify extractsremove_extract- Delete extractscomment_extract- Comment on extractspublish_extract- Publish extracts
Datacell
Stores extracted data for a document/column pair. Supports both automated extraction results and manual metadata entry.
| Field | Type | Description |
|---|---|---|
| Relations | ||
extract | ForeignKey(Extract) | Parent extract (nullable for manual metadata) |
column | ForeignKey(Column) | Column definition |
document | ForeignKey(Document) | Source document |
sources | ManyToManyField(Annotation) | Source annotations used for extraction |
| Data Fields | ||
data | JSONField | Extracted or entered data (nullable) |
data_definition | TextField | Data type description |
corrected_data | JSONField | Human-corrected data (nullable) |
| Status Fields | ||
started | DateTimeField | Processing start time (nullable) |
completed | DateTimeField | Processing completion time (nullable) |
failed | DateTimeField | Failure time (nullable) |
stacktrace | TextField | Error details if failed (nullable) |
| Approval Workflow | ||
approved_by | ForeignKey(User) | User who approved the cell (nullable) |
rejected_by | ForeignKey(User) | User who rejected the cell (nullable) |
| Debugging | ||
llm_call_log | TextField | Captured LLM message history for debugging extraction issues (nullable) |
Unique Constraint: For manual metadata (where extract is null), only one datacell per document/column combination is allowed.
Permissions:
permission_datacell- Base permissioncreate_datacell- Create new datacellsread_datacell- View datacellsupdate_datacell- Modify datacellsremove_datacell- Delete datacellscomment_datacell- Comment on datacellspublish_datacell- Publish datacells
Celery Tasks
Orchestration Tasks
run_extract
Main extraction orchestrator that creates datacells and queues processing.
@shared_task
def run_extract(
extract_id: str | int,
user_id: str | int
) -> None:
"""
Creates Datacells for each document × column combination
and queues extraction tasks.
Args:
extract_id: ID of Extract to process
user_id: ID of user running extraction
"""
mark_extract_complete
Marks an extract as finished after all datacells complete.
@shared_task
def mark_extract_complete(
extract_id: str | int
) -> None:
"""
Updates Extract.finished timestamp and aggregates
any errors from failed datacells.
Args:
extract_id: ID of Extract to mark complete
"""
Extraction Tasks
doc_extract_query_task
Performs structured data extraction using agent framework.
@celery_task_with_async_to_sync()
async def doc_extract_query_task(
cell_id: int,
similarity_top_k: int = 10,
max_token_length: int = 64000
) -> None:
"""
Extracts data for a single datacell using PydanticAI agents.
Args:
cell_id: Datacell ID to process
similarity_top_k: Number of similar chunks to retrieve
max_token_length: Maximum context tokens
"""
Agent System
Factories
UnifiedAgentFactory
Creates framework-agnostic agents for document and corpus interactions.
class UnifiedAgentFactory:
@classmethod
def for_corpus(
cls,
corpus_id: int,
user_id: int,
framework: str = None
) -> CoreAgent:
"""Create agent for corpus-level queries."""
@classmethod
def for_document(
cls,
document_id: int,
user_id: int,
framework: str = None
) -> CoreAgent:
"""Create agent for document-level queries."""
UnifiedVectorStoreFactory
Creates appropriate vector store based on framework.
class UnifiedVectorStoreFactory:
@classmethod
def create(
cls,
framework: str,
corpus_id: int = None,
user_id: int = None,
**kwargs
) -> VectorStore:
"""
Create vector store for specified framework.
Args:
framework: "pydantic_ai"
corpus_id: Filter by corpus
user_id: Filter by user
**kwargs: Additional configuration
"""
Core Classes
CoreAgent
Base agent class providing unified interface.
class CoreAgent:
async def query(
self,
query: str,
tools: list[str] = None
) -> AsyncIterator[Event]:
"""
Process a query and stream events.
Yields:
StartEvent: Initial event with IDs
ContentEvent: Incremental content
SourcesEvent: Source annotations
FinishEvent: Final results
"""
async def approve_tool(
self,
tool_call_id: str
) -> None:
"""Approve a pending tool call."""
CoreAnnotationVectorStore
Framework-agnostic vector store implementation.
class CoreAnnotationVectorStore:
def __init__(
self,
corpus_id: int = None,
user_id: int = None,
embedder_path: str = None,
embed_dim: int = 384
):
"""Initialize vector store with filters."""
def search(
self,
query: VectorSearchQuery
) -> list[VectorSearchResult]:
"""Execute vector similarity search."""
WebSocket Consumers
UnifiedAgentConsumer
Handles all agent conversation contexts (corpus, document, standalone) over WebSocket.
class UnifiedAgentConsumer(AsyncWebsocketConsumer):
async def connect(self):
"""Authenticate, parse query params, and initialize context."""
async def receive(self, text_data):
"""Process incoming queries and approval decisions."""
async def disconnect(self, close_code):
"""Clean up on disconnection."""
WebSocket URL: /ws/agent-chat/?corpus_id=X&document_id=X
Query Parameters: corpus_id, document_id, conversation_id, agent_id
Message Types:
Client → Server:
{
"query": "string", // User question
"approval_decision": true, // Tool approval
"llm_message_id": "string" // For approval context
}
Server → Client:
{
"type": "ASYNC_START|ASYNC_CONTENT|ASYNC_SOURCES|ASYNC_FINISH|...",
"data": {} // Type-specific payload
}
See WebSocket Backend Documentation for full details on all consumers (UnifiedAgentConsumer, ThreadUpdatesConsumer, NotificationUpdatesConsumer).
GraphQL API
Queries
Extract Queries
query GetExtracts {
extracts {
edges {
node {
id
name
started
finished
datacells {
edges {
node {
id
data
completed
}
}
}
}
}
}
}
Fieldset Queries
query GetFieldsets {
fieldsets {
edges {
node {
id
name
description
columns {
edges {
node {
id
name
outputType
}
}
}
}
}
}
}
Mutations
Start Extract
mutation StartExtract($extractId: ID!) {
startExtract(extractId: $extractId) {
ok
message
objId
}
}
Create Fieldset
mutation CreateFieldset($name: String!, $description: String!) {
createFieldset(
name: $name
description: $description
) {
ok
objId
message
}
}
Configuration Settings
Agent Framework
# settings.py
# Framework selection: "pydantic_ai"
LLMS_DEFAULT_AGENT_FRAMEWORK = "pydantic_ai"
# Model configuration
LLMS_DEFAULT_MODEL = "gpt-4-turbo"
LLMS_MAX_TOKENS = 4096
LLMS_TEMPERATURE = 0.7
# Embedder settings
PREFERRED_EMBEDDER = "sentence-transformers/all-MiniLM-L6-v2"
EMBED_DIMENSIONS = 384
Celery Configuration
# Celery settings
CELERY_BROKER_URL = 'redis://localhost:6379'
CELERY_RESULT_BACKEND = 'redis://localhost:6379'
# Task routing
CELERY_TASK_ROUTES = {
'opencontractserver.tasks.extract_orchestrator_tasks.*': {
'queue': 'extract'
},
'opencontractserver.tasks.data_extract_tasks.*': {
'queue': 'ml'
}
}
WebSocket Configuration
# Channel layers
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
'hosts': [('127.0.0.1', 6379)],
},
},
}
# WebSocket settings
WEBSOCKET_TIMEOUT = 300 # seconds
WEBSOCKET_MAX_MESSAGE_SIZE = 1048576 # 1MB
Error Codes
WebSocket Close Codes
| Code | Description |
|---|---|
| 1000 | Normal closure |
| 4001 | Authentication failed |
| 4004 | Resource not found |
| 4008 | Rate limit exceeded |
| 5000 | Internal server error |
Extraction Error Types
| Error | Description |
|---|---|
ExtractionTimeout | Task exceeded time limit |
InvalidOutputType | Unsupported type specified |
DocumentNotFound | Document doesn't exist |
InsufficientPermissions | User lacks access |
AgentError | LLM processing failed |
Utilities
Type Parsing
from opencontractserver.utils.etl import parse_model_or_primitive
# Parse string type to Python type
python_type = parse_model_or_primitive("list[str]")
Embedding Generation
from opencontractserver.annotations.models import generate_embeddings_from_text
# Generate embeddings for text
embeddings = generate_embeddings_from_text(
text="Sample text",
embedder_path="sentence-transformers/all-MiniLM-L6-v2"
)
Async Decorators
from opencontractserver.shared.decorators import celery_task_with_async_to_sync
@celery_task_with_async_to_sync()
async def my_async_task():
# Async task implementation
pass