@agent-diaries/core 0.1.4 → 1.0.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/README.md CHANGED
@@ -69,6 +69,35 @@ async function runAgent() {
69
69
 
70
70
  runAgent();
71
71
  ```
72
+ ### Forcefully Re-running a Task (The Engineering Trick)
73
+
74
+ If you want an agent to strictly avoid duplicate work, use `await diary.claimTask(task)`. It will automatically return `false` if it was done.
75
+
76
+ But if an agent wants to explicitly overwrite or re-do a task because the user demanded it, you skip `claimTask()` entirely and just write the final result using `await diary.writeTaskResult(task, newResult)`. This seamlessly replaces the old memory with the new one.
77
+
78
+ ```text
79
+ 🤖 Agent Alice: Claiming and performing 'Generate Monthly Report'...
80
+ -> Task done! Saving result.
81
+ --------------------------------------------------
82
+ 🤖 Agent Bob: Checking if 'Generate Monthly Report' is done...
83
+ -> 🛑 Found in Diary! Previous result: "Report for May: $12,000 Revenue."
84
+ -> 💬 Informs User: "This report was already generated. Do you want me to re-run it with the latest data?"
85
+ -> 👤 User responds: YES
86
+ -> Agent Bob forcefully re-running the task...
87
+ ```
88
+
89
+ ```typescript
90
+ // 1. Check if it's already done (for logging/informing user)
91
+ if (await diary.hasProcessedTask(currentTask)) {
92
+ console.log("Task is already done. Forcefully re-running per user request...");
93
+ }
94
+
95
+ // 2. Perform the work again
96
+ const updatedResult = "Found 0 warnings, ALL critical errors resolved.";
97
+
98
+ // 3. Skip claimTask() and directly overwrite the old memory
99
+ await diary.writeTaskResult(currentTask, updatedResult);
100
+ ```
72
101
 
73
102
  ## ☁️ Cloud Storage Adapters (Production)
74
103
 
@@ -88,20 +117,21 @@ const diary = new AgentDiary({
88
117
  });
89
118
  ```
90
119
 
91
- ### PostgreSQL (Best for Stateful Architectures)
92
- The `PostgresStorage` adapter natively uses `pg_advisory_lock` to ensure absolute row-level safety during concurrent task evaluation.
120
+ ### MongoDB (Best for Document Scaling)
121
+ The `MongoStorage` adapter natively uses atomic `_id` unique insertion constraints to guarantee row-level safety during concurrent task evaluation, with built-in TTL lock expiration.
93
122
 
94
123
  ```typescript
95
124
  import { AgentDiary } from '@agent-diaries/core';
96
- import { PostgresStorage } from '@agent-diaries/core/dist/adapters/postgres';
97
- import { Pool } from 'pg';
125
+ import { MongoStorage } from '@agent-diaries/core/dist/adapters/mongo';
126
+ import { MongoClient } from 'mongodb';
98
127
 
99
- const pgStorage = new PostgresStorage({ pool: new Pool({ connectionString: process.env.DATABASE_URL }) });
100
- await pgStorage.initialize(); // Creates the state table
128
+ const client = new MongoClient(process.env.MONGO_URI);
129
+ await client.connect();
130
+ const collection = client.db('agent_diaries').collection('tasks');
101
131
 
102
132
  const diary = new AgentDiary({
103
133
  agentId: 'db-bot',
104
- storage: pgStorage
134
+ storage: new MongoStorage({ collection })
105
135
  });
106
136
  ```
107
137
 
@@ -1,14 +1,16 @@
1
1
  import { StorageAdapter } from '../storage';
2
2
  import { Collection } from 'mongodb';
3
+ interface MongoStorageOptions {
4
+ collection: Collection;
5
+ }
3
6
  export declare class MongoStorage<T> implements StorageAdapter<T> {
4
7
  private collection;
5
- private initialized;
6
- constructor(config: {
7
- collection: Collection;
8
- });
8
+ private static indexedCollections;
9
+ constructor(options: MongoStorageOptions);
9
10
  private ensureIndex;
10
11
  private hashString;
11
12
  get(key: string): Promise<T | null>;
12
13
  set(key: string, data: T): Promise<void>;
13
14
  withLock<R>(key: string, fn: () => Promise<R>): Promise<R>;
14
15
  }
16
+ export {};
@@ -7,20 +7,21 @@ exports.MongoStorage = void 0;
7
7
  const crypto_1 = __importDefault(require("crypto"));
8
8
  class MongoStorage {
9
9
  collection;
10
- initialized = false;
11
- constructor(config) {
12
- this.collection = config.collection;
10
+ static indexedCollections = new Set();
11
+ constructor(options) {
12
+ this.collection = options.collection;
13
13
  }
14
14
  async ensureIndex() {
15
- if (this.initialized)
15
+ const ns = this.collection.namespace;
16
+ if (MongoStorage.indexedCollections.has(ns))
16
17
  return;
17
18
  try {
18
- await this.collection.createIndex({ lockedAt: 1 }, { expireAfterSeconds: 30, partialFilterExpression: { lockedAt: { $exists: true } } });
19
+ await this.collection.createIndex({ lockedAt: 1 }, { expireAfterSeconds: 10, partialFilterExpression: { lockedAt: { $exists: true } } });
19
20
  }
20
21
  catch (e) {
21
22
  console.warn('[MongoStorage] Failed to create TTL index:', e);
22
23
  }
23
- this.initialized = true;
24
+ MongoStorage.indexedCollections.add(ns);
24
25
  }
25
26
  hashString(str) {
26
27
  return crypto_1.default.createHash('sha256').update(str).digest('hex');
@@ -57,8 +58,9 @@ class MongoStorage {
57
58
  const jitter = Math.random() * 50;
58
59
  await new Promise(resolve => setTimeout(resolve, backoff + jitter));
59
60
  attempt++;
60
- if (attempt > 60)
61
+ if (attempt > 150) {
61
62
  throw new Error(`[MongoStorage] Lock timeout on key: ${key}`);
63
+ }
62
64
  }
63
65
  try {
64
66
  return await fn();
package/dist/diary.js CHANGED
@@ -107,13 +107,8 @@ class AgentDiary {
107
107
  await this.storage.set(`diary_${this.agentId}`, state);
108
108
  }
109
109
  else {
110
- // If not claimed first, we insert it
111
- const record = { title, signature, result, timestamp: Date.now() };
112
- state.history = [record, ...state.history].slice(0, this.maxHistory);
113
- state.seenSignatures = state.history.map(r => r.signature);
114
- state.runCount += 1;
115
- state.lastRun = Date.now();
116
- await this.storage.set(`diary_${this.agentId}`, state);
110
+ // If not claimed first, we throw a loud error
111
+ throw new Error(`[AgentDiary] Task "${title}" was not claimed. Call claimTask() before writeTaskResult().`);
117
112
  }
118
113
  });
119
114
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-diaries/core",
3
- "version": "0.1.4",
3
+ "version": "1.0.0",
4
4
  "description": "The lightweight, framework-agnostic memory layer for edge AI agents.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",