@adecore/agents 0.33.2 → 0.33.3
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.
|
@@ -5,6 +5,7 @@ export interface RecordDirectoryOptions<T> {
|
|
|
5
5
|
schema: z.ZodType<T>;
|
|
6
6
|
idOf(record: T): string;
|
|
7
7
|
write?: (path: string, text: string) => Promise<void>;
|
|
8
|
+
remove?: (path: string) => Promise<void>;
|
|
8
9
|
keep?(record: T): T | null;
|
|
9
10
|
}
|
|
10
11
|
export declare class RecordDirectory<T> {
|
|
@@ -12,9 +13,10 @@ export declare class RecordDirectory<T> {
|
|
|
12
13
|
private readonly schema;
|
|
13
14
|
private readonly idOf;
|
|
14
15
|
private readonly writeFile;
|
|
16
|
+
private readonly removeFile;
|
|
15
17
|
private readonly keep;
|
|
16
18
|
private readonly records;
|
|
17
|
-
private readonly
|
|
19
|
+
private readonly files;
|
|
18
20
|
constructor(options: RecordDirectoryOptions<T>);
|
|
19
21
|
load(): Promise<void>;
|
|
20
22
|
get(id: string): T | undefined;
|
package/dist/record-directory.js
CHANGED
|
@@ -16,15 +16,20 @@ export class RecordDirectory {
|
|
|
16
16
|
schema;
|
|
17
17
|
idOf;
|
|
18
18
|
writeFile;
|
|
19
|
+
removeFile;
|
|
19
20
|
keep;
|
|
20
21
|
records = new Map();
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
/*
|
|
23
|
+
* One write or remove at a time per record, so an older write never lands after a newer one and
|
|
24
|
+
* no delete starts while another of the same file is pending, which Windows can fail with EFAULT.
|
|
25
|
+
*/
|
|
26
|
+
files = new KeyedSerializer();
|
|
23
27
|
constructor(options) {
|
|
24
28
|
this.dir = options.dir;
|
|
25
29
|
this.schema = options.schema;
|
|
26
30
|
this.idOf = options.idOf;
|
|
27
31
|
this.writeFile = options.write ?? writeAtomic;
|
|
32
|
+
this.removeFile = options.remove ?? removeFile;
|
|
28
33
|
this.keep = options.keep ?? null;
|
|
29
34
|
}
|
|
30
35
|
/* Reads what an earlier run of the host wrote down. Call before anything can ask. */
|
|
@@ -59,7 +64,7 @@ export class RecordDirectory {
|
|
|
59
64
|
}
|
|
60
65
|
const record = this.keep === null ? parsed.data : this.keep(parsed.data);
|
|
61
66
|
if (record === null) {
|
|
62
|
-
await removeFile(join(this.dir, name));
|
|
67
|
+
await this.removeFile(join(this.dir, name));
|
|
63
68
|
continue;
|
|
64
69
|
}
|
|
65
70
|
this.records.set(this.idOf(record), record);
|
|
@@ -82,23 +87,23 @@ export class RecordDirectory {
|
|
|
82
87
|
write(record) {
|
|
83
88
|
const id = this.idOf(record);
|
|
84
89
|
this.records.set(id, record);
|
|
85
|
-
return this.
|
|
90
|
+
return this.files.run(id, async () => {
|
|
86
91
|
if (this.records.get(id) !== record) {
|
|
87
92
|
return false;
|
|
88
93
|
}
|
|
89
94
|
await mkdir(this.dir, { recursive: true, mode: 0o700 });
|
|
90
95
|
await this.writeFile(this.pathOf(id), JSON.stringify(record));
|
|
91
96
|
if (!this.records.has(id)) {
|
|
92
|
-
await removeFile(this.pathOf(id));
|
|
97
|
+
await this.removeFile(this.pathOf(id));
|
|
93
98
|
return false;
|
|
94
99
|
}
|
|
95
100
|
return true;
|
|
96
101
|
});
|
|
97
102
|
}
|
|
98
|
-
/* Forgets a record here and now; its file follows. */
|
|
103
|
+
/* Forgets a record here and now; its file follows, after what is queued for it. */
|
|
99
104
|
remove(id) {
|
|
100
105
|
this.records.delete(id);
|
|
101
|
-
return removeFile(this.pathOf(id));
|
|
106
|
+
return this.files.run(id, () => this.removeFile(this.pathOf(id)));
|
|
102
107
|
}
|
|
103
108
|
async prune(drop) {
|
|
104
109
|
for (const listed of this.all()) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adecore/agents",
|
|
3
|
-
"version": "0.33.
|
|
3
|
+
"version": "0.33.3",
|
|
4
4
|
"description": "Node-compatible agent chat hosts, providers, accounts, usage and durable task coordination.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -81,8 +81,8 @@
|
|
|
81
81
|
"test": "bun --conditions=source test"
|
|
82
82
|
},
|
|
83
83
|
"dependencies": {
|
|
84
|
-
"@adecore/agent-contracts": "0.33.
|
|
85
|
-
"@adecore/intelligent-ui": "0.33.
|
|
84
|
+
"@adecore/agent-contracts": "0.33.3",
|
|
85
|
+
"@adecore/intelligent-ui": "0.33.3",
|
|
86
86
|
"zod": "^4.6.5"
|
|
87
87
|
},
|
|
88
88
|
"devDependencies": {
|
package/src/record-directory.ts
CHANGED
|
@@ -14,6 +14,8 @@ export interface RecordDirectoryOptions<T> {
|
|
|
14
14
|
schema: z.ZodType<T>;
|
|
15
15
|
idOf(record: T): string;
|
|
16
16
|
write?: (path: string, text: string) => Promise<void>;
|
|
17
|
+
// Stands in for `removeFile` whole, so it must take a missing file as removed: a write and a remove delete twice.
|
|
18
|
+
remove?: (path: string) => Promise<void>;
|
|
17
19
|
/*
|
|
18
20
|
* What a record read from disk is worth keeping as, for a store that drops what went stale while
|
|
19
21
|
* the host was down. Null takes the file with it.
|
|
@@ -31,16 +33,21 @@ export class RecordDirectory<T> {
|
|
|
31
33
|
private readonly schema: z.ZodType<T>;
|
|
32
34
|
private readonly idOf: (record: T) => string;
|
|
33
35
|
private readonly writeFile: (path: string, text: string) => Promise<void>;
|
|
36
|
+
private readonly removeFile: (path: string) => Promise<void>;
|
|
34
37
|
private readonly keep: ((record: T) => T | null) | null;
|
|
35
38
|
private readonly records = new Map<string, T>();
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
/*
|
|
40
|
+
* One write or remove at a time per record, so an older write never lands after a newer one and
|
|
41
|
+
* no delete starts while another of the same file is pending, which Windows can fail with EFAULT.
|
|
42
|
+
*/
|
|
43
|
+
private readonly files = new KeyedSerializer();
|
|
38
44
|
|
|
39
45
|
constructor(options: RecordDirectoryOptions<T>) {
|
|
40
46
|
this.dir = options.dir;
|
|
41
47
|
this.schema = options.schema;
|
|
42
48
|
this.idOf = options.idOf;
|
|
43
49
|
this.writeFile = options.write ?? writeAtomic;
|
|
50
|
+
this.removeFile = options.remove ?? removeFile;
|
|
44
51
|
this.keep = options.keep ?? null;
|
|
45
52
|
}
|
|
46
53
|
|
|
@@ -74,7 +81,7 @@ export class RecordDirectory<T> {
|
|
|
74
81
|
}
|
|
75
82
|
const record = this.keep === null ? parsed.data : this.keep(parsed.data);
|
|
76
83
|
if (record === null) {
|
|
77
|
-
await removeFile(join(this.dir, name));
|
|
84
|
+
await this.removeFile(join(this.dir, name));
|
|
78
85
|
continue;
|
|
79
86
|
}
|
|
80
87
|
this.records.set(this.idOf(record), record);
|
|
@@ -101,24 +108,24 @@ export class RecordDirectory<T> {
|
|
|
101
108
|
write(record: T): Promise<boolean> {
|
|
102
109
|
const id = this.idOf(record);
|
|
103
110
|
this.records.set(id, record);
|
|
104
|
-
return this.
|
|
111
|
+
return this.files.run(id, async () => {
|
|
105
112
|
if (this.records.get(id) !== record) {
|
|
106
113
|
return false;
|
|
107
114
|
}
|
|
108
115
|
await mkdir(this.dir, { recursive: true, mode: 0o700 });
|
|
109
116
|
await this.writeFile(this.pathOf(id), JSON.stringify(record));
|
|
110
117
|
if (!this.records.has(id)) {
|
|
111
|
-
await removeFile(this.pathOf(id));
|
|
118
|
+
await this.removeFile(this.pathOf(id));
|
|
112
119
|
return false;
|
|
113
120
|
}
|
|
114
121
|
return true;
|
|
115
122
|
});
|
|
116
123
|
}
|
|
117
124
|
|
|
118
|
-
/* Forgets a record here and now; its file follows. */
|
|
125
|
+
/* Forgets a record here and now; its file follows, after what is queued for it. */
|
|
119
126
|
remove(id: string): Promise<void> {
|
|
120
127
|
this.records.delete(id);
|
|
121
|
-
return removeFile(this.pathOf(id));
|
|
128
|
+
return this.files.run(id, () => this.removeFile(this.pathOf(id)));
|
|
122
129
|
}
|
|
123
130
|
|
|
124
131
|
async prune(drop: (record: T) => boolean): Promise<void> {
|