Metadata-Version: 2.4
Name: autourgos-history
Version: 1.0.0
Summary: Agent execution history middleware for Autourgos — logs every thought, tool call, and observation to Markdown and JSON files with automatic sensitive-data redaction
Author-email: Jitin Kumar Sengar <devxjitin@gmail.com>
License: MIT License
        
        Copyright (c) 2026 Jitin Kumar Sengar
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/autourgos/autourgos-history
Project-URL: Repository, https://github.com/autourgos/autourgos-history
Project-URL: Issues, https://github.com/autourgos/autourgos-history/issues
Keywords: autourgos,agent,history,logging,middleware,audit,tracing,react,llm,ai
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Logging
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: react
Requires-Dist: autourgos-react-agent>=1.0.0; extra == "react"
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: autourgos-react-agent>=1.0.0; extra == "dev"
Requires-Dist: autourgos-openaichat>=1.0.0; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Dynamic: license-file

# autourgos-history

Agent execution history middleware for the Autourgos framework.

Attach it to any Autourgos agent and every run is automatically recorded:
every **Thought**, every **Tool Call**, every **Observation**, and the **Final Answer** — written to a Markdown file and a structured JSON file.

Sensitive values (API keys, tokens, passwords) are **automatically redacted** before writing.

Zero required dependencies. Pure Python 3.10+.

---

## Why use this?

When you build agents, you need to know what they did. This middleware gives you a complete, readable audit trail of every agent run without adding any code to your agent logic.

- **Debug** — see exactly where the agent went wrong
- **Audit** — keep records of every tool call and its inputs
- **Monitor** — review agent reasoning in plain English
- **Privacy** — choose exactly what gets logged with per-field flags

---

## Table of Contents

- [Install](#install)
- [Quick Start](#quick-start)
- [Output Files](#output-files)
- [Privacy Controls](#privacy-controls)
- [Custom File Location](#custom-file-location)
- [Using with ReactAgent](#using-with-reactagent)
- [Using with Any Agent](#using-with-any-agent)
- [Flushing Logs](#flushing-logs)
- [Constructor Reference](#constructor-reference)
- [Markdown Output Format](#markdown-output-format)
- [JSON Output Format](#json-output-format)
- [Redaction Rules](#redaction-rules)
- [Thread Safety](#thread-safety)

---

## Install

```bash
pip install autourgos-history
```

Requires Python 3.10+. No other dependencies.

---

## Quick Start

```python
from autourgos_history     import AgentHistoryMiddleware
from autourgos_react_agent import ReactAgent
from autourgos_openaichat  import OpenAIChatModel

history = AgentHistoryMiddleware(
    include_query=True,
    include_tools=True,
    include_observations=True,
    include_final=True,
)

agent = ReactAgent(
    llm=OpenAIChatModel(model="gpt-4o"),
    middleware=[history],
)
agent.add_tools(my_tool)

result = agent.invoke("What is the weather in Tokyo?")
print(result)
# The weather in Tokyo is 22°C and sunny.
```

After the run, two files appear in `./Agent History/`:

```
Agent History/
├── Task_20260616_120000_abc12345.md    ← human-readable Markdown
└── Task_20260616_120000_abc12345.json  ← structured JSON
```

---

## Output Files

### Markdown file (`.md`)

Human-readable. Open in any editor or Markdown viewer.

```markdown
# Task Session: ReactAgent
**Started At:** 2026-06-16 12:00:00

## Initial Query
What is the weather in Tokyo?

---

## Iteration 1

### Thought
I need to call the get_weather tool to find the weather in Tokyo.

### Action (Tools)
**Tool:** `get_weather`
**Parameters:**
```json
{
  "city": "Tokyo",
  "unit": "celsius"
}
```

### Observations
**get_weather**:
"The weather in Tokyo is 22°C and sunny."

---

## Final Answer
The weather in Tokyo is 22°C and sunny.
```

### JSON file (`.json`)

Structured. Use for programmatic processing, dashboards, or storage.

```json
{
  "query": "What is the weather in Tokyo?",
  "agent_name": "ReactAgent",
  "start_time": "2026-06-16T12:00:00.123456",
  "end_time":   "2026-06-16T12:00:02.456789",
  "iterations": [
    {
      "iteration": 1,
      "thought": "I need to call the get_weather tool...",
      "tools": [
        {"tool": "get_weather", "params": {"city": "Tokyo", "unit": "celsius"}}
      ],
      "observations": [
        {"tool": "get_weather", "result": "The weather in Tokyo is 22°C and sunny."}
      ]
    }
  ],
  "final_response": "The weather in Tokyo is 22°C and sunny.",
  "error": null
}
```

---

## Privacy Controls

By default, content is redacted — you see the structure but not the values. Enable fields individually:

```python
history = AgentHistoryMiddleware(
    include_query=False,        # user query    → [REDACTED: length=32]
    include_tools=True,         # tool params   → written as JSON
    include_observations=True,  # tool results  → written as JSON
    include_final=True,         # final answer  → written as text
)
```

| Flag | Default | Controls |
|---|---|---|
| `include_query` | `False` | Whether the user's query is written or replaced with `[REDACTED: length=N]` |
| `include_tools` | `True` | Whether tool parameters are written or replaced with `[REDACTED]` |
| `include_observations` | `True` | Whether tool results (observations) are written or replaced with `[REDACTED]` |
| `include_final` | `True` | Whether the final answer is written or replaced with `[REDACTED]` |

Even with all flags set to `True`, automatic redaction still applies to sensitive keys and values. See [Redaction Rules](#redaction-rules).

---

## Custom File Location

### Save to a specific folder

```python
history = AgentHistoryMiddleware(folder="/var/log/agents")
# writes: /var/log/agents/Task_20260616_120000_abc12345.md
#         /var/log/agents/Task_20260616_120000_abc12345.json
```

### Save with a specific filename

```python
history = AgentHistoryMiddleware(file_path="run_001.md")
# writes: ./run_001.md
#         ./run_001.json
```

### Combine folder + filename

```python
history = AgentHistoryMiddleware(
    folder="/var/log/agents",
    file_path="my_task.md",
)
# writes: /var/log/agents/my_task.md
#         /var/log/agents/my_task.json
```

### Default (no arguments)

Files are auto-named and saved to `./Agent History/` in your working directory.

---

## Using with ReactAgent

```python
from autourgos_history     import AgentHistoryMiddleware
from autourgos_react_agent import ReactAgent
from autourgos_openaichat  import OpenAIChatModel

def search(query: str) -> str:
    return f"Search results for: {query}"

search_tool = {
    "name": "search",
    "description": "Search the web.",
    "parameters": {
        "type": "object",
        "properties": {
            "query": {"type": "string", "description": "Search terms"}
        },
        "required": ["query"],
    },
    "func": search,
}

history = AgentHistoryMiddleware(
    include_query=True,
    include_tools=True,
    include_observations=True,
    include_final=True,
)

agent = ReactAgent(
    llm=OpenAIChatModel(model="gpt-4o"),
    middleware=[history],
)
agent.add_tools(search_tool)

result = agent.invoke("Find the latest Python release notes.")
print(result)

# history.flush() — optional, ensures files are fully written before process exits
```

---

## Using with Any Agent

`AgentHistoryMiddleware` is a `CallbackHandler`. Any agent that accepts middleware / callback handlers will work.

Add it at construction time:

```python
agent = MyAgent(llm=llm, middleware=[AgentHistoryMiddleware()])
```

Or after construction:

```python
agent.add_middleware(AgentHistoryMiddleware())
```

The middleware listens for these lifecycle events fired by the agent:

| Event | When it fires |
|---|---|
| `on_agent_start` | Agent receives a new query |
| `on_iteration_start` | New Thought → Action → Observe cycle begins |
| `on_llm_end` | LLM returns its raw response |
| `on_tool_start` | Tool is about to be called |
| `on_tool_end` | Tool returned a result |
| `on_tool_error` | Tool raised an exception |
| `on_agent_end` | Agent produced a final answer |
| `on_agent_error` | Agent raised an unhandled exception |

---

## Flushing Logs

File I/O is async (dispatched to a background thread). If your process might exit immediately after `invoke()`, call `flush()` to wait for all writes to complete:

```python
result = agent.invoke("My task")
history.flush()  # wait for files to finish writing
```

This is rarely needed in long-running applications but important in scripts and tests.

---

## Constructor Reference

| Parameter | Type | Default | Description |
|---|---|---|---|
| `file_path` | `str` | `None` | Exact path for the Markdown file. JSON file uses the same name with `.json` extension |
| `folder` | `str` | `None` | Directory for auto-named files. Defaults to `./Agent History/` |
| `include_query` | `bool` | `False` | Write the user's query to the log |
| `include_tools` | `bool` | `True` | Write tool parameters to the log |
| `include_observations` | `bool` | `True` | Write tool results (observations) to the log |
| `include_final` | `bool` | `True` | Write the final answer to the log |

---

## Markdown Output Format

```
# Task Session: <AgentName>
**Started At:** YYYY-MM-DD HH:MM:SS

## Initial Query
<query or [REDACTED: length=N]>

---

## Iteration 1

### Thought
<LLM reasoning>

### Action (Tools)
**Tool:** `tool_name`
**Parameters:**
```json
{ ... }
```

### Observations
**tool_name**:
<result or [REDACTED]>

---

## Final Answer
<answer or [REDACTED]>
```

---

## JSON Output Format

```json
{
  "query":          "string | null",
  "agent_name":     "string",
  "start_time":     "ISO 8601 datetime",
  "end_time":       "ISO 8601 datetime",
  "iterations": [
    {
      "iteration":    1,
      "thought":      "string | null",
      "tools": [
        {"tool": "tool_name", "params": { ... }}
      ],
      "observations": [
        {"tool": "tool_name", "result": "string"}
      ]
    }
  ],
  "final_response": "string | null",
  "error":          "string | null"
}
```

---

## Redaction Rules

Applied automatically before any write, regardless of `include_*` flags.

### By key name

Keys matching this pattern (case-insensitive) have their value replaced with `[REDACTED]`:

```
api_key, api-key, token, secret, password,
authorization, cookie, session, credential
```

Example:
```python
{"api_key": "sk-abc123"}  →  {"api_key": "[REDACTED]"}
```

### By value shape

Values that look like secrets are replaced regardless of key name:

| Pattern | Example |
|---|---|
| `sk-...` | OpenAI API keys |
| `AKIA...` | AWS access keys |
| `Bearer ...` | HTTP authorization headers |
| `ghp_...` | GitHub personal access tokens |
| `ya29....` | Google OAuth tokens |

### By length

String values longer than **512 characters** are truncated:

```
"very long text..." → "first 512 chars... [TRUNCATED]"
```

---

## Thread Safety

Each concurrent agent call gets its own **thread-local state** — query, iteration data, file paths, and the logger are all isolated per thread. Multiple agents can run concurrently with the same `AgentHistoryMiddleware` instance and their logs will never mix.

All disk writes are dispatched to a **single-worker background executor** per middleware instance, keeping agent execution fast and preventing file corruption from concurrent writes.

---

## License

MIT — Copyright (c) 2026 Jitin Kumar Sengar
