How to Integrate DeepTutor with Other Systems: CLI, API, and Python SDK Patterns
DeepTutor provides three integration surfaces—CLI, HTTP/WebSocket API, and Python SDK—that all converge on a single ChatOrchestrator runtime, ensuring consistent behavior across automation scripts, web services, and embedded applications.
The HKUDS/DeepTutor repository is architected as an agent-native tutoring service designed for flexible integration. Whether you need to embed intelligent tutoring into a learning management system, automate content generation via shell scripts, or build real-time streaming interfaces, DeepTutor exposes the same core capabilities through multiple entry points.
Integration Entry Points
DeepTutor exposes functionality through three independent surfaces that share identical runtime behavior:
- Python SDK – Direct in-process access via
ChatOrchestratorfor embedding in existing applications - HTTP/WebSocket API – FastAPI-based REST endpoints and unified WebSocket for real-time streaming
- CLI (Typer) – Command-line interface for scripting and containerized workflows
All three methods ultimately execute the same pipeline defined in deeptutor/runtime/orchestrator.py, passing a UnifiedContext object through the capability registry and streaming StreamEvent objects back to the caller.
Python SDK Integration
The Python SDK offers the tightest integration by importing the orchestrator directly into your application code.
Direct Orchestrator Usage
The ChatOrchestrator class defined in deeptutor/runtime/orchestrator.py serves as the primary execution engine. It routes UnifiedContext objects to appropriate capabilities (such as chat, deep_solve, or deep_research) and returns an async stream of StreamEvent objects.
import asyncio
from deeptutor.runtime.orchestrator import ChatOrchestrator
from deeptutor.core.context import UnifiedContext
async def run_question():
ctx = UnifiedContext(
user_message="Explain the Fourier transform and give a code example.",
active_capability="deep_solve",
)
orchestrator = ChatOrchestrator()
async for event in orchestrator.handle(ctx):
if event.type == "content":
print(event.content, end="", flush=True)
asyncio.run(run_question())
This approach instantiates the singleton registries defined in deeptutor/runtime/registry/capability_registry.py and deeptutor/runtime/registry/tool_registry.py, loading all available tools and capabilities automatically.
HTTP and WebSocket API Integration
For service-oriented architectures, DeepTutor exposes a FastAPI application defined in deeptutor/api/main.py.
REST API Endpoints
Deploy the server using uvicorn deeptutor.api.main:app, then send POST requests to capability-specific endpoints such as /api/v1/chat or /api/v1/solve. The request handlers construct a UnifiedContext from the JSON payload and stream StreamEvent objects back to the client.
curl -X POST http://localhost:8000/api/v1/chat \
-H "Content-Type: application/json" \
-d '{"user_message":"Summarize the Pythagorean theorem"}'
The chat router in deeptutor/api/routers/chat.py processes these requests by forwarding the constructed context to ChatOrchestrator.handle(), ensuring parity with the Python SDK.
WebSocket Streaming
For real-time, turn-based interactions, connect to the unified WebSocket endpoint at /api/v1/ws implemented in deeptutor/api/routers/unified_ws.py. This endpoint supports asynchronous message types including message, start_turn, and subscribe_turn, enabling pause/resume functionality and cancellation of in-flight operations.
import json, asyncio, websockets
async def ws_demo():
async with websockets.connect("ws://localhost:8000/api/v1/ws") as ws:
await ws.send(json.dumps({
"type": "message",
"user_message": "Generate a short Python script that prints prime numbers.",
"session_id": "demo-session"
}))
while True:
raw = await ws.recv()
msg = json.loads(raw)
if msg.get("type") == "content":
print(msg["content"], end="", flush=True)
if msg.get("type") == "done":
break
asyncio.run(ws_demo())
The WebSocket handler subscribes to the orchestrator's StreamBus and forwards events directly to the connected client.
Command Line Interface
The Typer-based CLI defined in deeptutor_cli/main.py provides a thin wrapper around the orchestrator for shell-based automation.
pip install -r requirements/cli.txt && pip install -e .
deeptutor run chat "What is a quantum bit?"
The CLI parses arguments, builds a UnifiedContext, and streams output to stdout using the same ChatOrchestrator pipeline used by the API and SDK.
Extending DeepTutor with Custom Tools
New capabilities and tools automatically propagate to all integration methods through the plugin system. Create a manifest in plugins/my_tool/manifest.yaml and implement BaseTool from deeptutor/core/tool_protocol.py:
name: my_tool
version: 0.1.0
type: tool
description: "A demo tool that echoes a string."
entry: plugins.my_tool.tool:EchoTool
from deeptutor.core.tool_protocol import BaseTool, ToolResult
class EchoTool(BaseTool):
name = "echo"
async def execute(self, text: str) -> ToolResult:
return ToolResult(content=text)
When the ToolRegistry (defined in deeptutor/runtime/registry/tool_registry.py) initializes, it discovers the plugin via deeptutor/plugins/loader.py, making the tool immediately available across the CLI, HTTP API, and Python SDK without additional configuration.
Core Architecture
ChatOrchestrator
The ChatOrchestrator class in deeptutor/runtime/orchestrator.py functions as the single point of execution. It creates a StreamBus for each turn, manages the lifecycle of streaming events defined in deeptutor/core/stream.py, and coordinates between the capability registry and tool registry.
Registries and Configuration
- Capability Registry (
deeptutor/runtime/registry/capability_registry.py) – Discovers capabilities at startup, exposing their OpenAI function-calling schemas - Tool Registry (
deeptutor/runtime/registry/tool_registry.py) – Resolves tool aliases and emits JSON schemas for LLM function calling - Settings (
deeptutor/config/settings.py) – Provides global configuration including LLM provider, model selection, and knowledge base paths to all components
Because these components are implemented as singletons, any tool or capability registered at startup becomes available uniformly across all integration surfaces.
Summary
- Three integration methods—CLI, HTTP/WebSocket API, and Python SDK—all utilize the same
ChatOrchestratorruntime indeeptutor/runtime/orchestrator.py UnifiedContextserves as the standard contract between entry points and capabilities, defined indeeptutor/core/context.py- Streaming responses use
StreamEventobjects (defined indeeptutor/core/stream.py) regardless of whether you use the SDK, WebSocket, or CLI - Plugin architecture allows custom tools to automatically appear in all interfaces via the registries in
deeptutor/runtime/registry/ - Configuration is centralized in
deeptutor/config/settings.pyand accessible to every integration layer
Frequently Asked Questions
What is the difference between the REST API and WebSocket integration for DeepTutor?
The REST API at /api/v1/chat provides request/response workflows suitable for simple queries, while the WebSocket endpoint at /api/v1/ws defined in deeptutor/api/routers/unified_ws.py supports streaming StreamEvent objects in real-time with turn-based state management, pause/resume capabilities, and cancellation tokens.
Can I use DeepTutor as a library in my existing Python application?
Yes, by importing ChatOrchestrator from deeptutor/runtime/orchestrator.py and constructing UnifiedContext objects from deeptutor/core/context.py, you can embed DeepTutor directly into your service. This in-process method provides the lowest latency and full access to the async stream of events.
How do custom tools propagate across integration methods?
When you place a plugin manifest and tool implementation in the plugins/ directory, the ToolRegistry in deeptutor/runtime/registry/tool_registry.py automatically loads it at startup using the loader in deeptutor/plugins/loader.py. Because the registries are singletons shared by all entry points, the new tool immediately appears in the CLI, HTTP API, and Python SDK without code changes.
Which configuration file controls the LLM provider settings?
Global settings including the LLM provider, model name, and knowledge base locations are managed in deeptutor/config/settings.py. These settings are instantiated as singletons and consumed by the orchestrator and registry components, ensuring consistent LLM behavior across all three integration surfaces.
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 →