mirror of
https://github.com/open-jarvis/OpenJarvis.git
synced 2026-07-28 14:07:55 +00:00
init commit
This commit is contained in:
@@ -0,0 +1,218 @@
|
||||
---
|
||||
title: Code Companion
|
||||
description: Code review, debugging, and test generation with ReAct agents
|
||||
---
|
||||
|
||||
# Code Companion
|
||||
|
||||
This tutorial walks through `examples/code_companion/` — three developer-focused scripts that use a `native_react` (ReAct) agent to automate common coding tasks: reviewing pull request diffs, investigating errors, and generating tests. Each script adapts the same core pattern to a different workflow, making it easy to extend for your own code intelligence use cases.
|
||||
|
||||
!!! tip "Prerequisites"
|
||||
- Python 3.10 or later
|
||||
- OpenJarvis installed: `uv sync --extra dev` from the repository root
|
||||
- An inference engine running — Ollama locally or a cloud API key in `.env`
|
||||
- For `reviewer.py` and `code_review.py`: a git repository with at least two branches or commits
|
||||
|
||||
## The Three Scripts
|
||||
|
||||
| Script | Purpose | Tools Used |
|
||||
|---|---|---|
|
||||
| `reviewer.py` | Review a git diff between two branches | `git_diff`, `git_log`, `file_read`, `think` |
|
||||
| `debugger.py` | Investigate an error and propose a fix | `file_read`, `shell_exec`, `think` |
|
||||
| `test_gen.py` | Generate comprehensive tests for a Python module | `file_read`, `think`, `file_write` |
|
||||
|
||||
All three use the `native_react` agent with the same SDK pattern. The difference is which tools are provided and how the prompt is structured.
|
||||
|
||||
## The ReAct Agent Loop
|
||||
|
||||
The `native_react` agent implements the Thought-Action-Observation cycle. Rather than producing a single response, it iterates until it has gathered enough information:
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> Thought: Receive task prompt
|
||||
Thought --> Action: Decide which tool to call
|
||||
Action --> Observation: Execute tool, receive result
|
||||
Observation --> Thought: Feed result back into context
|
||||
Thought --> FinalAnswer: Sufficient information gathered
|
||||
FinalAnswer --> [*]
|
||||
```
|
||||
|
||||
This loop lets the agent adaptively explore the codebase. For example, the reviewer might read a diff, notice a suspicious function call, then read the source of that function before making its assessment — without any of that branching logic being hardcoded in the script.
|
||||
|
||||
## Core SDK Pattern
|
||||
|
||||
All three scripts follow the same structure. Understanding this pattern lets you adapt it to any code intelligence task:
|
||||
|
||||
```python title="Core SDK pattern" hl_lines="4 5 6"
|
||||
from openjarvis import Jarvis
|
||||
|
||||
j = Jarvis(model="qwen3:8b", engine_key="ollama") # (1)!
|
||||
try:
|
||||
response = j.ask(
|
||||
prompt, # (2)!
|
||||
agent="native_react", # (3)!
|
||||
tools=["git_diff", "think"], # (4)!
|
||||
)
|
||||
print(response)
|
||||
finally:
|
||||
j.close() # (5)!
|
||||
```
|
||||
|
||||
1. Both `model` and `engine_key` are optional. Omitting them uses auto-detected defaults from `~/.openjarvis/config.toml`.
|
||||
2. The prompt describes the task in detail, including what tools to use, what steps to follow, and what the output structure should look like.
|
||||
3. `"native_react"` selects the `NativeReActAgent`. The alias `"react"` also works.
|
||||
4. The tool list is passed directly. Any registered tool name is valid — run `jarvis agent info native_react` to see all available tools.
|
||||
5. Always call `j.close()` to release engine resources. A `try/finally` block ensures cleanup even if the agent raises an exception.
|
||||
|
||||
## Code Review
|
||||
|
||||
The `reviewer.py` script reviews the diff between two git refs and produces structured feedback with issues, suggestions, and an overall verdict.
|
||||
|
||||
```bash title="Terminal"
|
||||
# Review a feature branch against main (default)
|
||||
python examples/code_companion/reviewer.py --branch feature-x
|
||||
|
||||
# Review a specific commit range
|
||||
python examples/code_companion/reviewer.py --branch HEAD --base develop
|
||||
|
||||
# Use a cloud model for larger diffs
|
||||
python examples/code_companion/reviewer.py \
|
||||
--branch feature-x --model gpt-4o --engine cloud
|
||||
```
|
||||
|
||||
The agent follows a four-step process:
|
||||
|
||||
1. Call `git_diff` to see what changed between the two refs
|
||||
2. Call `git_log` to understand the commit history and intent
|
||||
3. Call `file_read` on any files that need more context
|
||||
4. Call `think` to reason about code quality, bugs, and design decisions
|
||||
|
||||
The final output is structured with four sections: **Summary**, **Issues Found**, **Suggestions**, and **Overall Assessment** (APPROVE, REQUEST CHANGES, or COMMENT).
|
||||
|
||||
| Flag | Default | Description |
|
||||
|---|---|---|
|
||||
| `--branch` | `HEAD` | Branch or commit to review |
|
||||
| `--base` | `main` | Base branch to diff against |
|
||||
| `--model` | `qwen3:8b` | Model identifier |
|
||||
| `--engine` | `ollama` | Engine backend |
|
||||
|
||||
## Debug Assistant
|
||||
|
||||
The `debugger.py` script takes an error message, optionally a file path, and produces a root cause analysis with a concrete fix.
|
||||
|
||||
```bash title="Terminal"
|
||||
# Investigate a TypeError
|
||||
python examples/code_companion/debugger.py \
|
||||
--error "TypeError: NoneType has no attribute 'split'"
|
||||
|
||||
# Provide the file where the error occurred for faster analysis
|
||||
python examples/code_companion/debugger.py \
|
||||
--error "KeyError: 'user_id'" \
|
||||
--file src/app/views.py
|
||||
|
||||
# Use a cloud model for complex stack traces
|
||||
python examples/code_companion/debugger.py \
|
||||
--error "Segfault in libfoo.so" \
|
||||
--model gpt-4o --engine cloud
|
||||
```
|
||||
|
||||
The agent uses `file_read` to examine the relevant source, `shell_exec` to run diagnostic commands (grep for symbols, check imports, inspect directory contents), and `think` to reason about root causes before proposing a fix.
|
||||
|
||||
!!! note "shell_exec safety"
|
||||
The `shell_exec` tool runs commands in the current working directory. In production deployments, `ToolExecutor` enforces RBAC capability policies — ensure the `shell_exec` capability is permitted for the agent's role. See [Architecture: Security](../architecture/security.md).
|
||||
|
||||
The output has three sections: **Root Cause**, **Proposed Fix** (concrete code change), and **Prevention** (type hints, validation, tests).
|
||||
|
||||
| Flag | Default | Description |
|
||||
|---|---|---|
|
||||
| `--error` | (required) | Error message or stack trace |
|
||||
| `--file` | (none) | Optional file path where the error occurred |
|
||||
| `--model` | `qwen3:8b` | Model identifier |
|
||||
| `--engine` | `ollama` | Engine backend |
|
||||
|
||||
## Test Generator
|
||||
|
||||
The `test_gen.py` script reads a Python module, reasons about its public interface, and writes a complete test file.
|
||||
|
||||
```bash title="Terminal"
|
||||
# Generate pytest tests for a module
|
||||
python examples/code_companion/test_gen.py \
|
||||
--module src/openjarvis/tools/calculator.py
|
||||
|
||||
# Use unittest and specify the output file
|
||||
python examples/code_companion/test_gen.py \
|
||||
--module src/openjarvis/tools/calculator.py \
|
||||
--framework unittest \
|
||||
--output tests/test_calculator_generated.py
|
||||
```
|
||||
|
||||
The agent reads the module with `file_read`, uses `think` to plan test cases (happy paths, edge cases, error handling, boundary conditions), reads any related base classes for context, then writes the complete test file with `file_write`.
|
||||
|
||||
!!! note "Output path default"
|
||||
If `--output` is not specified, the generated file is saved as `test_<module_name>.py` in the current working directory. The script prints the output path when done.
|
||||
|
||||
The generated tests follow these guidelines (enforced via the prompt):
|
||||
|
||||
- Every public function and method has at least one test
|
||||
- Each test has a docstring explaining what it verifies
|
||||
- Edge cases are covered: empty input, `None`, large values, invalid types
|
||||
- External dependencies are mocked with `unittest.mock`
|
||||
- The file is self-contained and runnable with `pytest` or `unittest` without modification
|
||||
|
||||
| Flag | Default | Description |
|
||||
|---|---|---|
|
||||
| `--module` | (required) | Path to the Python module |
|
||||
| `--framework` | `pytest` | Test framework (`pytest` or `unittest`) |
|
||||
| `--output` | `test_<name>.py` | Output file path |
|
||||
| `--model` | `qwen3:8b` | Model identifier |
|
||||
| `--engine` | `ollama` | Engine backend |
|
||||
|
||||
## Engine Selection
|
||||
|
||||
=== "Ollama (local)"
|
||||
|
||||
```bash title="Terminal"
|
||||
ollama serve
|
||||
ollama pull qwen3:8b
|
||||
python examples/code_companion/reviewer.py --branch feature-x
|
||||
```
|
||||
|
||||
=== "Cloud API"
|
||||
|
||||
```bash title="Terminal"
|
||||
source .env # load OPENAI_API_KEY or similar
|
||||
python examples/code_companion/reviewer.py \
|
||||
--branch feature-x \
|
||||
--model gpt-4o \
|
||||
--engine cloud
|
||||
```
|
||||
|
||||
## Customization
|
||||
|
||||
### Change the tool set
|
||||
|
||||
Edit the `tools` list in any script to add or remove tools. For example, to let the reviewer also search the web for known security advisories related to dependencies it sees in the diff:
|
||||
|
||||
```python
|
||||
tools = ["git_diff", "git_log", "file_read", "think", "web_search"]
|
||||
```
|
||||
|
||||
### Adjust the prompt
|
||||
|
||||
Each script contains a `prompt` string that instructs the agent what to do and what to produce. Modify it to match your team's conventions — different review sections, specific coding standards, or a particular output format for downstream tooling.
|
||||
|
||||
### Add memory
|
||||
|
||||
For multi-session workflows (e.g., a reviewer that remembers previous assessments of the same files), add `"memory_store"` and `"memory_search"` to the tool list and update the prompt to use them:
|
||||
|
||||
```python
|
||||
tools = ["git_diff", "git_log", "file_read", "think",
|
||||
"memory_store", "memory_search"]
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
- [Architecture: Agents](../architecture/agents.md) — `NativeReActAgent` internals and the Thought-Action-Observation loop
|
||||
- [Architecture: Tools and Memory](../architecture/memory.md) — git tools, file tools, shell tools, and the `ToolExecutor` dispatch pipeline
|
||||
- [Architecture: Security](../architecture/security.md) — RBAC capability policies for `shell_exec` and other privileged tools
|
||||
- [Tutorials: Deep Research Assistant](deep-research.md) — the same SDK pattern with the `OrchestratorAgent` and web/memory tools
|
||||
@@ -0,0 +1,197 @@
|
||||
---
|
||||
title: Deep Research Assistant
|
||||
description: Build a multi-source research agent with memory-augmented orchestration
|
||||
---
|
||||
|
||||
# Deep Research Assistant
|
||||
|
||||
This tutorial walks through `examples/deep_research/research.py` — a standalone script that uses an orchestrator agent to research a topic, gather sources across multiple tool-calling turns, and produce a cited report. It demonstrates how to compose web search, memory, and file output into a single coherent research workflow.
|
||||
|
||||
!!! tip "Prerequisites"
|
||||
- Python 3.10 or later
|
||||
- OpenJarvis installed: run `uv sync --extra dev` from the repository root
|
||||
- An inference engine running — either Ollama locally (see below) or a cloud API key in your `.env` file
|
||||
|
||||
## Quick Start
|
||||
|
||||
Run the research script from the repository root, passing your topic as a positional argument:
|
||||
|
||||
```bash title="Terminal"
|
||||
python examples/deep_research/research.py "quantum computing advances 2026"
|
||||
```
|
||||
|
||||
Save the report to a file:
|
||||
|
||||
```bash title="Terminal"
|
||||
python examples/deep_research/research.py "quantum computing advances 2026" \
|
||||
--output report.md
|
||||
```
|
||||
|
||||
Use a cloud model instead of a local engine:
|
||||
|
||||
```bash title="Terminal"
|
||||
source .env # load API keys
|
||||
python examples/deep_research/research.py "climate policy trends" \
|
||||
--model gpt-4o --engine cloud --max-turns 20
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
The script creates a `Jarvis` instance and delegates the research task to an `OrchestratorAgent` with five tools wired in. The orchestrator iterates through multiple tool-calling turns, deciding at each step whether to search, store, think, or synthesize.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant U as User
|
||||
participant J as Jarvis SDK
|
||||
participant O as OrchestratorAgent
|
||||
participant W as web_search
|
||||
participant T as think
|
||||
participant MS as memory_store
|
||||
participant MQ as memory_search
|
||||
participant F as file_write
|
||||
|
||||
U->>J: research.py "quantum computing"
|
||||
J->>O: ask(prompt, agent="orchestrator", tools=[...])
|
||||
loop Up to max_turns iterations
|
||||
O->>W: search("quantum computing 2026")
|
||||
W-->>O: search results
|
||||
O->>T: think(reasoning about findings)
|
||||
T-->>O: structured thoughts
|
||||
O->>MS: store(key finding)
|
||||
MS-->>O: stored
|
||||
O->>MQ: search(earlier findings)
|
||||
MQ-->>O: related context
|
||||
end
|
||||
O->>F: file_write(report.md)
|
||||
F-->>O: saved
|
||||
O-->>J: final report with citations
|
||||
J-->>U: print report
|
||||
```
|
||||
|
||||
Each turn the orchestrator decides which tool to call based on what it has learned so far. The `think` tool lets the model reason without side effects, while `memory_store` and `memory_search` provide persistent scratch space across turns — so a finding from turn 3 can still inform the synthesis in turn 12.
|
||||
|
||||
## The Script
|
||||
|
||||
```python title="examples/deep_research/research.py" hl_lines="9 10 11 12 13"
|
||||
from openjarvis import Jarvis
|
||||
|
||||
tools = ["web_search", "think", "file_write", "memory_store", "memory_search"]
|
||||
|
||||
j = Jarvis(model="qwen3:8b", engine_key="ollama") # (1)!
|
||||
try:
|
||||
response = j.ask(
|
||||
"Research the following topic in depth and produce a report:\n\nquantum computing",
|
||||
agent="orchestrator", # (2)!
|
||||
tools=tools, # (3)!
|
||||
system_prompt=..., # (4)!
|
||||
max_turns=15, # (5)!
|
||||
temperature=0.5,
|
||||
)
|
||||
finally:
|
||||
j.close()
|
||||
```
|
||||
|
||||
1. Creates a `Jarvis` instance targeting the local Ollama engine with `qwen3:8b`. Both parameters are optional — omitting them uses auto-detected defaults from `~/.openjarvis/config.toml`.
|
||||
2. Selects the `OrchestratorAgent`, which runs a multi-turn tool-calling loop rather than a single round-trip.
|
||||
3. The tool list is passed directly to the agent. All five tools are registered in the tool registry and need no further configuration.
|
||||
4. The system prompt instructs the model to cite sources and distinguish facts from emerging claims.
|
||||
5. The loop terminates after 15 tool-calling turns or when the agent decides it has enough information.
|
||||
|
||||
## Engine Configuration
|
||||
|
||||
=== "Ollama (local)"
|
||||
|
||||
Start the Ollama daemon and pull the model before running the script:
|
||||
|
||||
```bash title="Terminal"
|
||||
ollama serve
|
||||
ollama pull qwen3:8b
|
||||
python examples/deep_research/research.py "your topic here"
|
||||
```
|
||||
|
||||
No flags needed — `--engine ollama` and `--model qwen3:8b` are the defaults.
|
||||
|
||||
=== "Cloud API"
|
||||
|
||||
Set your API key in `.env`, then pass `--engine cloud` and the appropriate model identifier:
|
||||
|
||||
```bash title="Terminal"
|
||||
# .env (in the repository root, gitignored)
|
||||
OPENAI_API_KEY=sk-...
|
||||
|
||||
source .env
|
||||
python examples/deep_research/research.py "your topic" \
|
||||
--model gpt-4o --engine cloud
|
||||
```
|
||||
|
||||
=== "vLLM"
|
||||
|
||||
If you are running a vLLM inference server (e.g., on a multi-GPU node):
|
||||
|
||||
```bash title="Terminal"
|
||||
python examples/deep_research/research.py "your topic" \
|
||||
--model meta-llama/Meta-Llama-3-8B-Instruct \
|
||||
--engine vllm
|
||||
```
|
||||
|
||||
Make sure `VLLM_BASE_URL` is set in `.env` pointing to your vLLM server.
|
||||
|
||||
## Configuration Reference
|
||||
|
||||
| Flag | Default | Description |
|
||||
|---|---|---|
|
||||
| `--model` | `qwen3:8b` | Model identifier passed to the engine |
|
||||
| `--engine` | `ollama` | Engine backend (`ollama`, `cloud`, `vllm`, `llamacpp`, `mlx`) |
|
||||
| `--max-turns` | `15` | Maximum orchestrator loop iterations |
|
||||
| `--output` | (none) | File path to save the final report; if omitted, prints to stdout |
|
||||
|
||||
## Recipe-Driven Configuration
|
||||
|
||||
The companion `research.toml` in `examples/deep_research/` expresses the same setup declaratively. You can load it programmatically with `load_recipe()` and pass the result to `SystemBuilder`:
|
||||
|
||||
```python title="Using the recipe"
|
||||
from openjarvis.recipes import load_recipe
|
||||
from openjarvis import SystemBuilder
|
||||
|
||||
recipe = load_recipe("examples/deep_research/research.toml")
|
||||
system = SystemBuilder(**recipe.to_builder_kwargs()).build()
|
||||
response = system.ask("quantum computing advances 2026")
|
||||
system.close()
|
||||
```
|
||||
|
||||
This is useful when you want to version-control the research configuration, share it with collaborators, or feed it to the `jarvis eval` runner for benchmarking.
|
||||
|
||||
## Customization
|
||||
|
||||
### Swap the agent
|
||||
|
||||
Replace `"orchestrator"` with `"native_react"` for a Thought-Action-Observation loop, or `"native_openhands"` for a CodeAct-style agent that can write and execute code:
|
||||
|
||||
```python
|
||||
response = j.ask(prompt, agent="native_react", tools=tools)
|
||||
```
|
||||
|
||||
### Add more tools
|
||||
|
||||
Append any registered tool name to the `tools` list. For example, to also query a local knowledge base:
|
||||
|
||||
```python
|
||||
tools = ["web_search", "think", "file_write",
|
||||
"memory_store", "memory_search", "knowledge_graph_query"]
|
||||
```
|
||||
|
||||
Run `jarvis agent info orchestrator` to see the full tool catalog.
|
||||
|
||||
### Adjust temperature
|
||||
|
||||
Lower values (0.2) produce more focused, factual reports. Higher values (0.7-0.8) encourage broader exploration and more creative synthesis:
|
||||
|
||||
```bash title="Terminal"
|
||||
python examples/deep_research/research.py "your topic" --max-turns 20
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
- [Architecture: Agents](../architecture/agents.md) — agent hierarchy (`BaseAgent`, `ToolUsingAgent`, `OrchestratorAgent`) and the `accepts_tools` mechanism
|
||||
- [Architecture: Tools and Memory](../architecture/memory.md) — tool registry, MCP adapter, and the `ToolExecutor` dispatch pipeline
|
||||
- [Getting Started: Configuration](../getting-started/configuration.md) — how to configure engines and models in `~/.openjarvis/config.toml`
|
||||
@@ -0,0 +1,62 @@
|
||||
---
|
||||
title: Tutorials
|
||||
description: Step-by-step guides for building with OpenJarvis
|
||||
---
|
||||
|
||||
# Tutorials
|
||||
|
||||
Hands-on guides that walk through building real applications with OpenJarvis. Each tutorial includes a standalone script you can run immediately, a TOML recipe for configuration, and a detailed walkthrough of the concepts involved.
|
||||
|
||||
!!! note "Before you begin"
|
||||
All tutorials assume OpenJarvis is installed and an inference engine is running. If you have not completed setup yet, start with the [Quick Start guide](../getting-started/quickstart.md).
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- :material-magnify:{ .lg .middle } **Deep Research Assistant**
|
||||
|
||||
---
|
||||
|
||||
Multi-source research with a memory-augmented orchestrator agent. Searches the web, stores findings across turns, cross-references sources, and produces a cited report.
|
||||
|
||||
[:octicons-arrow-right-24: Get started](deep-research.md)
|
||||
|
||||
- :material-clock-outline:{ .lg .middle } **Scheduled Personal Ops**
|
||||
|
||||
---
|
||||
|
||||
Autonomous agents on cron schedules for recurring personal tasks — morning news digests, weekly code reviews, and gym schedule checks.
|
||||
|
||||
[:octicons-arrow-right-24: Get started](scheduled-ops.md)
|
||||
|
||||
- :material-message-outline:{ .lg .middle } **Messaging Hub**
|
||||
|
||||
---
|
||||
|
||||
Smart inbox assistant that triages messages by priority, drafts context-aware replies, and produces end-of-day summaries across Slack, WhatsApp, and other channels.
|
||||
|
||||
[:octicons-arrow-right-24: Get started](messaging-hub.md)
|
||||
|
||||
- :material-code-braces:{ .lg .middle } **Code Companion**
|
||||
|
||||
---
|
||||
|
||||
Code review, debugging, and test generation using a ReAct agent that reads source files, runs commands, and reasons step by step before producing structured output.
|
||||
|
||||
[:octicons-arrow-right-24: Get started](code-companion.md)
|
||||
|
||||
</div>
|
||||
|
||||
## What You Will Learn
|
||||
|
||||
Each tutorial demonstrates a different combination of OpenJarvis primitives working together:
|
||||
|
||||
| Tutorial | Agent | Key Primitives |
|
||||
|---|---|---|
|
||||
| Deep Research | `orchestrator` | Engine, Agents, Tools (web + memory), Recipes |
|
||||
| Scheduled Ops | `orchestrator`, `native_react` | Agents, Tools, Scheduler |
|
||||
| Messaging Hub | `orchestrator` | Agents, Tools (memory), Channels |
|
||||
| Code Companion | `native_react` | Agents, Tools (git + file + shell) |
|
||||
|
||||
## Estimated Time
|
||||
|
||||
Each tutorial takes approximately 15-30 minutes to complete end-to-end, including setup and running the scripts. The TOML configuration sections and customization tips are optional reading for when you adapt the pattern to your own use case.
|
||||
@@ -0,0 +1,215 @@
|
||||
---
|
||||
title: Messaging Hub
|
||||
description: Smart inbox with message triage and auto-replies across channels
|
||||
---
|
||||
|
||||
# Messaging Hub
|
||||
|
||||
This tutorial walks through `examples/messaging_hub/smart_inbox.py` — a script that connects OpenJarvis to messaging platforms, triages incoming messages by priority, drafts context-aware replies, and produces end-of-day summaries. It demonstrates channel integration, structured agent output, and memory-backed aggregation across multiple messages.
|
||||
|
||||
!!! tip "Prerequisites"
|
||||
- Python 3.10 or later
|
||||
- OpenJarvis installed: `uv sync --extra dev` from the repository root
|
||||
- An inference engine running (Ollama with `qwen3:8b` pulled, or cloud API keys)
|
||||
- For live channel mode: channel-specific credentials (see [Setting Up Real Channels](#setting-up-real-channels))
|
||||
|
||||
## Quick Start: Demo Mode
|
||||
|
||||
Demo mode processes five sample messages with no channel setup or credentials required. It is the fastest way to see the triage pipeline in action:
|
||||
|
||||
```bash title="Terminal"
|
||||
python examples/messaging_hub/smart_inbox.py --demo
|
||||
```
|
||||
|
||||
Expected output (abbreviated):
|
||||
|
||||
```
|
||||
Smart Inbox — Demo Mode
|
||||
Model: qwen3:8b | Engine: ollama
|
||||
============================================================
|
||||
Processing 5 messages...
|
||||
|
||||
[1/5] Classifying: URGENT: Server is down in production...
|
||||
-> URGENT
|
||||
[2/5] Classifying: Hey, just wanted to share this interest...
|
||||
-> FYI
|
||||
[3/5] Classifying: Can you review my PR #42 by end of day...
|
||||
-> ACTION_REQUIRED
|
||||
[4/5] Classifying: Meeting reminder: Team standup at 10am...
|
||||
-> FYI
|
||||
[5/5] Classifying: Buy now! Limited time offer on premium...
|
||||
-> SPAM
|
||||
|
||||
# Category Message Reply
|
||||
---------------------------------------------------------------
|
||||
1 URGENT URGENT: Server is down... On it — escalating now.
|
||||
2 FYI Hey, just wanted to share... Thanks for sharing!
|
||||
3 ACTION_REQUIRED Can you review my PR #42... Will review before EOD.
|
||||
4 FYI Meeting reminder: Team standup... N/A
|
||||
5 SPAM Buy now! Limited time offer... N/A
|
||||
|
||||
Generating end-of-day summary...
|
||||
```
|
||||
|
||||
Override the model or engine:
|
||||
|
||||
```bash title="Terminal"
|
||||
python examples/messaging_hub/smart_inbox.py --demo --model gpt-4o --engine cloud
|
||||
```
|
||||
|
||||
## How Message Classification Works
|
||||
|
||||
Each incoming message goes through a structured prompt that asks the agent to output exactly two fields — a category and a reply — in a parseable format. The script then extracts those fields and builds a triage table.
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Incoming message] --> B[OrchestratorAgent]
|
||||
B --> C{think tool: internal reasoning}
|
||||
C --> D{memory_store: persist context}
|
||||
D --> E[Structured response]
|
||||
E --> F{Parse CATEGORY and REPLY}
|
||||
F -->|URGENT| G[Flag for immediate attention]
|
||||
F -->|ACTION_REQUIRED| H[Add to action list]
|
||||
F -->|FYI| I[Log for reference]
|
||||
F -->|SPAM| J[Discard]
|
||||
G --> K[Triage table]
|
||||
H --> K
|
||||
I --> K
|
||||
J --> K
|
||||
K --> L[memory_search: cross-reference]
|
||||
L --> M[End-of-day summary]
|
||||
```
|
||||
|
||||
After all messages are processed, a second orchestrator call uses `memory_search` to retrieve the stored triage log and produces a grouped summary with open action items highlighted.
|
||||
|
||||
## The Classification Prompt
|
||||
|
||||
The agent receives a structured prompt that specifies the output format exactly. This makes the response reliably parseable without a complex schema:
|
||||
|
||||
```python title="examples/messaging_hub/smart_inbox.py"
|
||||
CLASSIFICATION_PROMPT = (
|
||||
"You are a smart inbox assistant. Classify the following message into "
|
||||
"exactly one category: URGENT, ACTION_REQUIRED, FYI, or SPAM.\n"
|
||||
"Then draft a short reply if appropriate (not for SPAM).\n\n"
|
||||
"Respond in this exact format:\n"
|
||||
"CATEGORY: <category>\n"
|
||||
"REPLY: <reply or N/A>\n\n"
|
||||
"Message:\n{message}"
|
||||
)
|
||||
```
|
||||
|
||||
The `think` tool lets the agent reason internally before committing to a category, and `memory_store` persists each classification so the summary prompt can reference the full triage log.
|
||||
|
||||
## Setting Up Real Channels
|
||||
|
||||
=== "Slack"
|
||||
|
||||
1. Add the Slack MCP server to your configuration:
|
||||
|
||||
```bash title="Terminal"
|
||||
jarvis add slack
|
||||
```
|
||||
|
||||
2. Set your credentials in `.env` (gitignored):
|
||||
|
||||
```bash title=".env"
|
||||
SLACK_BOT_TOKEN=xoxb-...
|
||||
SLACK_APP_TOKEN=xapp-...
|
||||
```
|
||||
|
||||
3. Invite the bot to the target Slack channel in the Slack workspace settings.
|
||||
|
||||
4. Run the script in live channel mode:
|
||||
|
||||
```bash title="Terminal"
|
||||
python examples/messaging_hub/smart_inbox.py --channel slack
|
||||
```
|
||||
|
||||
=== "WhatsApp"
|
||||
|
||||
1. Ensure Node.js 22 or later is installed.
|
||||
|
||||
2. Configure the WhatsApp Baileys bridge. See the [channel documentation](../architecture/overview.md) for full setup steps.
|
||||
|
||||
3. Start the bridge — it will print a QR code. Scan it with the WhatsApp mobile app to authenticate.
|
||||
|
||||
4. Run the script:
|
||||
|
||||
```bash title="Terminal"
|
||||
python examples/messaging_hub/smart_inbox.py --channel whatsapp
|
||||
```
|
||||
|
||||
=== "Other Channels"
|
||||
|
||||
OpenJarvis supports LINE, Viber, Mastodon, Rocket.Chat, Zulip, XMPP, Twitch, Nostr, and more. List all available channels:
|
||||
|
||||
```bash title="Terminal"
|
||||
jarvis channel list
|
||||
jarvis channel status
|
||||
```
|
||||
|
||||
Each channel requires its own environment variables. Run `jarvis add <channel>` where available to auto-generate the configuration template.
|
||||
|
||||
!!! warning "Live channel mode"
|
||||
Live channel mode requires channel credentials and the corresponding channel subsystem to be running. Use `--demo` to verify the triage logic before connecting to a real channel.
|
||||
|
||||
## Channel Configuration via TOML
|
||||
|
||||
The `messaging.toml` recipe in `examples/messaging_hub/` captures the agent and channel defaults declaratively:
|
||||
|
||||
```toml title="examples/messaging_hub/messaging.toml"
|
||||
[channel]
|
||||
default = "slack"
|
||||
|
||||
[agent]
|
||||
type = "orchestrator"
|
||||
max_turns = 5
|
||||
temperature = 0.3
|
||||
tools = ["think", "memory_store", "memory_search"]
|
||||
```
|
||||
|
||||
You can load this recipe programmatically:
|
||||
|
||||
```python title="Loading the messaging recipe"
|
||||
from openjarvis.recipes import load_recipe
|
||||
from openjarvis import SystemBuilder
|
||||
|
||||
recipe = load_recipe("examples/messaging_hub/messaging.toml")
|
||||
system = SystemBuilder(**recipe.to_builder_kwargs()).build()
|
||||
response = system.ask(CLASSIFICATION_PROMPT.format(message=incoming_message))
|
||||
system.close()
|
||||
```
|
||||
|
||||
## Adding Custom Triage Rules
|
||||
|
||||
Extend the classification categories by editing `CLASSIFICATION_PROMPT`. For example, to add a `FOLLOW_UP` category for messages that need a response within 48 hours:
|
||||
|
||||
```python title="Custom classification prompt" hl_lines="2"
|
||||
CLASSIFICATION_PROMPT = (
|
||||
"Classify into: URGENT, ACTION_REQUIRED, FOLLOW_UP, FYI, or SPAM.\n"
|
||||
"Then draft a short reply if appropriate (not for SPAM).\n\n"
|
||||
"Respond in this exact format:\n"
|
||||
"CATEGORY: <category>\n"
|
||||
"REPLY: <reply or N/A>\n\n"
|
||||
"Message:\n{message}"
|
||||
)
|
||||
```
|
||||
|
||||
You can also add domain rules in the system prompt via `messaging.toml` — for instance, routing any message containing "P0" or "incident" directly to URGENT regardless of phrasing.
|
||||
|
||||
## Scheduling the Daily Summary
|
||||
|
||||
After processing all messages, the end-of-day summary call runs immediately in the script. For production use, schedule it independently via the OpenJarvis scheduler:
|
||||
|
||||
```bash title="Terminal"
|
||||
jarvis scheduler create "Daily inbox summary" \
|
||||
--type cron --value "0 17 * * *"
|
||||
```
|
||||
|
||||
Or use the operator recipe pattern to run a persistent triage agent on a schedule. See the operator recipes in `src/openjarvis/recipes/data/operators/` for ready-made examples.
|
||||
|
||||
## See Also
|
||||
|
||||
- [Architecture: Agents](../architecture/agents.md) — `OrchestratorAgent` and the multi-turn tool loop
|
||||
- [Architecture: Tools and Memory](../architecture/memory.md) — `memory_store`, `memory_search`, and the storage backends
|
||||
- [Tutorials: Scheduled Personal Ops](scheduled-ops.md) — combining scripts with the cron scheduler
|
||||
@@ -0,0 +1,215 @@
|
||||
---
|
||||
title: Scheduled Personal Ops
|
||||
description: Run autonomous agents on cron schedules for recurring personal tasks
|
||||
---
|
||||
|
||||
# Scheduled Personal Ops
|
||||
|
||||
This tutorial walks through `examples/scheduled_ops/` — three scripts that run autonomous agents on cron-like schedules to handle recurring personal tasks. Together they demonstrate how to combine the `Jarvis` SDK, the scheduler CLI, and the Python `TaskScheduler` API to build a personal operations layer that runs in the background.
|
||||
|
||||
!!! tip "Prerequisites"
|
||||
- Python 3.10 or later
|
||||
- OpenJarvis installed: `uv sync --extra dev` from the repository root
|
||||
- An inference engine running (Ollama with `qwen3:8b` pulled, or a cloud API key)
|
||||
- For full cron expression support, install `croniter`: `uv add croniter`
|
||||
|
||||
## The Three Scripts
|
||||
|
||||
| Script | Agent | Tools | Default Schedule | Purpose |
|
||||
|---|---|---|---|---|
|
||||
| `daily_digest.py` | `orchestrator` | `web_search`, `think` | Daily 9:00 AM | Search and summarize top news for chosen topics |
|
||||
| `code_review.py` | `native_react` | `git_log`, `git_diff`, `file_read`, `think` | Monday 8:00 AM | Review the past week of commits in a repository |
|
||||
| `gym_scheduler.py` | `orchestrator` | `web_search`, `think` | MWF 6:00 AM | Check gym hours and class availability |
|
||||
|
||||
Each script follows the same SDK pattern: create a `Jarvis` instance, call `j.ask()` with an agent and tools, print the result, and close the instance. The schedule is managed externally by the OpenJarvis scheduler daemon.
|
||||
|
||||
## Quick Start: Run Scripts Manually
|
||||
|
||||
Test each script without a running scheduler by invoking it directly:
|
||||
|
||||
```bash title="Terminal"
|
||||
# Morning news digest for AI and robotics
|
||||
uv run python examples/scheduled_ops/daily_digest.py --topics "AI,robotics"
|
||||
|
||||
# Code review for the current repository (last 7 days of commits)
|
||||
uv run python examples/scheduled_ops/code_review.py --repo-path .
|
||||
|
||||
# Gym schedule check
|
||||
uv run python examples/scheduled_ops/gym_scheduler.py --gym "24 Hour Fitness"
|
||||
```
|
||||
|
||||
All scripts accept `--model` and `--engine` flags:
|
||||
|
||||
```bash title="Terminal"
|
||||
uv run python examples/scheduled_ops/daily_digest.py \
|
||||
--model qwen3:8b --engine ollama --topics "AI,finance"
|
||||
```
|
||||
|
||||
## How the Scheduler Works
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[jarvis scheduler start] --> B[Scheduler Daemon]
|
||||
B --> C{Cron trigger fires}
|
||||
C -->|0 9 * * *| D[daily_digest.py]
|
||||
C -->|0 8 * * 1| E[code_review.py]
|
||||
C -->|0 6 * * 1,3,5| F[gym_scheduler.py]
|
||||
D --> G[OrchestratorAgent]
|
||||
E --> H[NativeReActAgent]
|
||||
F --> G
|
||||
G --> I[web_search + think]
|
||||
H --> J[git_diff + git_log + file_read + think]
|
||||
I --> K[Output / Channel]
|
||||
J --> K
|
||||
```
|
||||
|
||||
The scheduler daemon reads registered tasks from SQLite, fires them at the correct time, and passes the configured prompt to the agent. Each script can also be run directly — the scheduler is only needed for recurring, unattended operation.
|
||||
|
||||
## Set Up Schedules with the CLI
|
||||
|
||||
Register each script as a recurring task using `jarvis scheduler create`:
|
||||
|
||||
```bash title="Terminal"
|
||||
# Morning digest every day at 9 AM
|
||||
jarvis scheduler create "Run daily news digest" \
|
||||
--type cron --value "0 9 * * *"
|
||||
|
||||
# Weekly code review every Monday at 8 AM
|
||||
jarvis scheduler create "Run weekly code review" \
|
||||
--type cron --value "0 8 * * 1"
|
||||
|
||||
# Gym check on Monday, Wednesday, Friday at 6 AM
|
||||
jarvis scheduler create "Check gym schedule" \
|
||||
--type cron --value "0 6 * * 1,3,5"
|
||||
```
|
||||
|
||||
Then start the scheduler daemon in the foreground (or as a background service):
|
||||
|
||||
```bash title="Terminal"
|
||||
jarvis scheduler start
|
||||
```
|
||||
|
||||
List registered tasks at any time:
|
||||
|
||||
```bash title="Terminal"
|
||||
jarvis scheduler list
|
||||
```
|
||||
|
||||
!!! note "Cron expression syntax"
|
||||
OpenJarvis uses standard five-field cron syntax: `minute hour day-of-month month day-of-week`. Install `croniter` (`uv add croniter`) for full expression support including ranges and step values. Without it, basic `hour:minute` patterns still work.
|
||||
|
||||
## Configure Schedules with TOML
|
||||
|
||||
The `schedules.toml` file in `examples/scheduled_ops/` defines all three schedules declaratively. This is convenient for version-controlling your personal ops configuration or sharing it across machines:
|
||||
|
||||
```toml title="examples/scheduled_ops/schedules.toml"
|
||||
[schedules.daily_digest]
|
||||
type = "cron"
|
||||
value = "0 9 * * *"
|
||||
description = "Morning news and social media digest"
|
||||
script = "daily_digest.py"
|
||||
|
||||
[schedules.code_review]
|
||||
type = "cron"
|
||||
value = "0 8 * * 1"
|
||||
description = "Weekly code review"
|
||||
script = "code_review.py"
|
||||
|
||||
[schedules.gym_scheduler]
|
||||
type = "cron"
|
||||
value = "0 6 * * 1,3,5"
|
||||
description = "Gym hours and class check"
|
||||
script = "gym_scheduler.py"
|
||||
```
|
||||
|
||||
Point your own tooling or a custom loader at this file to register tasks in bulk.
|
||||
|
||||
## Register Tasks via the Python API
|
||||
|
||||
The `gym_scheduler.py` script includes a `--register` flag that demonstrates programmatic task registration using `TaskScheduler` directly:
|
||||
|
||||
```bash title="Terminal"
|
||||
uv run python examples/scheduled_ops/gym_scheduler.py \
|
||||
--register --gym "Planet Fitness"
|
||||
```
|
||||
|
||||
The equivalent Python code:
|
||||
|
||||
```python title="Programmatic task registration"
|
||||
from openjarvis.scheduler import TaskScheduler
|
||||
from openjarvis.scheduler.store import SchedulerStore
|
||||
|
||||
store = SchedulerStore()
|
||||
scheduler = TaskScheduler(store)
|
||||
|
||||
task = scheduler.create_task( # (1)!
|
||||
prompt="Check gym schedule for 'Planet Fitness'",
|
||||
schedule_type="cron",
|
||||
schedule_value="0 6 * * 1,3,5",
|
||||
agent="orchestrator",
|
||||
tools="web_search,think",
|
||||
)
|
||||
print(f"Task registered: {task.id}")
|
||||
print(f"Next run: {task.next_run}")
|
||||
```
|
||||
|
||||
1. `create_task()` persists the task to SQLite and computes the next trigger time. The scheduler daemon picks it up without a restart.
|
||||
|
||||
## The Daily Digest Script
|
||||
|
||||
The digest script is the simplest of the three. It builds a date-stamped prompt and passes it to an orchestrator with `web_search` and `think`:
|
||||
|
||||
```python title="examples/scheduled_ops/daily_digest.py" hl_lines="5 6 7 8"
|
||||
from openjarvis import Jarvis
|
||||
|
||||
j = Jarvis() # uses defaults from ~/.openjarvis/config.toml
|
||||
response = j.ask(
|
||||
f"Today is {today}. Search and summarize the top news on: {topics}",
|
||||
agent="orchestrator",
|
||||
tools=["web_search", "think"],
|
||||
)
|
||||
j.close()
|
||||
```
|
||||
|
||||
The orchestrator searches for each topic in a separate turn, uses `think` to synthesize across topics, and returns a structured digest with bullet-point summaries and a one-paragraph outlook.
|
||||
|
||||
## Send Results to a Channel
|
||||
|
||||
To route script output to Slack or any other supported channel, pipe stdout through `jarvis channel send`:
|
||||
|
||||
```bash title="Terminal"
|
||||
uv run python examples/scheduled_ops/daily_digest.py \
|
||||
--topics "AI,finance" | jarvis channel send slack
|
||||
```
|
||||
|
||||
Or add channel output inside the script:
|
||||
|
||||
```python title="In-script channel output"
|
||||
from openjarvis.channels import ChannelRegistry
|
||||
|
||||
channel = ChannelRegistry.create("slack", webhook_url="https://hooks.slack.com/...")
|
||||
channel.send(response)
|
||||
```
|
||||
|
||||
List all available channels:
|
||||
|
||||
```bash title="Terminal"
|
||||
jarvis channel list
|
||||
```
|
||||
|
||||
!!! warning "Channel credentials"
|
||||
Live channel output requires channel-specific credentials. Run `jarvis add slack` (or the relevant provider) to set up the MCP server and credential store, then configure environment variables in your `.env` file before starting the scheduler daemon.
|
||||
|
||||
## Customization Tips
|
||||
|
||||
- **Change topics**: Pass `--topics "finance,healthcare,sports"` to `daily_digest.py` for a different digest.
|
||||
- **Review window**: Pass `--days 14` to `code_review.py` for a two-week review cycle instead of one week.
|
||||
- **Swap agents**: Replace `orchestrator` with `native_react` in any script to compare agent behavior on the same task.
|
||||
- **Add file output**: Append `"file_write"` to the `tools` list and update the prompt to save reports to disk instead of printing them.
|
||||
- **One-time tasks**: Use `--type once --value "2026-04-01T09:00:00"` with `jarvis scheduler create` for non-recurring tasks.
|
||||
|
||||
## See Also
|
||||
|
||||
- [Architecture: Agents](../architecture/agents.md) — `OrchestratorAgent` and `NativeReActAgent` internals
|
||||
- [Architecture: Tools and Memory](../architecture/memory.md) — tool registry and `ToolExecutor`
|
||||
- [Getting Started: Configuration](../getting-started/configuration.md) — engine and model defaults
|
||||
Reference in New Issue
Block a user