This project has been archived by its maintainers, and is no longer receiving any updates.
autourgos-history
Agent execution history middleware for the Autourgos framework. Attach it to any 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.
from autourgos_history import AgentHistoryMiddleware
from autourgos_agent import Agent
from autourgos_openaichat import OpenAIChatModel
history = AgentHistoryMiddleware(include_query=True, include_tools=True, include_observations=True, include_final=True)
agent = Agent(llm=OpenAIChatModel(model="gpt-4o"), middleware=[history])
Features
- Dual output: human-readable Markdown + structured JSON, one pair per run
- Automatic redaction — by key name (
api_key,token,secret,password/pwd/pass,auth,private_key,access_key,client_secret, ...), by value shape (sk-...,AKIA...,Bearer ...,ghp_...,ya29...., Slackxox[baprs]-...tokens, JWTs), and by length (>512 chars truncated) - Per-field privacy flags — choose exactly what gets written (
include_query,include_tools,include_observations,include_final) - Concurrency-safe — per-run state isolated via
contextvars.ContextVar, correct for both concurrent threads (invoke()) and concurrentasynciotasks sharing one thread (ainvoke()); disk writes on a single-worker background executor - Works with any agent — it's a
CallbackHandler, notautourgos-agent-specific - Zero required dependencies, pure Python 3.10+
Table of Contents
- Why Use This?
- Install
- Quick Start
- Output Files
- Privacy Controls
- Custom File Location
- Using With Any Agent
- Flushing Logs
- Constructor Reference
- Redaction Rules
- Thread Safety
- License
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 where the agent went wrong, audit every tool call, monitor reasoning in plain English, and control privacy with per-field flags.
Install
pip install autourgos-history
Requires Python 3.10+. No other dependencies.
Quick Start
from autourgos_history import AgentHistoryMiddleware
from autourgos_agent import Agent
from autourgos_openaichat import OpenAIChatModel
def my_tool(city: str) -> str:
"""Look up the weather for a city."""
return f"The weather in {city} is 22C and sunny."
history = AgentHistoryMiddleware(
include_query=True,
include_tools=True,
include_observations=True,
include_final=True,
)
agent = Agent(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
With Agent(verbose=True), one line announcing the file path prints once per run:
[History] Logging this run to ./Agent History/Task_20260616_120000_abc12345.md
Output Files
Markdown (.md)
# Task Session: Agent
**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 (`.json`)
```json
{
"query": "What is the weather in Tokyo?",
"agent_name": "Agent",
"start_time": "2026-06-16T12:00:00.123456",
"end_time": "2026-06-16T12:00:02.456789",
"iterations": [
{"iteration": 1, "thought": "...", "tools": [{"tool": "get_weather", "params": {"city": "Tokyo"}}],
"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:
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 True, automatic redaction still applies to sensitive keys and values — see
Redaction Rules.
Custom File Location
history = AgentHistoryMiddleware(folder="/var/log/agents")
# writes: /var/log/agents/Task_20260616_120000_abc12345.{md,json}
history = AgentHistoryMiddleware(file_path="run_001.md")
# writes: ./run_001.{md,json}
history = AgentHistoryMiddleware(folder="/var/log/agents", file_path="my_task.md")
# writes: /var/log/agents/my_task.{md,json}
Default (no arguments): auto-named files saved to ./Agent History/.
Using With Any Agent
AgentHistoryMiddleware is a CallbackHandler. Any agent that accepts middleware / callback handlers works.
agent = MyAgent(llm=llm, middleware=[AgentHistoryMiddleware()])
# or after construction:
agent.add_middleware(AgentHistoryMiddleware())
Listened events: on_agent_start, on_iteration_start, on_llm_end, on_tool_start, on_tool_end,
on_tool_error, on_agent_end, on_agent_error.
Flushing Logs
File I/O is async (dispatched to a background thread). If your process might exit immediately after
invoke(), call flush():
result = agent.invoke("My task")
history.flush() # wait for files to finish writing
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 |
Redaction Rules
Applied automatically before any write, regardless of include_* flags.
By key name (case-insensitive): api_key, api-key, token, secret, password, pwd, pass,
authorization, auth, cookie, session, credential, private_key, access_key, client_secret
→ value replaced with [REDACTED].
By value shape: OpenAI keys (sk-...), AWS keys (AKIA...), HTTP auth headers (Bearer ...), GitHub
tokens (ghp_...), Google OAuth tokens (ya29....), Slack tokens (xox[baprs]-...), JWTs
(eyJ...........).
By length: string values longer than 512 characters are truncated ("...[TRUNCATED]").
This is a best-effort, pattern-based scheme — a secret that matches neither a known key name nor a known value shape (e.g. a bare high-entropy string under an unrecognized key) will not be caught. Treat it as one layer of defense-in-depth, not a guarantee.
Thread Safety
Each concurrent agent call gets its own isolated per-run state — query, iteration data, file paths, and
the logger — via contextvars.ContextVar rather than threading.local(). This isolates correctly both
across OS threads (concurrent invoke() calls) and across concurrent asyncio tasks sharing one
thread (concurrent ainvoke() calls); threading.local() alone only handles the former, so two
interleaved ainvoke() runs on the same event-loop thread would otherwise clobber each other's state.
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.
License
Apache License 2.0, Copyright (c) 2026 Jitin Kumar Sengar
Metadata
Release files for autourgos-history 2.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| autourgos_history-2.2.0.tar.gz | 29.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| autourgos_history-2.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 50.6 kB
Release files / autourgos_history-2.2.0.tar.gz
| Download URL | autourgos_history-2.2.0.tar.gz |
|---|---|
| Size | 29.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e0feac962344fb06b4fac512c1a5de7a43507b81c0586bf36896181907c8c51a
|
|
BLAKE2b-256 checksum How to use checksums |
f6072e5a572193da8d052ce3f408df7edccc2ff2edc6d521a6be6771cbce888b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.9
|
Release files / autourgos_history-2.2.0-py3-none-any.whl
| Download URL | autourgos_history-2.2.0-py3-none-any.whl |
|---|---|
| Size | 21.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
055f9091bd258f7a13778eb2fdb5aec53b60667748ae2fdc7ffc11310e0a96cd
|
|
BLAKE2b-256 checksum How to use checksums |
f91e1e5d1767c0ed8125463b50dfe4f66fa138e0f4c8bbb0ec6ab4b5eb72b979
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.9
|