transactional-ai 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +161 -0
- package/dist/bin/inspect.d.ts +3 -0
- package/dist/bin/inspect.d.ts.map +1 -0
- package/dist/bin/inspect.js +43 -0
- package/dist/bin/inspect.js.map +1 -0
- package/dist/engine/FileStorage.d.ts +10 -0
- package/dist/engine/FileStorage.d.ts.map +1 -0
- package/dist/engine/FileStorage.js +38 -0
- package/dist/engine/FileStorage.js.map +1 -0
- package/dist/engine/RedisStorage.d.ts +16 -0
- package/dist/engine/RedisStorage.d.ts.map +1 -0
- package/dist/engine/RedisStorage.js +38 -0
- package/dist/engine/RedisStorage.js.map +1 -0
- package/dist/engine/Storage.d.ts +7 -0
- package/dist/engine/Storage.d.ts.map +1 -0
- package/dist/engine/Storage.js +3 -0
- package/dist/engine/Storage.js.map +1 -0
- package/dist/engine/Transaction.d.ts +26 -0
- package/dist/engine/Transaction.d.ts.map +1 -0
- package/dist/engine/Transaction.js +85 -0
- package/dist/engine/Transaction.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 omar
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Transactional AI
|
|
2
|
+
|
|
3
|
+
**A reliability protocol for AI Agents.**
|
|
4
|
+
Implement the Saga Pattern with persistent rollback and state recovery for Long-Running Machine (LLM) operations.
|
|
5
|
+
|
|
6
|
+
[](https://www.npmjs.com/package/transactional-ai)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
|
|
9
|
+
## Why use this?
|
|
10
|
+
AI Agents are flaky. Steps fail, APIs time out, and hallucinations happen.
|
|
11
|
+
`transactional-ai` gives you:
|
|
12
|
+
1. **Automatic Rollbacks**: If step 3 fails, steps 2 and 1 are compensated (undone) automatically.
|
|
13
|
+
2. **Persistence**: Transactions survive process crashes using Redis or File storage.
|
|
14
|
+
3. **Observability**: Inspect running transactions via the built-in CLI.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install transactional-ai
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
### 1. The "Litmus Test" (Basic Usage)
|
|
27
|
+
Define a transaction where every action has a compensating rollback action.
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { Transaction } from 'transactional-ai';
|
|
31
|
+
|
|
32
|
+
// 1. Create a named transaction (required for resumability)
|
|
33
|
+
const agent = new Transaction('user-onboarding-123');
|
|
34
|
+
|
|
35
|
+
agent
|
|
36
|
+
.step({
|
|
37
|
+
name: 'create-file',
|
|
38
|
+
execute: async (ctx) => {
|
|
39
|
+
// Do the work
|
|
40
|
+
const file = await googleDrive.createFile('report.txt');
|
|
41
|
+
return file.id;
|
|
42
|
+
},
|
|
43
|
+
compensate: async (fileId) => {
|
|
44
|
+
// Undo the work
|
|
45
|
+
await googleDrive.deleteFile(fileId);
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
.step({
|
|
49
|
+
name: 'email-report',
|
|
50
|
+
execute: async (ctx) => {
|
|
51
|
+
// Use previous results via context or external state
|
|
52
|
+
await emailService.send(ctx.result);
|
|
53
|
+
},
|
|
54
|
+
compensate: async () => {
|
|
55
|
+
await emailService.recallLast();
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// 2. Run it
|
|
60
|
+
await agent.run({ initialData: 'foo' });
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Adding Persistence (Redis)
|
|
64
|
+
To survive process crashes, simply provide a storage adapter.
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { Transaction, RedisStorage } from 'transactional-ai';
|
|
68
|
+
|
|
69
|
+
const storage = new RedisStorage('redis://localhost:6379');
|
|
70
|
+
const agent = new Transaction('workflow-id-555', storage);
|
|
71
|
+
|
|
72
|
+
// If the process crashes here, running this code again
|
|
73
|
+
// will automatically SKIP completed steps and resume at the failure point.
|
|
74
|
+
agent
|
|
75
|
+
.step({ /* ... */ })
|
|
76
|
+
.step({ /* ... */ });
|
|
77
|
+
|
|
78
|
+
await agent.run();
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## CLI Inspector
|
|
84
|
+
You don't need a complex dashboard to see what your agents are doing. Use the included CLI to inspect transaction logs directly from your terminal.
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Inspect a specific transaction ID (File Storage)
|
|
88
|
+
npx tai-inspect workflow-id-555
|
|
89
|
+
|
|
90
|
+
# Inspect using Redis
|
|
91
|
+
export REDIS_URL="redis://localhost:6379"
|
|
92
|
+
npx tai-inspect workflow-id-555
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Output:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
🔍 Inspecting: workflow-id-555
|
|
99
|
+
Source: RedisStorage
|
|
100
|
+
|
|
101
|
+
STEP NAME | STATUS
|
|
102
|
+
------------------------------------
|
|
103
|
+
├── create-file | ✅ completed
|
|
104
|
+
│ └-> Result: "file_xyz123"
|
|
105
|
+
├── email-report | ❌ failed
|
|
106
|
+
└── (comp) create-f..| ✅ completed
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Advanced Usage
|
|
112
|
+
|
|
113
|
+
### Audit Mode (Governance)
|
|
114
|
+
By default, logs are cleared upon success to save storage space. To keep a permanent audit trail for compliance (e.g., "Why did the agent do this?"), enable Audit Mode:
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
const agent = new Transaction('id', storage, {
|
|
118
|
+
cleanupOnSuccess: false
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Manual Rollbacks
|
|
123
|
+
The library handles rollbacks automatically on error. You can trigger them manually by throwing an error inside any step:
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
// Define a step that throws an error to trigger rollback
|
|
127
|
+
agent.step({
|
|
128
|
+
name: 'check-balance',
|
|
129
|
+
execute: async (ctx) => {
|
|
130
|
+
const balance = await getBalance(ctx.userId);
|
|
131
|
+
if (balance < 10) {
|
|
132
|
+
// Throwing an error automatically triggers the compensation
|
|
133
|
+
// for all previous steps.
|
|
134
|
+
throw new Error("Insufficient funds");
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
compensate: async () => {
|
|
138
|
+
// No compensation needed for a read-only check
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Roadmap
|
|
146
|
+
[x] Core Saga Engine (Execute/Compensate)
|
|
147
|
+
|
|
148
|
+
[x] Persistence Adapters (File, Redis)
|
|
149
|
+
|
|
150
|
+
[x] Resumability (Skip completed steps)
|
|
151
|
+
|
|
152
|
+
[x] CLI Inspector (tai-inspect)
|
|
153
|
+
|
|
154
|
+
[ ] Concurrent Transaction Locking
|
|
155
|
+
|
|
156
|
+
[ ] Postgres/SQL Storage Adapter
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## License
|
|
161
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspect.d.ts","sourceRoot":"","sources":["../../bin/inspect.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const RedisStorage_1 = require("../engine/RedisStorage");
|
|
5
|
+
const FileStorage_1 = require("../engine/FileStorage");
|
|
6
|
+
async function main() {
|
|
7
|
+
const [, , txId] = process.argv;
|
|
8
|
+
if (!txId) {
|
|
9
|
+
console.error("Usage: npx transactional-ai inspect <transaction-id>");
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
// Auto-detect storage based on Env Var
|
|
13
|
+
const storage = process.env.REDIS_URL
|
|
14
|
+
? new RedisStorage_1.RedisStorage(process.env.REDIS_URL)
|
|
15
|
+
: new FileStorage_1.FileStorage();
|
|
16
|
+
console.log(`\n🔍 Inspecting Transaction: ${txId}`);
|
|
17
|
+
console.log(` Source: ${storage.constructor.name}\n`);
|
|
18
|
+
const history = await storage.load(txId);
|
|
19
|
+
if (!history) {
|
|
20
|
+
console.error("❌ Transaction not found.");
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
console.log(" STEP NAME | STATUS ");
|
|
24
|
+
console.log(" ------------------------------------");
|
|
25
|
+
history.forEach((step, index) => {
|
|
26
|
+
const isLast = index === history.length - 1;
|
|
27
|
+
// Simple ASCII Tree
|
|
28
|
+
const prefix = isLast ? "└──" : "├──";
|
|
29
|
+
// Status Icon
|
|
30
|
+
const icon = step.status === 'completed' ? '✅' : '⏳';
|
|
31
|
+
console.log(` ${prefix} ${step.name.padEnd(20)} | ${icon} ${step.status}`);
|
|
32
|
+
// If there is a result and it's small, show it
|
|
33
|
+
if (step.result && typeof step.result === 'string' && step.result.length < 50) {
|
|
34
|
+
console.log(` └-> Result: ${step.result}`);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
console.log("\n");
|
|
38
|
+
if (storage instanceof RedisStorage_1.RedisStorage) {
|
|
39
|
+
await storage.disconnect();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
main().catch(console.error);
|
|
43
|
+
//# sourceMappingURL=inspect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspect.js","sourceRoot":"","sources":["../../bin/inspect.ts"],"names":[],"mappings":";;;AACA,yDAAsD;AACtD,uDAAoD;AAEpD,KAAK,UAAU,IAAI;IACjB,MAAM,CAAC,EAAC,EAAE,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAE/B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,CAAC,KAAK,CAAC,sDAAsD,CAAC,CAAC;QACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,uCAAuC;IACvC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS;QACnC,CAAC,CAAC,IAAI,2BAAY,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;QACzC,CAAC,CAAC,IAAI,yBAAW,EAAE,CAAC;IAEtB,OAAO,CAAC,GAAG,CAAC,gCAAgC,IAAI,EAAE,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,cAAc,OAAO,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,CAAC;IAExD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEzC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;IAEvD,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC9B,MAAM,MAAM,GAAG,KAAK,KAAK,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QAC5C,oBAAoB;QACpB,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;QAEtC,cAAc;QACd,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QAErD,OAAO,CAAC,GAAG,CAAC,MAAM,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,IAAI,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QAE7E,+CAA+C;QAC/C,IAAI,IAAI,CAAC,MAAM,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;YAC7E,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACpD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAElB,IAAI,OAAO,YAAY,2BAAY,EAAE,CAAC;QACpC,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;IAC7B,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { StorageAdapter } from './Storage';
|
|
2
|
+
import { StepContext } from './Transaction';
|
|
3
|
+
export declare class FileStorage implements StorageAdapter {
|
|
4
|
+
private dir;
|
|
5
|
+
init(): Promise<void>;
|
|
6
|
+
save(txId: string, state: StepContext[]): Promise<void>;
|
|
7
|
+
load(txId: string): Promise<StepContext[] | null>;
|
|
8
|
+
clear(txId: string): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=FileStorage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileStorage.d.ts","sourceRoot":"","sources":["../../engine/FileStorage.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,qBAAa,WAAY,YAAW,cAAc;IAChD,OAAO,CAAC,GAAG,CAAiD;IAEtD,IAAI;IAIJ,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAKvD,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC;IASjD,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGzC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.FileStorage = void 0;
|
|
7
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
class FileStorage {
|
|
10
|
+
dir = path_1.default.join(process.cwd(), '.transaction-logs');
|
|
11
|
+
async init() {
|
|
12
|
+
try {
|
|
13
|
+
await promises_1.default.mkdir(this.dir, { recursive: true });
|
|
14
|
+
}
|
|
15
|
+
catch { }
|
|
16
|
+
}
|
|
17
|
+
async save(txId, state) {
|
|
18
|
+
await this.init();
|
|
19
|
+
await promises_1.default.writeFile(path_1.default.join(this.dir, `${txId}.json`), JSON.stringify(state, null, 2));
|
|
20
|
+
}
|
|
21
|
+
async load(txId) {
|
|
22
|
+
try {
|
|
23
|
+
const data = await promises_1.default.readFile(path_1.default.join(this.dir, `${txId}.json`), 'utf-8');
|
|
24
|
+
return JSON.parse(data);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async clear(txId) {
|
|
31
|
+
try {
|
|
32
|
+
await promises_1.default.unlink(path_1.default.join(this.dir, `${txId}.json`));
|
|
33
|
+
}
|
|
34
|
+
catch { }
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.FileStorage = FileStorage;
|
|
38
|
+
//# sourceMappingURL=FileStorage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileStorage.js","sourceRoot":"","sources":["../../engine/FileStorage.ts"],"names":[],"mappings":";;;;;;AAAA,2DAA6B;AAC7B,gDAAwB;AAIxB,MAAa,WAAW;IACd,GAAG,GAAG,cAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,mBAAmB,CAAC,CAAC;IAE5D,KAAK,CAAC,IAAI;QACR,IAAI,CAAC;YAAC,MAAM,kBAAE,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACjE,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAY,EAAE,KAAoB;QAC3C,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,MAAM,kBAAE,CAAC,SAAS,CAAC,cAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,OAAO,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1F,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAY;QACrB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,kBAAE,CAAC,QAAQ,CAAC,cAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC;YAC7E,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,IAAY;QACtB,IAAI,CAAC;YAAC,MAAM,kBAAE,CAAC,MAAM,CAAC,cAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACxE,CAAC;CACF;AAxBD,kCAwBC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { StorageAdapter } from './Storage';
|
|
2
|
+
import { StepContext } from './Transaction';
|
|
3
|
+
export declare class RedisStorage implements StorageAdapter {
|
|
4
|
+
private redis;
|
|
5
|
+
private ttlSeconds;
|
|
6
|
+
/**
|
|
7
|
+
* @param connectionString Redis connection URL (e.g., "redis://localhost:6379")
|
|
8
|
+
* @param ttlSeconds How long to keep logs (default: 1 hour)
|
|
9
|
+
*/
|
|
10
|
+
constructor(connectionString: string, ttlSeconds?: number);
|
|
11
|
+
save(txId: string, state: StepContext[]): Promise<void>;
|
|
12
|
+
load(txId: string): Promise<StepContext[] | null>;
|
|
13
|
+
clear(txId: string): Promise<void>;
|
|
14
|
+
disconnect(): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=RedisStorage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RedisStorage.d.ts","sourceRoot":"","sources":["../../engine/RedisStorage.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,qBAAa,YAAa,YAAW,cAAc;IACjD,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,UAAU,CAAS;IAE3B;;;OAGG;gBACS,gBAAgB,EAAE,MAAM,EAAE,UAAU,SAAO;IAKjD,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAOvD,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC;IAKjD,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKlC,UAAU;CAGjB"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.RedisStorage = void 0;
|
|
7
|
+
const ioredis_1 = __importDefault(require("ioredis"));
|
|
8
|
+
class RedisStorage {
|
|
9
|
+
redis;
|
|
10
|
+
ttlSeconds;
|
|
11
|
+
/**
|
|
12
|
+
* @param connectionString Redis connection URL (e.g., "redis://localhost:6379")
|
|
13
|
+
* @param ttlSeconds How long to keep logs (default: 1 hour)
|
|
14
|
+
*/
|
|
15
|
+
constructor(connectionString, ttlSeconds = 3600) {
|
|
16
|
+
this.redis = new ioredis_1.default(connectionString);
|
|
17
|
+
this.ttlSeconds = ttlSeconds;
|
|
18
|
+
}
|
|
19
|
+
async save(txId, state) {
|
|
20
|
+
const key = `tx:${txId}`;
|
|
21
|
+
await this.redis.set(key, JSON.stringify(state));
|
|
22
|
+
// Reset expiration timer on every update so active transactions don't expire
|
|
23
|
+
await this.redis.expire(key, this.ttlSeconds);
|
|
24
|
+
}
|
|
25
|
+
async load(txId) {
|
|
26
|
+
const data = await this.redis.get(`tx:${txId}`);
|
|
27
|
+
return data ? JSON.parse(data) : null;
|
|
28
|
+
}
|
|
29
|
+
async clear(txId) {
|
|
30
|
+
await this.redis.del(`tx:${txId}`);
|
|
31
|
+
}
|
|
32
|
+
// Helper to close connection when app shuts down
|
|
33
|
+
async disconnect() {
|
|
34
|
+
await this.redis.quit();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.RedisStorage = RedisStorage;
|
|
38
|
+
//# sourceMappingURL=RedisStorage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RedisStorage.js","sourceRoot":"","sources":["../../engine/RedisStorage.ts"],"names":[],"mappings":";;;;;;AAAA,sDAA4B;AAI5B,MAAa,YAAY;IACf,KAAK,CAAQ;IACb,UAAU,CAAS;IAE3B;;;OAGG;IACH,YAAY,gBAAwB,EAAE,UAAU,GAAG,IAAI;QACrD,IAAI,CAAC,KAAK,GAAG,IAAI,iBAAK,CAAC,gBAAgB,CAAC,CAAC;QACzC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAY,EAAE,KAAoB;QAC3C,MAAM,GAAG,GAAG,MAAM,IAAI,EAAE,CAAC;QACzB,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;QACjD,6EAA6E;QAC7E,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAY;QACrB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;QAChD,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,IAAY;QACtB,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IACrC,CAAC;IAED,iDAAiD;IACjD,KAAK,CAAC,UAAU;QACd,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IAC1B,CAAC;CACF;AAjCD,oCAiCC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { StepContext } from './Transaction';
|
|
2
|
+
export interface StorageAdapter {
|
|
3
|
+
save(transactionId: string, state: StepContext[]): Promise<void>;
|
|
4
|
+
load(transactionId: string): Promise<StepContext[] | null>;
|
|
5
|
+
clear(transactionId: string): Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=Storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Storage.d.ts","sourceRoot":"","sources":["../../engine/Storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,CAAC;IAC3D,KAAK,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Storage.js","sourceRoot":"","sources":["../../engine/Storage.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { StorageAdapter } from './Storage';
|
|
2
|
+
export type StepContext<T = any> = {
|
|
3
|
+
name: string;
|
|
4
|
+
result?: T;
|
|
5
|
+
status: 'completed' | 'pending';
|
|
6
|
+
};
|
|
7
|
+
export type StepDefinition<T> = {
|
|
8
|
+
do: () => Promise<T> | T;
|
|
9
|
+
undo: (result: T) => Promise<void> | void;
|
|
10
|
+
};
|
|
11
|
+
type TransactionOptions = {
|
|
12
|
+
cleanupOnSuccess?: boolean;
|
|
13
|
+
};
|
|
14
|
+
export declare class Transaction {
|
|
15
|
+
private stepStack;
|
|
16
|
+
private history;
|
|
17
|
+
private id;
|
|
18
|
+
private storage?;
|
|
19
|
+
private cleanupOnSuccess;
|
|
20
|
+
constructor(id: string, storage?: StorageAdapter, options?: TransactionOptions);
|
|
21
|
+
run(workflow: (tx: Transaction) => Promise<void>): Promise<void>;
|
|
22
|
+
step<T>(name: string, definition: StepDefinition<T>): Promise<T>;
|
|
23
|
+
private rollback;
|
|
24
|
+
}
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=Transaction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Transaction.d.ts","sourceRoot":"","sources":["../../engine/Transaction.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,MAAM,MAAM,WAAW,CAAC,CAAC,GAAG,GAAG,IAAI;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,CAAC,CAAC;IACX,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;IAC9B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACzB,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC3C,CAAC;AASF,KAAK,kBAAkB,GAAG;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF,qBAAa,WAAW;IACtB,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,EAAE,CAAS;IACnB,OAAO,CAAC,OAAO,CAAC,CAAiB;IACjC,OAAO,CAAC,gBAAgB,CAAU;gBAEtB,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,EAAE,OAAO,GAAE,kBAAuB;IAO5E,GAAG,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAyBhE,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;YAgCxD,QAAQ;CAWvB"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Transaction = void 0;
|
|
4
|
+
class Transaction {
|
|
5
|
+
stepStack = [];
|
|
6
|
+
history = new Map();
|
|
7
|
+
id;
|
|
8
|
+
storage;
|
|
9
|
+
cleanupOnSuccess;
|
|
10
|
+
constructor(id, storage, options = {}) {
|
|
11
|
+
this.id = id;
|
|
12
|
+
this.storage = storage;
|
|
13
|
+
// Default to TRUE (clean up) unless told otherwise
|
|
14
|
+
this.cleanupOnSuccess = options.cleanupOnSuccess ?? true;
|
|
15
|
+
}
|
|
16
|
+
async run(workflow) {
|
|
17
|
+
// 1. Load previous state if storage is provided
|
|
18
|
+
if (this.storage) {
|
|
19
|
+
const savedState = await this.storage.load(this.id);
|
|
20
|
+
if (savedState) {
|
|
21
|
+
console.log(`[Transaction] 🔄 Resuming ${this.id} with ${savedState.length} completed steps.`);
|
|
22
|
+
savedState.forEach(s => this.history.set(s.name, s.result));
|
|
23
|
+
// Note: We can't re-hydrate the 'undo' functions until the code runs again.
|
|
24
|
+
// The 'step' method handles re-hydrating the stack.
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
await workflow(this);
|
|
29
|
+
// CHANGED: Only clear if flag is true
|
|
30
|
+
if (this.storage && this.cleanupOnSuccess) {
|
|
31
|
+
await this.storage.clear(this.id);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
console.error(`\n🔴 [Transaction Failed] Error: ${error instanceof Error ? error.message : error}`);
|
|
36
|
+
await this.rollback();
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async step(name, definition) {
|
|
41
|
+
// 1. Check if we already did this step (Resumability!)
|
|
42
|
+
if (this.history.has(name)) {
|
|
43
|
+
console.log(`⏩ [Skip: ${name}] Already completed.`);
|
|
44
|
+
const result = this.history.get(name);
|
|
45
|
+
// CRITICAL: We still need to push the undo handler to the stack
|
|
46
|
+
// so we can rollback if a LATER step fails.
|
|
47
|
+
this.stepStack.push({ name, undo: () => definition.undo(result) });
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
// 2. If not, Execute
|
|
51
|
+
console.log(`➡️ [Do: ${name}] Executing...`);
|
|
52
|
+
const result = await definition.do();
|
|
53
|
+
// 3. Update State
|
|
54
|
+
this.stepStack.push({ name, undo: () => definition.undo(result) });
|
|
55
|
+
// 4. Persist
|
|
56
|
+
if (this.storage) {
|
|
57
|
+
const currentHistory = this.stepStack.map(s => ({
|
|
58
|
+
name: s.name,
|
|
59
|
+
result: s.name === name ? result : this.history.get(s.name), // simplified for demo
|
|
60
|
+
status: 'completed'
|
|
61
|
+
}));
|
|
62
|
+
// In a real app, map the full history properly
|
|
63
|
+
await this.storage.save(this.id, currentHistory);
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
async rollback() {
|
|
68
|
+
const stepsToUndo = [...this.stepStack].reverse();
|
|
69
|
+
for (const step of stepsToUndo) {
|
|
70
|
+
console.log(`⬅️ [Undo: ${step.name}] Reverting...`);
|
|
71
|
+
try {
|
|
72
|
+
await step.undo();
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
console.error(` ❌ [CRITICAL] Undo failed for '${step.name}'`, err);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Clear storage after rollback so we don't resume into a broken state
|
|
79
|
+
if (this.storage)
|
|
80
|
+
await this.storage.clear(this.id);
|
|
81
|
+
this.stepStack = [];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
exports.Transaction = Transaction;
|
|
85
|
+
//# sourceMappingURL=Transaction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Transaction.js","sourceRoot":"","sources":["../../engine/Transaction.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { Transaction } from './engine/Transaction';
|
|
2
|
+
export type { StepContext, StepDefinition } from './engine/Transaction';
|
|
3
|
+
export { StorageAdapter } from './engine/Storage';
|
|
4
|
+
export { FileStorage } from './engine/FileStorage';
|
|
5
|
+
export { RedisStorage } from './engine/RedisStorage';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGxE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RedisStorage = exports.FileStorage = exports.Transaction = void 0;
|
|
4
|
+
// Export the core engine
|
|
5
|
+
var Transaction_1 = require("./engine/Transaction");
|
|
6
|
+
Object.defineProperty(exports, "Transaction", { enumerable: true, get: function () { return Transaction_1.Transaction; } });
|
|
7
|
+
var FileStorage_1 = require("./engine/FileStorage");
|
|
8
|
+
Object.defineProperty(exports, "FileStorage", { enumerable: true, get: function () { return FileStorage_1.FileStorage; } });
|
|
9
|
+
var RedisStorage_1 = require("./engine/RedisStorage");
|
|
10
|
+
Object.defineProperty(exports, "RedisStorage", { enumerable: true, get: function () { return RedisStorage_1.RedisStorage; } });
|
|
11
|
+
// We do NOT export the internal 'examples' or 'bin' scripts.
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";;;AAAA,yBAAyB;AACzB,oDAAmD;AAA1C,0GAAA,WAAW,OAAA;AAKpB,oDAAmD;AAA1C,0GAAA,WAAW,OAAA;AACpB,sDAAqD;AAA5C,4GAAA,YAAY,OAAA;AAErB,6DAA6D"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "transactional-ai",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A reliability protocol for AI Agents. Saga pattern with persistent rollback.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"tai-inspect": "dist/bin/inspect.js"
|
|
8
|
+
},
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"postbuild": "chmod +x dist/bin/inspect.js",
|
|
16
|
+
"test": "jest",
|
|
17
|
+
"prepublishOnly": "npm run build"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"ai",
|
|
21
|
+
"agent",
|
|
22
|
+
"transaction",
|
|
23
|
+
"saga",
|
|
24
|
+
"reliability",
|
|
25
|
+
"llm"
|
|
26
|
+
],
|
|
27
|
+
"author": "Your Name",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
31
|
+
"@testing-library/react": "^16.3.1",
|
|
32
|
+
"@types/ioredis": "^5.0.0",
|
|
33
|
+
"@types/jest": "^30.0.0",
|
|
34
|
+
"jest": "^30.2.0",
|
|
35
|
+
"jest-environment-jsdom": "^30.2.0",
|
|
36
|
+
"react": "19.2.3",
|
|
37
|
+
"react-dom": "19.2.3",
|
|
38
|
+
"ts-jest": "^29.4.6",
|
|
39
|
+
"tsx": "^4.21.0",
|
|
40
|
+
"typescript": "^5.9.3"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@prisma/client": "6.15.0",
|
|
44
|
+
"ioredis": "^5.9.1",
|
|
45
|
+
"node-fetch": "^3.3.2",
|
|
46
|
+
"openai": "^6.15.0",
|
|
47
|
+
"prisma": "6.15.0"
|
|
48
|
+
}
|
|
49
|
+
}
|