Skip to content

hartungsol/Rational_agent

Repository files navigation

Rational Agent

A Pollock-style Normative Defeasible Engine (NDE) for defeasible reasoning, with LLM-assisted argument generation and defeat discovery.

Overview

This project implements a computational model of defeasible reasoning based on John Pollock's philosophical work on epistemology and argumentation theory. The system maintains a strict separation between:

  • Normative Core: The NDE is the sole authority on defeat status and warrant
  • Heuristic Agents: Generate candidate arguments and defeaters (including LLM-assisted)
  • Environment: External source of evidence and interests

Key features:

  • Incremental fixpoint computation for defeat status
  • Support for rebutting and undercutting defeaters
  • Epistemic interest management
  • LLM integration (Ollama) for defeater generation
  • Optional LangChain integration for retrieval-augmented reasoning
  • SQLite + JSON persistence for snapshots and audit trails
  • Event-driven architecture with pluggable environments

Architecture

┌─────────────────────────────────────────────────────────────────┐
│                         Runtime Layer                           │
│  ┌─────────────┐  ┌─────────────┐  ┌────────────────────────┐  │
│  │   Daemon    │  │  EventBus   │  │     Environment        │  │
│  │  (Control)  │◄─┤   (I/O)     │◄─┤  (Exogenous Events)    │  │
│  └──────┬──────┘  └─────────────┘  └────────────────────────┘  │
│         │                                                      │
│         ▼                                                      │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                    Agent Layer                          │   │
│  │  ┌────────────┐ ┌─────────────┐ ┌───────────────────┐  │   │
│  │  │  Support   │ │  Defeater   │ │   Undercutter     │  │   │
│  │  │   Agent    │ │   Hunter    │ │     Agent         │  │   │
│  │  └────────────┘ └─────────────┘ └───────────────────┘  │   │
│  │  ┌────────────┐ ┌─────────────┐                        │   │
│  │  │   Info     │ │  Explainer  │                        │   │
│  │  │  Seeker    │ │  Service    │                        │   │
│  │  └────────────┘ └─────────────┘                        │   │
│  └─────────────────────────────────────────────────────────┘  │
│                              │                                 │
│                              ▼                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │              Normative Core (NDE)                       │   │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐   │   │
│  │  │  Argument    │  │    Defeat    │  │   Epistemic  │   │   │
│  │  │    Graph     │  │   Operator   │  │   Interests  │   │   │
│  │  └──────────────┘  └──────────────┘  └──────────────┘   │   │
│  └─────────────────────────────────────────────────────────┘   │
│                              │                                 │
│                              ▼                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                     LLM Layer                           │   │
│  │  ┌──────────────────┐  ┌─────────────────────────────┐  │   │
│  │  │   OllamaClient   │  │   LangChainAdapter          │  │   │
│  │  │  (Defeaters)     │  │   (Retrieval, optional)     │  │   │
│  │  └──────────────────┘  └─────────────────────────────┘  │   │
│  └─────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘

Project Structure

Rational_agent/
├── core/                    # Normative reasoning core
│   ├── nde.py              # Normative Defeasible Engine
│   ├── graph.py            # Argument graph with defeat edges
│   ├── formulas.py         # Propositional formula representation
│   ├── interests.py        # Epistemic interest tracking
│   ├── reasons.py          # Pollock-style reason schemas
│   └── belief_store.py     # Belief state projection
│
├── agents/                  # Heuristic agents (non-normative)
│   ├── base.py             # Agent protocol and context
│   ├── prediction.py       # SimpleSupportAgent
│   ├── defeater_hunter.py  # SimpleDefeaterHunterAgent (rebutters)
│   ├── undercutter_agent.py# SimpleUndercutterAgent (LLM-based)
│   ├── info_seeker.py      # InfoSeekerAgent (LLM-based)
│   └── explainer.py        # ExplanationService
│
├── runtime/                 # Execution infrastructure
│   ├── daemon.py           # Main control loop
│   ├── events.py           # Event model and EventBus
│   ├── inference_queue.py  # Agent scheduler
│   ├── persistence.py      # SQLite + JSON snapshots
│   └── logger.py           # Centralized logging
│
├── environment/             # External event sources
│   └── __init__.py         # Environment, ScriptedEnvironment
│
├── llm/                     # LLM integration
│   ├── ollama_client.py    # Ollama API client
│   ├── langchain_adapter.py# Optional LangChain wrapper
│   └── prompts/            # Prompt templates (placeholder)
│
├── scripts/                 # Entry points
│   ├── run_local.py        # Demo runner
│   ├── plan_checker.py     # Interactive plan feasibility checker
│   └── query_explanations.py
│
├── data/                    # Runtime data (gitignored)
│   └── chroma_index/       # Chroma vector store for retrieval
│
├── tests/                   # Unit tests
│   ├── test_defeat_fixpoint.py
│   ├── test_reinstatement.py
│   └── test_interest_control.py
│
├── pyproject.toml           # Project metadata (PEP 621)
├── requirements.txt         # Python dependencies
└── LICENSE                  # Apache License 2.0

Core Concepts

Defeat Status

Each node (argument) in the graph has a status:

  • UNDEFEATED (U): The argument currently stands
  • DEFEATED (D): At least one undefeated defeater exists

The defeat operator:

status(a) = DEFEATED    if ∃b: b defeats a ∧ status(b) = UNDEFEATED
            UNDEFEATED  otherwise

Defeat Types

The system distinguishes two types of defeat (following Pollock):

Type Description Example
REBUT Attacks the conclusion directly "It is not raining" defeats "It is raining"
UNDERCUT Attacks the inference from premises to conclusion "The sensor is unreliable" defeats the inference from sensor reading to conclusion

Reinstatement

A defeated argument can be reinstated if all its defeaters become defeated:

A: "It rained" (initially undefeated)
B: "The sprinklers ran" defeats A → A becomes DEFEATED
C: "The sprinklers are broken" defeats B → B becomes DEFEATED → A is REINSTATED

Epistemic Interests

Interests represent queries the system cares about:

  • ACTIVE: The system should reason about this
  • RESOLVED: A warranted answer has been found
  • CANCELLED: No longer relevant

Installation

# Clone the repository
git clone <repo-url>
cd Rational_agent

# Create and activate a virtual environment
python -m venv venv
source venv/bin/activate  # Linux/macOS
# or: venv\Scripts\activate  # Windows

# Install dependencies
pip install -r requirements.txt

Optional: Ollama for LLM-based Agents

The undercutter and info-seeker agents use a local Ollama server:

# Install Ollama (see https://ollama.ai)
# Then pull a model:
ollama pull llama3.2

# Set environment variables (optional)
export OLLAMA_MODEL=llama3.2
export OLLAMA_BASE_URL=http://localhost:11434

Optional: LangChain + Chroma for Retrieval

The plan checker and defeater hunter agents support retrieval-augmented generation using LangChain with Chroma as the vector store:

pip install langchain langchain-community chromadb sentence-transformers

To use retrieval, you'll need a Chroma index at data/chroma_index/. You can build one by indexing your domain documents (see scripts/build_retriever.py for a template).

Usage

Running the Demo

PYTHONPATH=. python scripts/run_local.py

This will:

  1. Create an NDE with an initial interest ("Sky is blue")
  2. Run agents that add supporting arguments and generate defeaters
  3. Process defeat status updates incrementally
  4. Print the belief state at each step
  5. Save snapshots to data/snapshots/ and data/nde_snapshots.db

Plan Checker (Interactive)

The plan checker is an interactive tool that evaluates the feasibility of user-submitted plans using defeasible reasoning:

PYTHONPATH=. python -m scripts.plan_checker

Features:

  • Registers a plan as an epistemic interest and asserts provisional success
  • Runs multiple reasoning ticks (agents generate defeaters and counter-defeaters)
  • Uses LangChain + Chroma for retrieval-augmented defeater generation
  • Outputs a verdict (provisionally-feasible or currently-defeated)
  • Provides both text and structured JSON explanations with full defeat trees

Example session:

Plan: I plan on quitting my job and becoming a day trader with no experience.

Verdict: currently-defeated (node status = D)

Explanation (text):
Node plan-success is D – undefeated defeater exists.
Defeaters:
  - def-plan-success-bf65806d (rebut, status=U): 'Lack of experience and
    training in day trading typically results in significant financial loss...'

Programmatic Usage

from core.formulas import Formula
from core.graph import ArgumentGraph
from core.nde import NormativeDefeasibleEngine

# Create the engine
graph = ArgumentGraph()
nde = NormativeDefeasibleEngine(graph=graph)

# Add premises
nde.add_premise("A", Formula("It is raining"))
nde.add_premise("B", Formula("It is not raining"))

# Declare defeat
nde.add_defeat("B", "A")

# Compute defeat status
nde.process_pending_updates()

# Query status
print(nde.is_undefeated("A"))  # False
print(nde.is_undefeated("B"))  # True

# Get explanation
print(nde.explain_status("A"))

Creating Interests and Using Agents

from agents.base import AgentContext
from agents.prediction import SimpleSupportAgent
from core.belief_store import BeliefStore

# Create context
belief_store = BeliefStore(nde.graph)
ctx = AgentContext(nde=nde, graph=nde.graph, belief_store=belief_store)

# Create an interest
phi = Formula("The sky is blue")
nde.create_interest("I1", phi, priority=1.0)

# Create and run an agent
agent = SimpleSupportAgent("supporter", ctx)
agent.step()  # Adds a premise supporting the interest

# Update and check
nde.process_pending_updates()
nde.update_interests()
print(nde.is_formula_warranted(phi))  # True

Testing

PYTHONPATH=. pytest tests/ -v

Key APIs

NormativeDefeasibleEngine

Method Description
add_premise(id, formula) Add a bare premise node
add_argument(id, formula, premise_ids) Add an argument with premises
add_defeat(defeater, target, defeat_type) Declare a defeat relation
process_pending_updates() Compute defeat statuses
is_undefeated(node_id) Check if a node is undefeated
is_formula_warranted(formula) Check if any undefeated node concludes formula
create_interest(id, formula, ...) Register an epistemic interest
update_interests() Resolve interests based on warrant
explain_status(node_id) Human-readable status explanation
explain_status_dict(node_id) JSON-serializable explanation
explain_status_tree(node_id, max_depth) Recursive defeat tree

Agents

Agent Purpose
SimpleSupportAgent Adds premises supporting active interests
SimpleDefeaterHunterAgent Generates rebutting defeaters (synthetic negation)
SimpleUndercutterAgent Uses LLM to generate undercutting defeaters
InfoSeekerAgent Uses LLM to propose information needs as sub-interests
ExplanationService Provides structured explanations for nodes and interests

Design Principles

  1. Normative Separation: Only the NDE assigns defeat status. Agents propose; the NDE decides.

  2. Incremental Fixpoint: Status is computed incrementally via a worklist algorithm, not recomputed globally.

  3. Observational Logging: Logging never affects reasoning or control flow.

  4. LLM as Heuristic: LLMs generate candidate defeaters and questions—they don't determine warrant.

  5. Event-Driven: External inputs come through an EventBus; the Environment is the source of exogenous events.

  6. Persistence for Audit: Snapshots and events are persisted for debugging and reproducibility.

References

  • Pollock, J. L. (1995). Cognitive Carpentry: A Blueprint for How to Build a Person. MIT Press.
  • Pollock, J. L. (1987). Defeasible Reasoning. Cognitive Science, 11(4), 481–518.
  • Pollock, J. L. (2001). Defeasible Reasoning with Variable Degrees of Justification. Artificial Intelligence, 133(1-2), 233–282.

License

Copyright 2025 Robert J. Hartung III

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the LICENSE file for the specific language governing permissions and limitations under the License.

About

A Pollock-style Normative Defeasible Engine (NDE) for defeasible reasoning, with LLM-assisted argument generation and defeat discovery.

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages