epi-recorder 2.1.2__tar.gz → 2.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/CHANGELOG.md +26 -0
- {epi_recorder-2.1.2/epi_recorder.egg-info → epi_recorder-2.1.3}/PKG-INFO +30 -27
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/README.md +22 -20
- epi_recorder-2.1.3/epi_cli/chat.py +193 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_cli/main.py +7 -1
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_core/__init__.py +1 -1
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_recorder/__init__.py +1 -1
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_recorder/patcher.py +110 -1
- {epi_recorder-2.1.2 → epi_recorder-2.1.3/epi_recorder.egg-info}/PKG-INFO +30 -27
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_recorder.egg-info/SOURCES.txt +1 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_recorder.egg-info/requires.txt +1 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/pyproject.toml +8 -7
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/LICENSE +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/MANIFEST.in +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_cli/__init__.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_cli/__main__.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_cli/keys.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_cli/ls.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_cli/record.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_cli/run.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_cli/verify.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_cli/view.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_core/container.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_core/redactor.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_core/schemas.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_core/serialize.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_core/trust.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_postinstall.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_recorder/api.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_recorder/bootstrap.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_recorder/environment.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_recorder/test_import.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_recorder/test_script.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_recorder.egg-info/dependency_links.txt +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_recorder.egg-info/entry_points.txt +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_recorder.egg-info/top_level.txt +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_viewer_static/app.js +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_viewer_static/crypto.js +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_viewer_static/index.html +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/epi_viewer_static/viewer_lite.css +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/examples/advanced_demo.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/examples/api_example.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/examples/complete_demo_workflow.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/examples/complete_example.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/examples/complex_rag_demo.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/examples/decorator_example.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/examples/demo_python_api.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/examples/demo_script.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/examples/demo_workflow.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/examples/hello_simple.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/examples/live_demo_workflow.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/examples/metadata_example.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/examples/openai_example.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/examples/quick_demo.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/examples/sentiment_analysis.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/examples/view_example.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/examples/visualization_script.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/examples/zero_config_example.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/setup.cfg +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/setup.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/COMPREHENSIVE_REAL_TEST.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/ENTERPRISE_PLATFORM_TEST.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/FINAL_COMPREHENSIVE_TEST.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/REAL_USER_TEST.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/ULTIMATE_COMPLETE_TEST.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/__init__.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/comprehensive_test_v1.1.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/edge_case_simple.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/edge_case_test.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/full_system_test.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/my_test.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/quick_api_test.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/simulate_user.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/stress_test.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_100_percent.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_absolute_100.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_all_cli_commands.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_api.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_api_integration.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_cli_comprehensive.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_cli_integration.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_cli_record.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_cli_workflow.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_complete_workflow.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_comprehensive_e2e.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_container.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_context_debug.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_coverage_100.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_debug_record_path.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_decorator_debug.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_detailed_debug.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_final_100.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_final_validation.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_magic.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_matching_validation.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_metadata_features.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_metadata_fix.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_new_ux.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_patcher.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_real_workflow_api.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_record_vs_class.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_redaction_only.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_redactor.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_serialize.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_signing.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_signing_debug.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_signing_verbose.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_simple.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_simple_context.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_steps_format.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_trace_exit.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_trust.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_user_demo.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_user_workflow.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/test_user_workflow_simple.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/torture_test.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/user_journey_test.py +0 -0
- {epi_recorder-2.1.2 → epi_recorder-2.1.3}/tests/verify_improvements.py +0 -0
|
@@ -5,6 +5,32 @@ All notable changes to EPI Recorder will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.1.3] - 2026-01-24
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Google Gemini Support**: Automatic interception of Gemini API calls via `patch_gemini()`
|
|
12
|
+
- **`epi chat` command**: Interactive AI-powered querying of evidence files using natural language
|
|
13
|
+
- **google-generativeai dependency**: Gemini AI features work out of the box
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- Updated `patch_all()` to include Gemini alongside OpenAI
|
|
17
|
+
- Added 'gemini' to package keywords
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
- **Windows Compatibility**: Replaced Unicode emojis in CLI output with ASCII to prevent crashes on legacy terminals
|
|
21
|
+
- **Error Handling**: Improved API error reporting (e.g., Quota Exceeded) with user-friendly UI panels
|
|
22
|
+
- **Deprecation Warnings**: Suppressed `FutureWarning` spam from google-generativeai SDK
|
|
23
|
+
|
|
24
|
+
## [2.1.2] - 2025-01-17
|
|
25
|
+
|
|
26
|
+
### Security
|
|
27
|
+
- **Client-Side Verification**: Embedded HTML viewer now verifies Ed25519 signatures offline using JS
|
|
28
|
+
- **Manifest V1.1**: Canonical JSON hashing and public key inclusion
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
- Updated trust badges in Viewer UI
|
|
32
|
+
- Spec version bump to 1.1-json
|
|
33
|
+
|
|
8
34
|
## [2.1.1] - 2025-12-16
|
|
9
35
|
|
|
10
36
|
### Added
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: epi-recorder
|
|
3
|
-
Version: 2.1.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 2.1.3
|
|
4
|
+
Summary: The PDF for AI Evidence - Cryptographic proof of what Autonomous AI Systems actually did.
|
|
5
5
|
Author-email: Mohd Ibrahim Afridi <epitechforworld@outlook.com>
|
|
6
6
|
Maintainer-email: Mohd Ibrahim Afridi <epitechforworld@outlook.com>
|
|
7
7
|
License: Apache-2.0
|
|
8
|
-
Project-URL: Homepage, https://github.com/mohdibrahimaiml/EPI-V2.1.
|
|
9
|
-
Project-URL: Documentation, https://github.com/mohdibrahimaiml/EPI-V2.1.
|
|
10
|
-
Project-URL: Repository, https://github.com/mohdibrahimaiml/EPI-V2.1.
|
|
11
|
-
Project-URL: Issues, https://github.com/mohdibrahimaiml/EPI-V2.1.
|
|
12
|
-
Keywords: ai,reproducibility,verification,llm,evidence,openai,cryptography,workflow,audit
|
|
8
|
+
Project-URL: Homepage, https://github.com/mohdibrahimaiml/EPI-V2.1.3
|
|
9
|
+
Project-URL: Documentation, https://github.com/mohdibrahimaiml/EPI-V2.1.3#readme
|
|
10
|
+
Project-URL: Repository, https://github.com/mohdibrahimaiml/EPI-V2.1.3
|
|
11
|
+
Project-URL: Issues, https://github.com/mohdibrahimaiml/EPI-V2.1.3/issues
|
|
12
|
+
Keywords: ai,reproducibility,verification,llm,evidence,openai,gemini,cryptography,workflow,audit
|
|
13
13
|
Classifier: Development Status :: 4 - Beta
|
|
14
14
|
Classifier: Intended Audience :: Developers
|
|
15
15
|
Classifier: Intended Audience :: Science/Research
|
|
@@ -29,6 +29,7 @@ Requires-Dist: cryptography>=41.0.0
|
|
|
29
29
|
Requires-Dist: cbor2>=5.6.0
|
|
30
30
|
Requires-Dist: typer[all]>=0.12.0
|
|
31
31
|
Requires-Dist: rich>=13.0.0
|
|
32
|
+
Requires-Dist: google-generativeai>=0.4.0
|
|
32
33
|
Provides-Extra: dev
|
|
33
34
|
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
34
35
|
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
|
|
@@ -43,18 +44,18 @@ Dynamic: license-file
|
|
|
43
44
|
|
|
44
45
|
# EPI Recorder
|
|
45
46
|
|
|
46
|
-
### The PDF for AI Evidence
|
|
47
|
+
### The PDF for AI Evidence
|
|
47
48
|
|
|
48
|
-
**
|
|
49
|
+
**Cryptographic proof of what Autonomous AI Systems actually did.**
|
|
49
50
|
|
|
50
|
-
[](https://www.python.org)
|
|
52
|
-
[](LICENSE)
|
|
53
|
-
[](https://pypi.org/project/epi-recorder/)
|
|
52
|
+
[](https://www.python.org)
|
|
53
|
+
[](LICENSE)
|
|
54
|
+
[](https://github.com/mohdibrahimaiml/EPI-V2.1.3)
|
|
55
|
+
[](https://pypi.org/project/epi-recorder/)
|
|
56
|
+
[](https://github.com/mohdibrahimaiml/EPI-V2.1.3)
|
|
56
57
|
|
|
57
|
-
[**🚀 Quick Start**](#-quick-start-30-seconds) • [**📖 Docs**](https://epilabs.org/docs) • [**💬 Community**](https://github.com/mohdibrahimaiml/EPI-V2.
|
|
58
|
+
[**🚀 Quick Start**](#-quick-start-30-seconds) • [**📖 Docs**](https://epilabs.org/docs) • [**💬 Community**](https://github.com/mohdibrahimaiml/EPI-V2.1.3/discussions) • [**🎥 Demo**](https://colab.research.google.com/github/mohdibrahimaiml/EPI-V2.1.3/blob/main/colab_demo.ipynb)
|
|
58
59
|
|
|
59
60
|
</div>
|
|
60
61
|
|
|
@@ -73,12 +74,12 @@ Dynamic: license-file
|
|
|
73
74
|
|
|
74
75
|
**Unix/Mac:**
|
|
75
76
|
```bash
|
|
76
|
-
curl -sSL https://raw.githubusercontent.com/mohdibrahimaiml/EPI-V2.1.
|
|
77
|
+
curl -sSL https://raw.githubusercontent.com/mohdibrahimaiml/EPI-V2.1.3/main/scripts/install.sh | sh
|
|
77
78
|
```
|
|
78
79
|
|
|
79
80
|
**Windows:**
|
|
80
81
|
```powershell
|
|
81
|
-
iwr https://raw.githubusercontent.com/mohdibrahimaiml/EPI-V2.1.
|
|
82
|
+
iwr https://raw.githubusercontent.com/mohdibrahimaiml/EPI-V2.1.3/main/scripts/install.ps1 -useb | iex
|
|
82
83
|
```
|
|
83
84
|
|
|
84
85
|
**Manual (pip):**
|
|
@@ -476,21 +477,23 @@ Use `python -m epi_cli` instead (always works). Or run `python -m epi_cli doctor
|
|
|
476
477
|
|
|
477
478
|
---
|
|
478
479
|
|
|
479
|
-
## 🆕 What's New in v2.1.
|
|
480
|
+
## 🆕 What's New in v2.1.3
|
|
480
481
|
|
|
481
482
|
> [!IMPORTANT]
|
|
482
|
-
> **
|
|
483
|
+
> **Gemini Native:** EPI now natively supports Google Gemini. Just run your script, and Gemini calls are captured automatically. Plus, talk to your evidence with `epi chat`.
|
|
483
484
|
|
|
484
|
-
###
|
|
485
|
+
### 🤖 Gemini Integration
|
|
486
|
+
- **Automatic Patcher:** Intercepts `google.generativeai` calls without code changes. Logs prompts, responses, and token usage.
|
|
487
|
+
- **Evidence Chat:** New command `epi chat` allows you to query your `.epi` files using Gemini AI. "What happened in this run?"
|
|
488
|
+
- **Error Capture:** Automatically records API errors like Quota Exceeded (429) or Blocked Content.
|
|
489
|
+
|
|
490
|
+
### 🛡️ Security & Integrity (v2.1.2)
|
|
485
491
|
- **Client-Side Verification:** The HTML viewer now includes a bundled crypto library to verify signatures offline.
|
|
486
|
-
- **Spec Update (v1.1-json):** Manifests now use Canonical JSON hashing and include the `public_key` for self-contained proof.
|
|
487
492
|
- **Trust Badges:** UI now explicitly shows "Verified" (Green), "Unsigned" (Yellow), or "Tampered" (Red).
|
|
488
493
|
|
|
489
|
-
### ✨ Enhanced CLI Reliability
|
|
490
|
-
|
|
491
|
-
**
|
|
492
|
-
- `python -m epi_cli` now works as a 100% reliable alternative
|
|
493
|
-
- Perfect for restricted environments
|
|
494
|
+
### ✨ Enhanced CLI Reliability
|
|
495
|
+
- **Windows Compatibility:** Fixed Unicode issues in CLI for legacy terminals.
|
|
496
|
+
- **Python Module Fallback:** `python -m epi_cli` works reliably everywhere.
|
|
494
497
|
|
|
495
498
|
**2. Automatic PATH Configuration**
|
|
496
499
|
- Post-install script auto-fixes PATH on Windows
|
|
@@ -4,18 +4,18 @@
|
|
|
4
4
|
|
|
5
5
|
# EPI Recorder
|
|
6
6
|
|
|
7
|
-
### The PDF for AI Evidence
|
|
7
|
+
### The PDF for AI Evidence
|
|
8
8
|
|
|
9
|
-
**
|
|
9
|
+
**Cryptographic proof of what Autonomous AI Systems actually did.**
|
|
10
10
|
|
|
11
|
-
[](https://www.python.org)
|
|
13
|
-
[](LICENSE)
|
|
14
|
-
[](https://pypi.org/project/epi-recorder/)
|
|
12
|
+
[](https://www.python.org)
|
|
13
|
+
[](LICENSE)
|
|
14
|
+
[](https://github.com/mohdibrahimaiml/EPI-V2.1.3)
|
|
15
|
+
[](https://pypi.org/project/epi-recorder/)
|
|
16
|
+
[](https://github.com/mohdibrahimaiml/EPI-V2.1.3)
|
|
17
17
|
|
|
18
|
-
[**🚀 Quick Start**](#-quick-start-30-seconds) • [**📖 Docs**](https://epilabs.org/docs) • [**💬 Community**](https://github.com/mohdibrahimaiml/EPI-V2.
|
|
18
|
+
[**🚀 Quick Start**](#-quick-start-30-seconds) • [**📖 Docs**](https://epilabs.org/docs) • [**💬 Community**](https://github.com/mohdibrahimaiml/EPI-V2.1.3/discussions) • [**🎥 Demo**](https://colab.research.google.com/github/mohdibrahimaiml/EPI-V2.1.3/blob/main/colab_demo.ipynb)
|
|
19
19
|
|
|
20
20
|
</div>
|
|
21
21
|
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
|
|
35
35
|
**Unix/Mac:**
|
|
36
36
|
```bash
|
|
37
|
-
curl -sSL https://raw.githubusercontent.com/mohdibrahimaiml/EPI-V2.1.
|
|
37
|
+
curl -sSL https://raw.githubusercontent.com/mohdibrahimaiml/EPI-V2.1.3/main/scripts/install.sh | sh
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
**Windows:**
|
|
41
41
|
```powershell
|
|
42
|
-
iwr https://raw.githubusercontent.com/mohdibrahimaiml/EPI-V2.1.
|
|
42
|
+
iwr https://raw.githubusercontent.com/mohdibrahimaiml/EPI-V2.1.3/main/scripts/install.ps1 -useb | iex
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
**Manual (pip):**
|
|
@@ -437,21 +437,23 @@ Use `python -m epi_cli` instead (always works). Or run `python -m epi_cli doctor
|
|
|
437
437
|
|
|
438
438
|
---
|
|
439
439
|
|
|
440
|
-
## 🆕 What's New in v2.1.
|
|
440
|
+
## 🆕 What's New in v2.1.3
|
|
441
441
|
|
|
442
442
|
> [!IMPORTANT]
|
|
443
|
-
> **
|
|
443
|
+
> **Gemini Native:** EPI now natively supports Google Gemini. Just run your script, and Gemini calls are captured automatically. Plus, talk to your evidence with `epi chat`.
|
|
444
444
|
|
|
445
|
-
###
|
|
445
|
+
### 🤖 Gemini Integration
|
|
446
|
+
- **Automatic Patcher:** Intercepts `google.generativeai` calls without code changes. Logs prompts, responses, and token usage.
|
|
447
|
+
- **Evidence Chat:** New command `epi chat` allows you to query your `.epi` files using Gemini AI. "What happened in this run?"
|
|
448
|
+
- **Error Capture:** Automatically records API errors like Quota Exceeded (429) or Blocked Content.
|
|
449
|
+
|
|
450
|
+
### 🛡️ Security & Integrity (v2.1.2)
|
|
446
451
|
- **Client-Side Verification:** The HTML viewer now includes a bundled crypto library to verify signatures offline.
|
|
447
|
-
- **Spec Update (v1.1-json):** Manifests now use Canonical JSON hashing and include the `public_key` for self-contained proof.
|
|
448
452
|
- **Trust Badges:** UI now explicitly shows "Verified" (Green), "Unsigned" (Yellow), or "Tampered" (Red).
|
|
449
453
|
|
|
450
|
-
### ✨ Enhanced CLI Reliability
|
|
451
|
-
|
|
452
|
-
**
|
|
453
|
-
- `python -m epi_cli` now works as a 100% reliable alternative
|
|
454
|
-
- Perfect for restricted environments
|
|
454
|
+
### ✨ Enhanced CLI Reliability
|
|
455
|
+
- **Windows Compatibility:** Fixed Unicode issues in CLI for legacy terminals.
|
|
456
|
+
- **Python Module Fallback:** `python -m epi_cli` works reliably everywhere.
|
|
455
457
|
|
|
456
458
|
**2. Automatic PATH Configuration**
|
|
457
459
|
- Post-install script auto-fixes PATH on Windows
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"""
|
|
2
|
+
EPI CLI Chat - Interactive evidence querying with AI.
|
|
3
|
+
|
|
4
|
+
Allows users to ask natural language questions about their .epi evidence files.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
import os
|
|
9
|
+
import warnings
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Optional
|
|
12
|
+
|
|
13
|
+
import typer
|
|
14
|
+
from rich.console import Console
|
|
15
|
+
from rich.markdown import Markdown
|
|
16
|
+
from rich.panel import Panel
|
|
17
|
+
from rich.prompt import Prompt
|
|
18
|
+
import google.api_core.exceptions
|
|
19
|
+
|
|
20
|
+
from epi_core.container import EPIContainer
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
console = Console()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def load_steps_from_epi(epi_path: Path) -> list:
|
|
27
|
+
"""Load steps from an .epi file."""
|
|
28
|
+
import tempfile
|
|
29
|
+
|
|
30
|
+
temp_dir = Path(tempfile.mkdtemp())
|
|
31
|
+
extracted = EPIContainer.unpack(epi_path, temp_dir)
|
|
32
|
+
|
|
33
|
+
steps_file = extracted / "steps.jsonl"
|
|
34
|
+
if not steps_file.exists():
|
|
35
|
+
return []
|
|
36
|
+
|
|
37
|
+
steps = []
|
|
38
|
+
with open(steps_file, 'r', encoding='utf-8') as f:
|
|
39
|
+
for line in f:
|
|
40
|
+
if line.strip():
|
|
41
|
+
steps.append(json.loads(line))
|
|
42
|
+
|
|
43
|
+
return steps
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def chat(
|
|
47
|
+
epi_file: Path = typer.Argument(..., help="Path to .epi file to chat with"),
|
|
48
|
+
model: str = typer.Option("gemini-2.0-flash", "--model", "-m", help="Gemini model to use")
|
|
49
|
+
):
|
|
50
|
+
"""
|
|
51
|
+
Chat with your evidence file using AI.
|
|
52
|
+
|
|
53
|
+
Ask natural language questions about what happened in your recording.
|
|
54
|
+
|
|
55
|
+
Example:
|
|
56
|
+
epi chat my_recording.epi
|
|
57
|
+
"""
|
|
58
|
+
# Resolve path
|
|
59
|
+
if not epi_file.exists():
|
|
60
|
+
# Try epi-recordings directory
|
|
61
|
+
recordings_dir = Path("./epi-recordings")
|
|
62
|
+
potential_path = recordings_dir / f"{epi_file.stem}.epi"
|
|
63
|
+
if potential_path.exists():
|
|
64
|
+
epi_file = potential_path
|
|
65
|
+
else:
|
|
66
|
+
console.print(f"[red]Error:[/red] File not found: {epi_file}")
|
|
67
|
+
raise typer.Exit(1)
|
|
68
|
+
|
|
69
|
+
# Check for API key
|
|
70
|
+
api_key = os.environ.get("GOOGLE_API_KEY") or os.environ.get("GEMINI_API_KEY")
|
|
71
|
+
if not api_key:
|
|
72
|
+
console.print(Panel(
|
|
73
|
+
"[yellow]No API key found![/yellow]\n\n"
|
|
74
|
+
"Set your Google AI API key:\n"
|
|
75
|
+
" [cyan]set GOOGLE_API_KEY=your-key-here[/cyan] (Windows)\n"
|
|
76
|
+
" [cyan]export GOOGLE_API_KEY=your-key-here[/cyan] (Mac/Linux)\n\n"
|
|
77
|
+
"Get a free key at: [link]https://makersuite.google.com/app/apikey[/link]",
|
|
78
|
+
title="[!] API Key Required",
|
|
79
|
+
border_style="yellow"
|
|
80
|
+
))
|
|
81
|
+
raise typer.Exit(1)
|
|
82
|
+
|
|
83
|
+
# Load the .epi file
|
|
84
|
+
console.print(f"\n[dim]Loading evidence from:[/dim] {epi_file}")
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
manifest = EPIContainer.read_manifest(epi_file)
|
|
88
|
+
steps = load_steps_from_epi(epi_file)
|
|
89
|
+
except Exception as e:
|
|
90
|
+
console.print(f"[red]Error loading .epi file:[/red] {e}")
|
|
91
|
+
raise typer.Exit(1)
|
|
92
|
+
|
|
93
|
+
# Initialize Gemini
|
|
94
|
+
try:
|
|
95
|
+
import warnings
|
|
96
|
+
with warnings.catch_warnings():
|
|
97
|
+
warnings.simplefilter("ignore")
|
|
98
|
+
import google.generativeai as genai
|
|
99
|
+
|
|
100
|
+
genai.configure(api_key=api_key)
|
|
101
|
+
ai_model = genai.GenerativeModel(model)
|
|
102
|
+
except ImportError:
|
|
103
|
+
console.print(Panel(
|
|
104
|
+
"[red]Google Generative AI package not installed![/red]\n\n"
|
|
105
|
+
"Install it with:\n"
|
|
106
|
+
" [cyan]pip install google-generativeai[/cyan]",
|
|
107
|
+
title="[X] Missing Dependency",
|
|
108
|
+
border_style="red"
|
|
109
|
+
))
|
|
110
|
+
raise typer.Exit(1)
|
|
111
|
+
except Exception as e:
|
|
112
|
+
console.print(f"[red]Error initializing Gemini:[/red] {e}")
|
|
113
|
+
raise typer.Exit(1)
|
|
114
|
+
|
|
115
|
+
# Build context
|
|
116
|
+
context = f"""You are an expert assistant analyzing an EPI evidence recording file.
|
|
117
|
+
|
|
118
|
+
The recording contains cryptographically signed, tamper-proof evidence of an AI workflow execution.
|
|
119
|
+
|
|
120
|
+
Recording metadata:
|
|
121
|
+
- Created: {manifest.created_at}
|
|
122
|
+
- Goal: {manifest.goal or 'Not specified'}
|
|
123
|
+
- Command: {manifest.cli_command or 'Not specified'}
|
|
124
|
+
- Workflow ID: {manifest.workflow_id}
|
|
125
|
+
- Total steps: {len(steps)}
|
|
126
|
+
|
|
127
|
+
Here are the recorded steps (this is the timeline of events):
|
|
128
|
+
{json.dumps(steps[:50], indent=2, default=str)[:8000]}
|
|
129
|
+
|
|
130
|
+
When answering questions:
|
|
131
|
+
1. Be specific and cite step indices when relevant
|
|
132
|
+
2. Distinguish between LLM requests, responses, and other events
|
|
133
|
+
3. If asked about security, note that API keys are automatically redacted
|
|
134
|
+
4. Keep answers concise but informative
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
# Start chat session
|
|
138
|
+
chat_session = ai_model.start_chat(history=[])
|
|
139
|
+
|
|
140
|
+
# Display header
|
|
141
|
+
console.print()
|
|
142
|
+
console.print(Panel(
|
|
143
|
+
f"[bold cyan]EPI Evidence Chat[/bold cyan]\n\n"
|
|
144
|
+
f"[dim]File:[/dim] {epi_file.name}\n"
|
|
145
|
+
f"[dim]Steps:[/dim] {len(steps)}\n"
|
|
146
|
+
f"[dim]Model:[/dim] {model}\n\n"
|
|
147
|
+
f"Ask questions about this evidence recording.\n"
|
|
148
|
+
f"Type [yellow]exit[/yellow] or [yellow]quit[/yellow] to end the session.",
|
|
149
|
+
border_style="cyan"
|
|
150
|
+
))
|
|
151
|
+
console.print()
|
|
152
|
+
|
|
153
|
+
# Chat loop
|
|
154
|
+
while True:
|
|
155
|
+
try:
|
|
156
|
+
question = Prompt.ask("[bold cyan]You[/bold cyan]")
|
|
157
|
+
except (KeyboardInterrupt, EOFError):
|
|
158
|
+
console.print("\n[dim]Goodbye![/dim]")
|
|
159
|
+
break
|
|
160
|
+
|
|
161
|
+
if question.lower() in ('exit', 'quit', 'q'):
|
|
162
|
+
console.print("[dim]Goodbye![/dim]")
|
|
163
|
+
break
|
|
164
|
+
|
|
165
|
+
if not question.strip():
|
|
166
|
+
continue
|
|
167
|
+
|
|
168
|
+
# Send to Gemini with context
|
|
169
|
+
try:
|
|
170
|
+
full_prompt = f"{context}\n\nUser question: {question}"
|
|
171
|
+
response = chat_session.send_message(full_prompt)
|
|
172
|
+
|
|
173
|
+
console.print()
|
|
174
|
+
console.print("[bold green]AI:[/bold green]")
|
|
175
|
+
console.print(Markdown(response.text))
|
|
176
|
+
console.print()
|
|
177
|
+
|
|
178
|
+
except google.api_core.exceptions.ResourceExhausted:
|
|
179
|
+
console.print(Panel(
|
|
180
|
+
"[yellow]API Quota Exceeded[/yellow]\n\n"
|
|
181
|
+
"You have hit the rate limit for the Gemini API (free tier).\n"
|
|
182
|
+
"Please wait a minute before trying again.",
|
|
183
|
+
title="[!] Rate Limit",
|
|
184
|
+
border_style="yellow"
|
|
185
|
+
))
|
|
186
|
+
except google.api_core.exceptions.NotFound:
|
|
187
|
+
console.print(f"[red]Error:[/red] The model '{model}' was not found. Try using a different model with --model.")
|
|
188
|
+
except google.api_core.exceptions.InvalidArgument as e:
|
|
189
|
+
console.print(f"[red]Error:[/red] Invalid argument: {e}")
|
|
190
|
+
except Exception as e:
|
|
191
|
+
console.print(f"[red]Error:[/red] {e}")
|
|
192
|
+
console.print("[dim]Try asking a different question.[/dim]")
|
|
193
|
+
console.print()
|
|
@@ -12,7 +12,9 @@ from epi_cli.keys import generate_default_keypair_if_missing
|
|
|
12
12
|
# Create Typer app
|
|
13
13
|
app = typer.Typer(
|
|
14
14
|
name="epi",
|
|
15
|
-
help="""EPI -
|
|
15
|
+
help="""EPI - The PDF for AI Evidence.
|
|
16
|
+
|
|
17
|
+
Cryptographic proof of what Autonomous AI Systems actually did.
|
|
16
18
|
|
|
17
19
|
Commands:
|
|
18
20
|
run <script.py> Record, auto-verify and open viewer. (Zero-config)
|
|
@@ -120,6 +122,10 @@ app.add_typer(view_app, name="view", help="Open recording in browser (name resol
|
|
|
120
122
|
from epi_cli.ls import ls as ls_command
|
|
121
123
|
app.command(name="ls", help="List local recordings (./epi-recordings/)")(ls_command)
|
|
122
124
|
|
|
125
|
+
# NEW: chat command (v2.1.3 - AI-powered evidence querying)
|
|
126
|
+
from epi_cli.chat import chat as chat_command
|
|
127
|
+
app.command(name="chat", help="Chat with your evidence file using AI")(chat_command)
|
|
128
|
+
|
|
123
129
|
# Phase 1: keys command (for manual key management)
|
|
124
130
|
@app.command()
|
|
125
131
|
def keys(
|
|
@@ -325,7 +325,113 @@ def _patch_openai_legacy() -> bool:
|
|
|
325
325
|
return False
|
|
326
326
|
|
|
327
327
|
|
|
328
|
-
|
|
328
|
+
# ==================== Google Gemini Patcher ====================
|
|
329
|
+
|
|
330
|
+
def patch_gemini() -> bool:
|
|
331
|
+
"""
|
|
332
|
+
Patch Google Generative AI library to intercept Gemini API calls.
|
|
333
|
+
|
|
334
|
+
Returns:
|
|
335
|
+
bool: True if patching succeeded, False otherwise
|
|
336
|
+
"""
|
|
337
|
+
try:
|
|
338
|
+
import warnings
|
|
339
|
+
with warnings.catch_warnings():
|
|
340
|
+
warnings.simplefilter("ignore")
|
|
341
|
+
import google.generativeai as genai
|
|
342
|
+
from google.generativeai.types import GenerateContentResponse
|
|
343
|
+
|
|
344
|
+
# Get the GenerativeModel class
|
|
345
|
+
GenerativeModel = genai.GenerativeModel
|
|
346
|
+
|
|
347
|
+
# Store original method
|
|
348
|
+
original_generate_content = GenerativeModel.generate_content
|
|
349
|
+
|
|
350
|
+
@wraps(original_generate_content)
|
|
351
|
+
def wrapped_generate_content(self, *args, **kwargs):
|
|
352
|
+
"""Wrapped Gemini generate_content with recording."""
|
|
353
|
+
|
|
354
|
+
# Only record if context is active
|
|
355
|
+
if not is_recording():
|
|
356
|
+
return original_generate_content(self, *args, **kwargs)
|
|
357
|
+
|
|
358
|
+
context = get_recording_context()
|
|
359
|
+
start_time = time.time()
|
|
360
|
+
|
|
361
|
+
# Extract prompt from args/kwargs
|
|
362
|
+
contents = args[0] if args else kwargs.get("contents", "")
|
|
363
|
+
|
|
364
|
+
# Capture request
|
|
365
|
+
request_data = {
|
|
366
|
+
"provider": "google",
|
|
367
|
+
"method": "GenerativeModel.generate_content",
|
|
368
|
+
"model": getattr(self, '_model_name', getattr(self, 'model_name', 'gemini')),
|
|
369
|
+
"contents": str(contents)[:2000], # Truncate long prompts
|
|
370
|
+
"generation_config": str(kwargs.get("generation_config", {})),
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
# Log request step
|
|
374
|
+
context.add_step("llm.request", request_data)
|
|
375
|
+
|
|
376
|
+
# Execute original call
|
|
377
|
+
try:
|
|
378
|
+
response = original_generate_content(self, *args, **kwargs)
|
|
379
|
+
elapsed = time.time() - start_time
|
|
380
|
+
|
|
381
|
+
# Capture response
|
|
382
|
+
response_text = ""
|
|
383
|
+
try:
|
|
384
|
+
if hasattr(response, 'text'):
|
|
385
|
+
response_text = response.text[:2000] # Truncate long responses
|
|
386
|
+
elif hasattr(response, 'parts'):
|
|
387
|
+
response_text = str(response.parts)[:2000]
|
|
388
|
+
except Exception:
|
|
389
|
+
response_text = "[Response text extraction failed]"
|
|
390
|
+
|
|
391
|
+
response_data = {
|
|
392
|
+
"provider": "google",
|
|
393
|
+
"model": getattr(self, '_model_name', getattr(self, 'model_name', 'gemini')),
|
|
394
|
+
"response": response_text,
|
|
395
|
+
"latency_seconds": round(elapsed, 3)
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
# Try to get usage info if available
|
|
399
|
+
try:
|
|
400
|
+
if hasattr(response, 'usage_metadata'):
|
|
401
|
+
usage = response.usage_metadata
|
|
402
|
+
response_data["usage"] = {
|
|
403
|
+
"prompt_tokens": getattr(usage, 'prompt_token_count', None),
|
|
404
|
+
"completion_tokens": getattr(usage, 'candidates_token_count', None),
|
|
405
|
+
"total_tokens": getattr(usage, 'total_token_count', None)
|
|
406
|
+
}
|
|
407
|
+
except Exception:
|
|
408
|
+
pass
|
|
409
|
+
|
|
410
|
+
# Log response step
|
|
411
|
+
context.add_step("llm.response", response_data)
|
|
412
|
+
|
|
413
|
+
return response
|
|
414
|
+
|
|
415
|
+
except Exception as e:
|
|
416
|
+
# Log error step
|
|
417
|
+
context.add_step("llm.error", {
|
|
418
|
+
"provider": "google",
|
|
419
|
+
"error": str(e),
|
|
420
|
+
"error_type": type(e).__name__
|
|
421
|
+
})
|
|
422
|
+
raise
|
|
423
|
+
|
|
424
|
+
# Apply patch
|
|
425
|
+
GenerativeModel.generate_content = wrapped_generate_content
|
|
426
|
+
|
|
427
|
+
return True
|
|
428
|
+
|
|
429
|
+
except ImportError:
|
|
430
|
+
# google-generativeai not installed
|
|
431
|
+
return False
|
|
432
|
+
except Exception as e:
|
|
433
|
+
print(f"Warning: Failed to patch Gemini: {e}")
|
|
434
|
+
return False
|
|
329
435
|
|
|
330
436
|
|
|
331
437
|
def patch_requests() -> bool:
|
|
@@ -419,6 +525,9 @@ def patch_all() -> Dict[str, bool]:
|
|
|
419
525
|
# Patch OpenAI
|
|
420
526
|
results["openai"] = patch_openai()
|
|
421
527
|
|
|
528
|
+
# Patch Google Gemini
|
|
529
|
+
results["gemini"] = patch_gemini()
|
|
530
|
+
|
|
422
531
|
# Patch generic requests (covers LangChain, Anthropic, etc.)
|
|
423
532
|
results["requests"] = patch_requests()
|
|
424
533
|
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: epi-recorder
|
|
3
|
-
Version: 2.1.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 2.1.3
|
|
4
|
+
Summary: The PDF for AI Evidence - Cryptographic proof of what Autonomous AI Systems actually did.
|
|
5
5
|
Author-email: Mohd Ibrahim Afridi <epitechforworld@outlook.com>
|
|
6
6
|
Maintainer-email: Mohd Ibrahim Afridi <epitechforworld@outlook.com>
|
|
7
7
|
License: Apache-2.0
|
|
8
|
-
Project-URL: Homepage, https://github.com/mohdibrahimaiml/EPI-V2.1.
|
|
9
|
-
Project-URL: Documentation, https://github.com/mohdibrahimaiml/EPI-V2.1.
|
|
10
|
-
Project-URL: Repository, https://github.com/mohdibrahimaiml/EPI-V2.1.
|
|
11
|
-
Project-URL: Issues, https://github.com/mohdibrahimaiml/EPI-V2.1.
|
|
12
|
-
Keywords: ai,reproducibility,verification,llm,evidence,openai,cryptography,workflow,audit
|
|
8
|
+
Project-URL: Homepage, https://github.com/mohdibrahimaiml/EPI-V2.1.3
|
|
9
|
+
Project-URL: Documentation, https://github.com/mohdibrahimaiml/EPI-V2.1.3#readme
|
|
10
|
+
Project-URL: Repository, https://github.com/mohdibrahimaiml/EPI-V2.1.3
|
|
11
|
+
Project-URL: Issues, https://github.com/mohdibrahimaiml/EPI-V2.1.3/issues
|
|
12
|
+
Keywords: ai,reproducibility,verification,llm,evidence,openai,gemini,cryptography,workflow,audit
|
|
13
13
|
Classifier: Development Status :: 4 - Beta
|
|
14
14
|
Classifier: Intended Audience :: Developers
|
|
15
15
|
Classifier: Intended Audience :: Science/Research
|
|
@@ -29,6 +29,7 @@ Requires-Dist: cryptography>=41.0.0
|
|
|
29
29
|
Requires-Dist: cbor2>=5.6.0
|
|
30
30
|
Requires-Dist: typer[all]>=0.12.0
|
|
31
31
|
Requires-Dist: rich>=13.0.0
|
|
32
|
+
Requires-Dist: google-generativeai>=0.4.0
|
|
32
33
|
Provides-Extra: dev
|
|
33
34
|
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
34
35
|
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
|
|
@@ -43,18 +44,18 @@ Dynamic: license-file
|
|
|
43
44
|
|
|
44
45
|
# EPI Recorder
|
|
45
46
|
|
|
46
|
-
### The PDF for AI Evidence
|
|
47
|
+
### The PDF for AI Evidence
|
|
47
48
|
|
|
48
|
-
**
|
|
49
|
+
**Cryptographic proof of what Autonomous AI Systems actually did.**
|
|
49
50
|
|
|
50
|
-
[](https://www.python.org)
|
|
52
|
-
[](LICENSE)
|
|
53
|
-
[](https://pypi.org/project/epi-recorder/)
|
|
52
|
+
[](https://www.python.org)
|
|
53
|
+
[](LICENSE)
|
|
54
|
+
[](https://github.com/mohdibrahimaiml/EPI-V2.1.3)
|
|
55
|
+
[](https://pypi.org/project/epi-recorder/)
|
|
56
|
+
[](https://github.com/mohdibrahimaiml/EPI-V2.1.3)
|
|
56
57
|
|
|
57
|
-
[**🚀 Quick Start**](#-quick-start-30-seconds) • [**📖 Docs**](https://epilabs.org/docs) • [**💬 Community**](https://github.com/mohdibrahimaiml/EPI-V2.
|
|
58
|
+
[**🚀 Quick Start**](#-quick-start-30-seconds) • [**📖 Docs**](https://epilabs.org/docs) • [**💬 Community**](https://github.com/mohdibrahimaiml/EPI-V2.1.3/discussions) • [**🎥 Demo**](https://colab.research.google.com/github/mohdibrahimaiml/EPI-V2.1.3/blob/main/colab_demo.ipynb)
|
|
58
59
|
|
|
59
60
|
</div>
|
|
60
61
|
|
|
@@ -73,12 +74,12 @@ Dynamic: license-file
|
|
|
73
74
|
|
|
74
75
|
**Unix/Mac:**
|
|
75
76
|
```bash
|
|
76
|
-
curl -sSL https://raw.githubusercontent.com/mohdibrahimaiml/EPI-V2.1.
|
|
77
|
+
curl -sSL https://raw.githubusercontent.com/mohdibrahimaiml/EPI-V2.1.3/main/scripts/install.sh | sh
|
|
77
78
|
```
|
|
78
79
|
|
|
79
80
|
**Windows:**
|
|
80
81
|
```powershell
|
|
81
|
-
iwr https://raw.githubusercontent.com/mohdibrahimaiml/EPI-V2.1.
|
|
82
|
+
iwr https://raw.githubusercontent.com/mohdibrahimaiml/EPI-V2.1.3/main/scripts/install.ps1 -useb | iex
|
|
82
83
|
```
|
|
83
84
|
|
|
84
85
|
**Manual (pip):**
|
|
@@ -476,21 +477,23 @@ Use `python -m epi_cli` instead (always works). Or run `python -m epi_cli doctor
|
|
|
476
477
|
|
|
477
478
|
---
|
|
478
479
|
|
|
479
|
-
## 🆕 What's New in v2.1.
|
|
480
|
+
## 🆕 What's New in v2.1.3
|
|
480
481
|
|
|
481
482
|
> [!IMPORTANT]
|
|
482
|
-
> **
|
|
483
|
+
> **Gemini Native:** EPI now natively supports Google Gemini. Just run your script, and Gemini calls are captured automatically. Plus, talk to your evidence with `epi chat`.
|
|
483
484
|
|
|
484
|
-
###
|
|
485
|
+
### 🤖 Gemini Integration
|
|
486
|
+
- **Automatic Patcher:** Intercepts `google.generativeai` calls without code changes. Logs prompts, responses, and token usage.
|
|
487
|
+
- **Evidence Chat:** New command `epi chat` allows you to query your `.epi` files using Gemini AI. "What happened in this run?"
|
|
488
|
+
- **Error Capture:** Automatically records API errors like Quota Exceeded (429) or Blocked Content.
|
|
489
|
+
|
|
490
|
+
### 🛡️ Security & Integrity (v2.1.2)
|
|
485
491
|
- **Client-Side Verification:** The HTML viewer now includes a bundled crypto library to verify signatures offline.
|
|
486
|
-
- **Spec Update (v1.1-json):** Manifests now use Canonical JSON hashing and include the `public_key` for self-contained proof.
|
|
487
492
|
- **Trust Badges:** UI now explicitly shows "Verified" (Green), "Unsigned" (Yellow), or "Tampered" (Red).
|
|
488
493
|
|
|
489
|
-
### ✨ Enhanced CLI Reliability
|
|
490
|
-
|
|
491
|
-
**
|
|
492
|
-
- `python -m epi_cli` now works as a 100% reliable alternative
|
|
493
|
-
- Perfect for restricted environments
|
|
494
|
+
### ✨ Enhanced CLI Reliability
|
|
495
|
+
- **Windows Compatibility:** Fixed Unicode issues in CLI for legacy terminals.
|
|
496
|
+
- **Python Module Fallback:** `python -m epi_cli` works reliably everywhere.
|
|
494
497
|
|
|
495
498
|
**2. Automatic PATH Configuration**
|
|
496
499
|
- Post-install script auto-fixes PATH on Windows
|
|
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "epi-recorder"
|
|
7
|
-
version = "2.1.
|
|
8
|
-
description = "
|
|
7
|
+
version = "2.1.3"
|
|
8
|
+
description = "The PDF for AI Evidence - Cryptographic proof of what Autonomous AI Systems actually did."
|
|
9
9
|
readme = {file = "README.md", content-type = "text/markdown"}
|
|
10
10
|
requires-python = ">=3.11"
|
|
11
11
|
license = {text = "Apache-2.0"}
|
|
@@ -15,7 +15,7 @@ authors = [
|
|
|
15
15
|
maintainers = [
|
|
16
16
|
{name = "Mohd Ibrahim Afridi", email = "epitechforworld@outlook.com"}
|
|
17
17
|
]
|
|
18
|
-
keywords = ["ai", "reproducibility", "verification", "llm", "evidence", "openai", "cryptography", "workflow", "audit"]
|
|
18
|
+
keywords = ["ai", "reproducibility", "verification", "llm", "evidence", "openai", "gemini", "cryptography", "workflow", "audit"]
|
|
19
19
|
classifiers = [
|
|
20
20
|
"Development Status :: 4 - Beta",
|
|
21
21
|
"Intended Audience :: Developers",
|
|
@@ -36,6 +36,7 @@ dependencies = [
|
|
|
36
36
|
"cbor2>=5.6.0",
|
|
37
37
|
"typer[all]>=0.12.0",
|
|
38
38
|
"rich>=13.0.0",
|
|
39
|
+
"google-generativeai>=0.4.0",
|
|
39
40
|
]
|
|
40
41
|
|
|
41
42
|
[project.optional-dependencies]
|
|
@@ -51,10 +52,10 @@ dev = [
|
|
|
51
52
|
epi = "epi_cli.main:app"
|
|
52
53
|
|
|
53
54
|
[project.urls]
|
|
54
|
-
Homepage = "https://github.com/mohdibrahimaiml/EPI-V2.1.
|
|
55
|
-
Documentation = "https://github.com/mohdibrahimaiml/EPI-V2.1.
|
|
56
|
-
Repository = "https://github.com/mohdibrahimaiml/EPI-V2.1.
|
|
57
|
-
Issues = "https://github.com/mohdibrahimaiml/EPI-V2.1.
|
|
55
|
+
Homepage = "https://github.com/mohdibrahimaiml/EPI-V2.1.3"
|
|
56
|
+
Documentation = "https://github.com/mohdibrahimaiml/EPI-V2.1.3#readme"
|
|
57
|
+
Repository = "https://github.com/mohdibrahimaiml/EPI-V2.1.3"
|
|
58
|
+
Issues = "https://github.com/mohdibrahimaiml/EPI-V2.1.3/issues"
|
|
58
59
|
|
|
59
60
|
[tool.setuptools.packages.find]
|
|
60
61
|
where = ["."]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|