Skip to content

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.

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:

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:

Core SDK pattern
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.

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.

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.

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.

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.

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.

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

Terminal
ollama serve
ollama pull qwen3:8b
python examples/code_companion/reviewer.py --branch feature-x
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:

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:

tools = ["git_diff", "git_log", "file_read", "think",
         "memory_store", "memory_search"]

See Also