mirror of
https://github.com/open-jarvis/OpenJarvis.git
synced 2026-07-28 13:26:48 +00:00
* chore: create learning subdirectory structure (routing, agents, intelligence) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: extract classify_query to routing/_utils.py Move the classify_query() function and its regex patterns into a shared utility module so multiple routing policies can import it without depending on the full trace_policy module. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: move routing files to learning/routing/ subdirectory Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: create LearnedRouterPolicy merging trace-driven + SFT routing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add conditional Algolia DocSearch integration Add Algolia DocSearch as an optional search upgrade — native lunr.js search remains the default until credentials are configured. Includes CDN assets, Jinja2 conditional config injection, init script with graceful fallback, light/dark theme CSS, improved search tokenization for snake_case/dotted identifiers, and search boosts for key pages. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: move agent_evolver and skill_discovery to learning/agents/ Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: move learning/orchestrator to learning/intelligence/orchestrator Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: delete removed learning policies, rewrite __init__.py, clean up api_routes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SFT/GRPO/DSPy/GEPA config dataclasses, update LearningConfig Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add general-purpose SFT trainer (intelligence/sft_trainer.py) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: update stale imports in multi_model_router example Update imports to use new learning/routing/ paths after the subdirectory reorganization. Replace BanditRouterPolicy with LearnedRouterPolicy. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add general-purpose GRPO trainer (intelligence/grpo_trainer.py) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add DSPy agent optimizer (agents/dspy_optimizer.py) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add GEPA agent optimizer (agents/gepa_optimizer.py) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add learning-dspy and learning-gepa optional dependency extras Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: update integration test to check for learned policy instead of grpo Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: clean up stale APIs and unused params in examples - deep_research: remove system_prompt and max_turns params not accepted by Jarvis.ask(), inline system prompt into the query instead - doc_qa: remove unused --top-k CLI arg that was never passed to the API - multi_model_router: fix select_model() call to match single-arg signature Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: import SFT/GRPO trainers in intelligence/__init__.py for registry Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: remove .md file changes from PR Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: restore search boost frontmatter for key docs pages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
386 lines
10 KiB
Markdown
386 lines
10 KiB
Markdown
---
|
|
title: Python SDK
|
|
description: High-level Python interface for local inference, memory, and agent workflows
|
|
search:
|
|
boost: 2
|
|
---
|
|
|
|
# Python SDK
|
|
|
|
The OpenJarvis Python SDK provides a high-level interface for interacting with local inference engines, managing memory, and running agent workflows. The primary entry point is the `Jarvis` class.
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
git clone https://github.com/open-jarvis/OpenJarvis.git
|
|
cd OpenJarvis
|
|
uv sync
|
|
```
|
|
|
|
## Quick Start
|
|
|
|
```python
|
|
from openjarvis import Jarvis
|
|
|
|
j = Jarvis()
|
|
response = j.ask("What is the capital of France?")
|
|
print(response)
|
|
j.close()
|
|
```
|
|
|
|
---
|
|
|
|
## Jarvis Class
|
|
|
|
### Constructor
|
|
|
|
```python
|
|
Jarvis(
|
|
*,
|
|
config: JarvisConfig | None = None,
|
|
config_path: str | None = None,
|
|
engine_key: str | None = None,
|
|
model: str | None = None,
|
|
)
|
|
```
|
|
|
|
| Parameter | Type | Default | Description |
|
|
|---------------|------------------|---------|----------------------------------------------------------------|
|
|
| `config` | `JarvisConfig` | `None` | Provide a pre-built configuration object |
|
|
| `config_path` | `str` | `None` | Path to a TOML configuration file |
|
|
| `engine_key` | `str` | `None` | Override the engine backend (`"ollama"`, `"vllm"`, etc.) |
|
|
| `model` | `str` | `None` | Override the default model (e.g., `"qwen3:8b"`) |
|
|
|
|
If no `config` or `config_path` is provided, the SDK loads configuration from the default location (`~/.openjarvis/config.toml`), falling back to built-in defaults.
|
|
|
|
**Examples:**
|
|
|
|
```python
|
|
# Default configuration — auto-detects engine
|
|
j = Jarvis()
|
|
|
|
# Override the model
|
|
j = Jarvis(model="qwen3:8b")
|
|
|
|
# Override the engine
|
|
j = Jarvis(engine_key="ollama")
|
|
|
|
# Load from a specific config file
|
|
j = Jarvis(config_path="/path/to/config.toml")
|
|
```
|
|
|
|
### Properties
|
|
|
|
| Property | Type | Description |
|
|
|-----------|----------------|-----------------------------------|
|
|
| `config` | `JarvisConfig` | The active configuration object |
|
|
| `version` | `str` | The OpenJarvis version string |
|
|
| `memory` | `MemoryHandle` | Proxy for memory operations |
|
|
|
|
---
|
|
|
|
## `ask()` Method
|
|
|
|
Send a query and receive a plain-text response.
|
|
|
|
```python
|
|
ask(
|
|
query: str,
|
|
*,
|
|
model: str | None = None,
|
|
agent: str | None = None,
|
|
tools: list[str] | None = None,
|
|
temperature: float = 0.7,
|
|
max_tokens: int = 1024,
|
|
context: bool = True,
|
|
) -> str
|
|
```
|
|
|
|
| Parameter | Type | Default | Description |
|
|
|---------------|--------------|---------|------------------------------------------------------|
|
|
| `query` | `str` | -- | The question or prompt to send |
|
|
| `model` | `str` | `None` | Override the model for this call |
|
|
| `agent` | `str` | `None` | Route through an agent (`"simple"`, `"orchestrator"`) |
|
|
| `tools` | `list[str]` | `None` | Tool names to enable (requires agent mode) |
|
|
| `temperature` | `float` | `0.7` | Sampling temperature |
|
|
| `max_tokens` | `int` | `1024` | Maximum tokens to generate |
|
|
| `context` | `bool` | `True` | Whether to inject memory context |
|
|
|
|
**Returns:** A `str` containing the model's response text.
|
|
|
|
**Examples:**
|
|
|
|
```python
|
|
# Simple query
|
|
response = j.ask("What is machine learning?")
|
|
|
|
# Override model for this call
|
|
response = j.ask("Hello", model="llama3.2:3b")
|
|
|
|
# Disable memory context injection
|
|
response = j.ask("Tell me about Python", context=False)
|
|
|
|
# Adjust generation parameters
|
|
response = j.ask("Write a haiku", temperature=0.3, max_tokens=50)
|
|
```
|
|
|
|
---
|
|
|
|
## `ask_full()` Method
|
|
|
|
Send a query and receive a detailed result dictionary with metadata.
|
|
|
|
```python
|
|
ask_full(
|
|
query: str,
|
|
*,
|
|
model: str | None = None,
|
|
agent: str | None = None,
|
|
tools: list[str] | None = None,
|
|
temperature: float = 0.7,
|
|
max_tokens: int = 1024,
|
|
context: bool = True,
|
|
) -> dict[str, Any]
|
|
```
|
|
|
|
The parameters are identical to `ask()`.
|
|
|
|
**Returns:** A dictionary with the following keys:
|
|
|
|
=== "Direct Mode"
|
|
|
|
| Key | Type | Description |
|
|
|-----------|--------|------------------------------------------|
|
|
| `content` | `str` | The response text |
|
|
| `usage` | `dict` | Token usage (`prompt_tokens`, `completion_tokens`, `total_tokens`) |
|
|
| `model` | `str` | The model used |
|
|
| `engine` | `str` | The engine backend used |
|
|
|
|
=== "Agent Mode"
|
|
|
|
| Key | Type | Description |
|
|
|----------------|--------------|------------------------------------------|
|
|
| `content` | `str` | The response text |
|
|
| `usage` | `dict` | Token usage (may be empty in agent mode) |
|
|
| `tool_results` | `list[dict]` | Tool execution results |
|
|
| `turns` | `int` | Number of agent turns taken |
|
|
| `model` | `str` | The model used |
|
|
| `engine` | `str` | The engine backend used |
|
|
|
|
**Example:**
|
|
|
|
```python
|
|
result = j.ask_full("What is 2+2?")
|
|
print(result["content"]) # "4"
|
|
print(result["model"]) # "qwen3:8b"
|
|
print(result["engine"]) # "ollama"
|
|
print(result["usage"]) # {"prompt_tokens": 10, ...}
|
|
```
|
|
|
|
---
|
|
|
|
## Agent Mode
|
|
|
|
Pass the `agent` parameter to route queries through an agent. Agents can manage multi-turn conversations and use tools.
|
|
|
|
```python
|
|
# Simple agent — single turn, no tools
|
|
response = j.ask("Hello", agent="simple")
|
|
|
|
# Orchestrator agent — multi-turn with tool calling
|
|
response = j.ask(
|
|
"What is sqrt(144) + 3^2?",
|
|
agent="orchestrator",
|
|
tools=["calculator", "think"],
|
|
)
|
|
```
|
|
|
|
When using agent mode with `ask_full()`, the result includes `tool_results` showing each tool invocation:
|
|
|
|
```python
|
|
result = j.ask_full(
|
|
"Calculate 15% of 340",
|
|
agent="orchestrator",
|
|
tools=["calculator"],
|
|
)
|
|
|
|
print(result["content"]) # "15% of 340 is 51.0"
|
|
print(result["turns"]) # 2
|
|
print(result["tool_results"])
|
|
# [{"tool_name": "calculator", "content": "51.0", "success": True}]
|
|
```
|
|
|
|
Available agents: `simple`, `orchestrator`, `operative`, `monitor_operative`
|
|
|
|
Available tools: `calculator`, `think`, `retrieval`, `llm`, `file_read`
|
|
|
|
---
|
|
|
|
## MemoryHandle
|
|
|
|
The `Jarvis.memory` attribute provides a `MemoryHandle` for document indexing, search, and statistics. The memory backend is lazily initialized on first use.
|
|
|
|
### `index()`
|
|
|
|
Index a file or directory into the memory store.
|
|
|
|
```python
|
|
index(
|
|
path: str,
|
|
*,
|
|
chunk_size: int = 512,
|
|
chunk_overlap: int = 64,
|
|
) -> dict[str, Any]
|
|
```
|
|
|
|
| Parameter | Type | Default | Description |
|
|
|-----------------|-------|---------|---------------------------------------|
|
|
| `path` | `str` | -- | Path to a file or directory to index |
|
|
| `chunk_size` | `int` | `512` | Chunk size in tokens |
|
|
| `chunk_overlap` | `int` | `64` | Overlap between chunks in tokens |
|
|
|
|
**Returns:** A dictionary with `chunks` (count), `doc_ids` (list), and `path`.
|
|
|
|
```python
|
|
result = j.memory.index("./docs/")
|
|
print(f"Indexed {result['chunks']} chunks")
|
|
# Indexed 42 chunks
|
|
|
|
# Custom chunking parameters
|
|
result = j.memory.index("./notes/", chunk_size=256, chunk_overlap=32)
|
|
```
|
|
|
|
### `search()`
|
|
|
|
Search the memory store for relevant chunks.
|
|
|
|
```python
|
|
search(
|
|
query: str,
|
|
*,
|
|
top_k: int = 5,
|
|
) -> list[dict[str, Any]]
|
|
```
|
|
|
|
| Parameter | Type | Default | Description |
|
|
|-----------|-------|---------|--------------------------------|
|
|
| `query` | `str` | -- | The search query |
|
|
| `top_k` | `int` | `5` | Number of results to return |
|
|
|
|
**Returns:** A list of dictionaries, each containing `content`, `score`, `source`, and `metadata`.
|
|
|
|
```python
|
|
results = j.memory.search("neural networks")
|
|
for r in results:
|
|
print(f"[{r['score']:.4f}] {r['source']}: {r['content'][:80]}...")
|
|
```
|
|
|
|
### `stats()`
|
|
|
|
Return memory backend statistics.
|
|
|
|
```python
|
|
stats() -> dict[str, Any]
|
|
```
|
|
|
|
**Returns:** A dictionary with `backend` (name) and `count` (document count, if available).
|
|
|
|
```python
|
|
info = j.memory.stats()
|
|
print(f"Backend: {info['backend']}, Documents: {info.get('count', 'N/A')}")
|
|
```
|
|
|
|
### `close()`
|
|
|
|
Release the memory backend and its resources.
|
|
|
|
```python
|
|
j.memory.close()
|
|
```
|
|
|
|
---
|
|
|
|
## Model and Engine Discovery
|
|
|
|
### `list_models()`
|
|
|
|
Return a list of model identifiers available on the active engine.
|
|
|
|
```python
|
|
models = j.list_models()
|
|
print(models) # ["qwen3:8b", "llama3.2:3b", ...]
|
|
```
|
|
|
|
### `list_engines()`
|
|
|
|
Return a list of registered engine keys.
|
|
|
|
```python
|
|
engines = j.list_engines()
|
|
print(engines) # ["ollama", "vllm", "llamacpp", ...]
|
|
```
|
|
|
|
---
|
|
|
|
## Resource Management
|
|
|
|
### `close()`
|
|
|
|
Release all resources held by the `Jarvis` instance, including the memory backend, telemetry store, and engine connection.
|
|
|
|
```python
|
|
j.close()
|
|
```
|
|
|
|
!!! tip "Context Manager Pattern"
|
|
While `Jarvis` does not implement `__enter__`/`__exit__` directly, you should always call `close()` when done to free database connections and other resources:
|
|
|
|
```python
|
|
j = Jarvis()
|
|
try:
|
|
response = j.ask("Hello")
|
|
print(response)
|
|
finally:
|
|
j.close()
|
|
```
|
|
|
|
---
|
|
|
|
## Complete Example
|
|
|
|
```python
|
|
from openjarvis import Jarvis
|
|
|
|
# Initialize with auto-detected engine
|
|
j = Jarvis(model="qwen3:8b")
|
|
|
|
# Index documents for context-augmented responses
|
|
result = j.memory.index("./docs/")
|
|
print(f"Indexed {result['chunks']} chunks from {result['path']}")
|
|
|
|
# Simple query with memory context
|
|
response = j.ask("What are the main features?")
|
|
print(response)
|
|
|
|
# Detailed query with agent and tools
|
|
full_result = j.ask_full(
|
|
"Calculate the square root of 256 and add 10",
|
|
agent="orchestrator",
|
|
tools=["calculator"],
|
|
)
|
|
print(f"Answer: {full_result['content']}")
|
|
print(f"Turns: {full_result['turns']}")
|
|
print(f"Tools used: {[t['tool_name'] for t in full_result['tool_results']]}")
|
|
|
|
# Search memory directly
|
|
results = j.memory.search("configuration")
|
|
for r in results:
|
|
print(f" [{r['score']:.3f}] {r['source']}")
|
|
|
|
# List available models
|
|
print("Models:", j.list_models())
|
|
|
|
# Clean up
|
|
j.close()
|
|
```
|