How to Implement Callback Functions for Processing Command Output in OpenBB
To process command output in OpenBB, define an async callback function that receives the raw aiohttp response object and pass it to the amake_request helper when building provider models.
The OpenBB Platform uses an asynchronous request architecture that separates data fetching from data transformation. By implementing callback functions for processing command output in OpenBB, you can intercept raw HTTP responses, apply custom parsing logic, and return structured data that integrates seamlessly with the CLI's display and registry systems.
Understanding the Callback Architecture in OpenBB
OpenBB processes data-fetching commands through the amake_request helper located in openbb_core/provider/utils/helpers.py. This utility accepts a response_callback parameter—an async function that transforms the raw response into the shape expected by the command's Pydantic model.
The Async Request Helper (amake_request)
The amake_request function serves as the bridge between HTTP transport and data processing. When a command executes, the helper opens an aiohttp session, fetches the response, then awaits your callback with the signature async def callback(response: ClientResponse, extra: any). Because the callback runs inside the request coroutine, you can perform additional async I/O such as secondary API calls or file extraction without blocking the CLI.
Where Callbacks Live in the Codebase
Provider-specific callbacks are typically organized in utility modules:
openbb_platform/providers/tradingeconomics/openbb_tradingeconomics/utils/helpers.py– Generic HTTP response handling for JSON, CSV, and ZIP formatsopenbb_platform/providers/sec/openbb_sec/utils/helpers.py– SEC-specific response handling for filings and compressed archivesopenbb_platform/providers/intrinio/openbb_intrinio/utils/helpers.py– Pagination-aware async JSON processing
The CLI controllers in cli/openbb_cli/controllers/base_controller.py and cli/openbb_cli/controllers/base_platform_controller.py handle the --register_obbject flag, which determines whether processed output gets stored in the OBBject registry.
Implementing a Custom Callback Function
To implement callback functions for processing command output in OpenBB, create an async function that accepts the ClientResponse object and returns a Python object (dict, list, or DataFrame).
Simple CSV Parsing Callback
For providers returning CSV data, implement a callback that streams and parses the text:
# File: openbb_platform/providers/example/utils/helpers.py
import csv
from io import StringIO
from aiohttp import ClientResponse
from typing import List, Dict
async def csv_callback(response: ClientResponse, _: any) -> List[Dict]:
"""Read a CSV response and return a list of dictionaries."""
text = await response.text()
reader = csv.DictReader(StringIO(text))
return [row for row in reader]
Use this callback when constructing your provider model:
# File: openbb_platform/providers/example/models/my_data.py
from ...utils.helpers import csv_callback
from openbb_core.provider.utils.helpers import amake_request
async def fetch_data(symbol: str):
url = f"https://example.com/data/{symbol}.csv"
raw = await amake_request(url, response_callback=csv_callback)
return raw
Enriched Data Callback with OBBject Registration
To add metadata before the CLI registers the result, create an enrichment callback:
# File: cli/openbb_cli/controllers/custom_controller.py
from datetime import datetime
from aiohttp import ClientResponse
async def enrich_callback(response: ClientResponse, _: any):
"""Add timestamp and source metadata to the response."""
data = await response.json()
data["fetched_at"] = datetime.utcnow().isoformat()
data["source"] = "custom_api"
return data
When users pass the --register_obbject flag, BasePlatformController (lines 165-168) automatically stores the enriched object in the session registry using the logic defined in base_controller.py (lines 734-735).
Handling Paginated Responses
For APIs with pagination, implement recursive callbacks that follow next_page URLs:
# File: openbb_platform/providers/intrinio/openbb_intrinio/utils/helpers.py
from aiohttp import ClientResponse
from typing import List, Dict
async def pagination_callback(response: ClientResponse, _: any) -> List[Dict]:
"""Concatenate paginated Intrinio responses into a single list."""
data = await response.json()
results = data.get("data", [])
while data.get("next_page"):
next_url = data["next_page"]
# Fetch next page using the same callback pattern
next_data = await amake_request(next_url, response_callback=pagination_callback)
results.extend(next_data.get("data", []))
data = next_data
return results
Integrating Callbacks into Provider Models
The command flow follows a strict injection pattern:
- User executes CLI command (e.g.,
openbb stocks.load AAPL) - Controller parses arguments via
BaseController.parse_known_args_and_warn - Provider model builds URL and calls
amake_request(url, response_callback=my_callback) - Callback transforms raw response into the expected data structure
- Model validates data through Pydantic and returns to CLI
You do not need to modify command-level logic—the callback is injected at the request construction point in the provider model file (e.g., openbb_platform/providers/sec/openbb_sec/models/sec_filing.py).
Registering Processed Output with the OBBject Registry
OpenBB's CLI maintains an OBBject registry for persisting command results across the session. To enable this for your custom callback:
- Ensure your callback returns a serializable object (dict, list, or Pydantic model)
- Users must append
--register_obbjectwhen running the command BasePlatformControllerdetects the flag and stores the result viasession.obbject_registry.add()
Access registered objects later using the results command with the appropriate key.
Summary
- Define async callbacks with the signature
async def callback(response: ClientResponse, extra: any)to intercept HTTP responses before they reach the CLI. - Pass callbacks to
amake_requestin your provider model to transform raw data into structured formats without modifying core CLI code. - Leverage existing infrastructure by using the
--register_obbjectflag (handled inbase_controller.pyandbase_platform_controller.py) to persist processed output in the OBBject registry. - Handle complex scenarios like pagination or file extraction within the callback since it executes inside the async request coroutine.
Frequently Asked Questions
What is the exact function signature for an OpenBB response callback?
An OpenBB response callback must be an async function accepting two parameters: response (an aiohttp.ClientResponse object) and extra (typically None or a session context). The function should return a Python object such as a dictionary, list, or Pydantic model. This signature is required by the amake_request helper in openbb_core/provider/utils/helpers.py.
Where should I place custom callback functions in the OpenBB codebase?
Place custom callbacks in the utils/helpers.py file within your specific provider directory (e.g., openbb_platform/providers/your_provider/openbb_your_provider/utils/helpers.py). For CLI-specific post-processing, you can define callbacks directly in the controller file at cli/openbb_cli/controllers/custom_controller.py or import them from utility modules.
How does the --register_obbject flag interact with my callback output?
When users include --register_obbject in their command, BaseController parses the flag (as implemented in cli/openbb_cli/controllers/base_controller.py lines 734-735) and BasePlatformController stores the returned object in the session registry (lines 165-168 in base_platform_controller.py). Your callback must return a serializable object for successful registration.
Can I perform additional async operations inside a callback?
Yes. Because amake_request awaits your callback within the active aiohttp session, you can safely perform additional async I/O operations such as secondary API calls, database queries, or file system operations. This is particularly useful for pagination patterns like those implemented in the Intrinio provider.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →