# langchain-deepsigma

LangChain integration for **Σ OVERWATCH** — governed, auditable LangChain chains and agents.

Every chain run becomes a sealed **Decision Episode** recorded through the full
DLR / RS / DS / MG governance pipeline.

---

## Install

```bash
# 1. Install the parent deepsigma package first
pip install -e /path/to/DeepSigma-v0.3.0

# 2. Install this package
pip install -e /path/to/DeepSigma-v0.3.0/packages/langchain-deepsigma
```

---

## Three Integration Surfaces

### 1. Callbacks — Automatic Governance

Drop `DeepSigmaCallbackHandler` into any chain or agent. Every run is automatically
wrapped in a sealed Decision Episode.

```python
from langchain_deepsigma import DeepSigmaCallbackHandler

handler = DeepSigmaCallbackHandler(decision_type="CustomerSupportChain")

# Use with any LangChain chain
result = chain.invoke(
    {"input": "What is the refund policy?"},
    config={"callbacks": [handler]},
)

# After the run, governance artifacts are available:
print(handler.episode)          # sealed episode dict
print(handler.dlr.to_dict_list())  # Decision Log Records
print(handler.rs.summarise())   # Reflection Session summary
print(handler.ds.summarise())   # Drift signals (if any errors occurred)
print(handler.mg.node_count)    # Memory Graph node count
```

### 2. Tools — Governance as Agent Capabilities

Give your agent the ability to query its own governance state.

```python
from langchain_deepsigma import deepsigma_tools, DeepSigmaCallbackHandler

handler = DeepSigmaCallbackHandler()
chain.invoke(..., config={"callbacks": [handler]})

# Wire the post-run governance state to tools
tools = deepsigma_tools(mg=handler.mg, dlr=handler.dlr)

# Bind to an agent
agent = create_tool_calling_agent(llm, tools, prompt)
```

**Available tools:**

| Tool | Name | What it does |
|------|------|-------------|
| `IRISQueryTool` | `iris_query` | WHY / WHAT_DRIFTED / STATUS / RECALL / WHAT_CHANGED |
| `CoherenceScorerTool` | `coherence_score` | Score episodes 0–100 (A–F) |
| `AuditTool` | `coherence_audit` | Cross-artifact consistency audit |
| `ReconcilerTool` | `coherence_reconcile` | Detect inconsistencies, propose repairs |

```python
# Use tools individually
from langchain_deepsigma import IRISQueryTool, CoherenceScorerTool
import json

iris = IRISQueryTool(mg=handler.mg)
print(iris._run(query_type="STATUS"))
# [IRIS STATUS] Status: RESOLVED
# Summary: Health: green. No drift detected. Claims: 3.

scorer = CoherenceScorerTool()
print(scorer._run(episodes=json.dumps(episodes)))
# Coherence Score: 91.2/100  Grade: A
# Dimensions:
#   policy_adherence          95.0  (weight 25%)
#   outcome_health            88.0  (weight 30%)
#   ...
```

### 3. Memory — Decision History in Prompts

Use the Memory Graph as a LangChain memory provider.

```python
from langchain_deepsigma import DeepSigmaMemory
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

memory = DeepSigmaMemory(top_k=5)

prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant. Here is relevant decision history:\n{decision_history}"),
    ("human", "{input}"),
])

chain = prompt | llm

# Each turn:
history = memory.load_memory_variables({"input": user_input})
response = chain.invoke({"input": user_input, **history})
memory.save_context({"input": user_input}, {"output": response.content})
```

#### Share a Memory Graph between handler and memory

```python
from coherence_ops import MemoryGraph

shared_mg = MemoryGraph()
handler = DeepSigmaCallbackHandler()
handler.mg = shared_mg
memory = DeepSigmaMemory(mg=shared_mg)

# Now both the chain's episodes AND saved memory turns live in one graph
```

---

## Full Example

```python
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_deepsigma import DeepSigmaCallbackHandler, DeepSigmaMemory, deepsigma_tools

llm = ChatOpenAI(model="gpt-4o-mini")
memory = DeepSigmaMemory(top_k=3)

prompt = ChatPromptTemplate.from_messages([
    ("system", "Decision history:\n{decision_history}"),
    ("human", "{input}"),
])

chain = prompt | llm

for user_input in ["What's the plan?", "Confirm deployment", "Roll back if needed"]:
    handler = DeepSigmaCallbackHandler(decision_type="OpsDecision")
    history = memory.load_memory_variables({"input": user_input})
    response = chain.invoke(
        {"input": user_input, **history},
        config={"callbacks": [handler]},
    )
    memory.save_context({"input": user_input}, {"output": response.content})
    print(f"Grade: {handler.dlr.to_dict_list()[0].get('outcomeCode', 'N/A')}")
```

---

## Tests

```bash
cd /path/to/DeepSigma-v0.3.0
pytest packages/langchain-deepsigma/tests/ -v
```

---

## Package Structure

```
langchain-deepsigma/
├── pyproject.toml
├── README.md
├── langchain_deepsigma/
│   ├── __init__.py       # Public exports
│   ├── callbacks.py      # DeepSigmaCallbackHandler
│   ├── tools.py          # Four governance tools + deepsigma_tools()
│   └── memory.py         # DeepSigmaMemory
└── tests/
    ├── test_callbacks.py
    ├── test_tools.py
    └── test_memory.py
```

---

**Σ OVERWATCH** — *We don't sell agents. We sell the ability to trust them.*
