proactive-gate 0.2.4 → 0.3.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 +51 -16
- package/README.tr.md +56 -17
- package/dist/src/store-contract.d.ts +11 -0
- package/dist/src/store-contract.js +118 -0
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@ English | [Türkçe](README.tr.md)
|
|
|
9
9
|
<img src="https://img.shields.io/bundlephobia/minzip/proactive-gate?style=flat-square&color=111111" alt="minzipped size">
|
|
10
10
|
<img src="https://img.shields.io/github/stars/Bubblegunn/proactive-gate?style=flat-square&color=111111" alt="stars">
|
|
11
11
|
<img src="https://img.shields.io/badge/license-MIT-111111?style=flat-square" alt="MIT">
|
|
12
|
+
<a href="https://doi.org/10.5281/zenodo.22393512"><img src="https://img.shields.io/badge/DOI-10.5281%2Fzenodo.22393512-111111?style=flat-square" alt="DOI"></a>
|
|
12
13
|
</p>
|
|
13
14
|
|
|
14
15
|
Decide whether a proactive AI agent may reach a user right now, and log why not.
|
|
@@ -138,21 +139,23 @@ consumed in check order at commit, so when a weekly check passes and the daily o
|
|
|
138
139
|
refuses, that weekly unit is spent without a delivery. It only happens when two commits
|
|
139
140
|
race after a shared evaluate.
|
|
140
141
|
|
|
141
|
-
###
|
|
142
|
+
### One limit you should know before you adopt this
|
|
142
143
|
|
|
143
|
-
|
|
144
|
+
It is not a bug, and it is pinned by tests so a future change has to be deliberate.
|
|
144
145
|
|
|
145
|
-
**The week is the ISO week, so the weekly budget refills on Monday.**
|
|
146
|
-
week
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
146
|
+
**The week is the ISO week, so the weekly budget refills on Monday.** Monday is not where
|
|
147
|
+
the week starts for most people: of the twenty most populous countries, CLDR gives Monday
|
|
148
|
+
to seven, Sunday to eleven and Saturday to two, which you can read yourself with
|
|
149
|
+
`new Intl.Locale("und-EG").getWeekInfo().firstDay`. Where the working week runs Sunday to
|
|
150
|
+
Thursday, an ISO refill lands one day in: a user who spends the budget on Sunday has it back
|
|
151
|
+
on Monday with four working days still to run. The key is ISO anyway, for two reasons. A
|
|
152
|
+
counter already in your store is keyed by it, and moving the key silently resets every user
|
|
153
|
+
mid-week. And the day the counter turns over is not the day the user is protected on: quiet
|
|
154
|
+
hours already read the user's own weekday, including a Friday or a Shabbat window, and they
|
|
155
|
+
are what decides when a notification is allowed. The budget only decides how many. If the ISO
|
|
156
|
+
week is wrong for your users, pass your own budget check keyed how you like; it is an object
|
|
157
|
+
with an `id` and a `run`, it composes in the order you choose, and the trace will show it
|
|
158
|
+
firing beside the built-in ones.
|
|
156
159
|
|
|
157
160
|
Order is a design decision and it should be visible. Consent has to come before
|
|
158
161
|
everything. Quiet hours have to come before the budget, or a rejected candidate
|
|
@@ -433,6 +436,23 @@ adding a package dependency. It was contributed by
|
|
|
433
436
|
[@aaqib-hafeez-khan-in](https://github.com/aaqib-hafeez-khan-in) in [#3](https://github.com/Bubblegunn/proactive-gate/pull/3). `SqliteStore` requires Node.js 22.5 or newer; the SQLite module
|
|
434
437
|
is loaded only when the store is constructed so the package can still be used on Node.js 20. On Node 22 the module prints an ExperimentalWarning on first use; it is stable from Node 24.
|
|
435
438
|
|
|
439
|
+
**Writing your own store?** `proactive-gate/store-contract` exports the same suite these three are
|
|
440
|
+
held to, so you can prove yours behaves rather than hope:
|
|
441
|
+
|
|
442
|
+
```ts
|
|
443
|
+
import { storeContract } from "proactive-gate/store-contract";
|
|
444
|
+
storeContract("PostgresStore", (clock) => new PostgresStore({ clock }));
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
It checks `get`, `set` and `del`, `incr` from an absent key, concurrent `incr` atomicity, the
|
|
448
|
+
expiry boundary, and that a TTL given to `set` and one given to `incr` agree, then replays a
|
|
449
|
+
seeded random operation sequence against `MemoryStore`. A store whose backend owns the clock
|
|
450
|
+
passes `expiry: "skip"` and those cases are reported as skipped rather than quietly dropped. It
|
|
451
|
+
was contributed by [@aaqib-hafeez-khan-in](https://github.com/aaqib-hafeez-khan-in) in
|
|
452
|
+
[#24](https://github.com/Bubblegunn/proactive-gate/pull/24), and lives on its own subpath so
|
|
453
|
+
importing the package never pulls `node:test` into your bundle. See
|
|
454
|
+
[docs/store-contract.md](docs/store-contract.md).
|
|
455
|
+
|
|
436
456
|
## Fail open, on purpose
|
|
437
457
|
|
|
438
458
|
When a store-backed check throws (Redis is down), the default lets the candidate
|
|
@@ -550,8 +570,10 @@ pip install proactive-gate
|
|
|
550
570
|
```
|
|
551
571
|
|
|
552
572
|
To run an unreleased state, install from the repository instead: `pip install "proactive-gate @
|
|
553
|
-
git+https://github.com/Bubblegunn/proactive-gate#subdirectory=python"`. The published
|
|
554
|
-
|
|
573
|
+
git+https://github.com/Bubblegunn/proactive-gate#subdirectory=python"`. The Python package is published by
|
|
574
|
+
the same workflow as the npm one, so it carries PyPI publish attestations naming the repository
|
|
575
|
+
and the workflow that built each file. Releases before 0.2.2 were uploaded from a local build with
|
|
576
|
+
a token and carry none.
|
|
555
577
|
|
|
556
578
|
```python
|
|
557
579
|
from proactive_gate import Gate
|
|
@@ -719,7 +741,20 @@ before. [@aaqib-hafeez-khan-in](https://github.com/aaqib-hafeez-khan-in) wrote `
|
|
|
719
741
|
([#3](https://github.com/Bubblegunn/proactive-gate/pull/3)) and
|
|
720
742
|
[@edwardsong08](https://github.com/edwardsong08) wrote the weekly budget
|
|
721
743
|
([#9](https://github.com/Bubblegunn/proactive-gate/pull/9)). Both shipped in 0.1.2 and are in
|
|
722
|
-
every release since, including the one you install today.
|
|
744
|
+
every release since, including the one you install today. @aaqib-hafeez-khan-in came back for a
|
|
745
|
+
second one and wrote the store contract suite in [#24](https://github.com/Bubblegunn/proactive-gate/pull/24).
|
|
746
|
+
|
|
747
|
+
## Cite this
|
|
748
|
+
|
|
749
|
+
Every release is archived on Zenodo with a DOI, so a paper or a report can point at the
|
|
750
|
+
exact code it ran.
|
|
751
|
+
|
|
752
|
+
[](https://doi.org/10.5281/zenodo.22393512)
|
|
753
|
+
|
|
754
|
+
That is the **concept** DOI: it always resolves to the newest version. To cite the exact
|
|
755
|
+
version you ran, open that page, pick the version in the sidebar, and use the DOI shown
|
|
756
|
+
there. `CITATION.cff` in this repository carries the same identifier, so GitHub's "Cite this
|
|
757
|
+
repository" button produces correct BibTeX and APA without any copying by hand.
|
|
723
758
|
|
|
724
759
|
## Development
|
|
725
760
|
|
package/README.tr.md
CHANGED
|
@@ -81,12 +81,37 @@ olurdu.
|
|
|
81
81
|
| 5 | `snooze()` | `user.snoozedUntil` gelecekteyse | genel duraklatma |
|
|
82
82
|
| 6 | `mute()` | `candidate.type`, `user.mutedTypes` içindeyse | tür bazlı susturma |
|
|
83
83
|
| 7 | `intensity()` | öncelik, kullanıcının yoğunluk tabanının altındaysa | low yalnızca high duyar, normal normal ve üstünü, high her şeyi |
|
|
84
|
-
| 8 | `quietHours({ priorityFloor })` | kullanıcının yerel sessiz penceresi içindeyse | IANA saat dilimi, pencere gece yarısını geçebilir, taban ve üstünde atlanır |
|
|
84
|
+
| 8 | `quietHours({ priorityFloor })` | kullanıcının yerel sessiz penceresi içindeyse | IANA saat dilimi, pencere gece yarısını geçebilir, taban ve üstünde atlanır; her gün tek pencere ya da [güne göre bir çizelge](#güne-göre-değişen-sessiz-saatler) |
|
|
85
85
|
| 9 | `trustRamp({ days, minPriority })` | kullanıcı `days` günden yeniyse ve öncelik tabanın altındaysa | sistem, kullanıcı en az bağışlayıcıyken en az kalibredir |
|
|
86
86
|
| 10 | `dismissalCooldown({ dismissals, withinDays, silenceDays })` | kullanıcı o türü pencere içinde `dismissals` kez reddettiyse | `gate.record(user, candidate, "dismissed")` ile beslenir; her yeni ret sessizliği yeniden başlatır |
|
|
87
87
|
| 11 | `adaptiveTiming({ nextGoodMoment, surfacesFor })` | asla | reddetmez: `deliverAt` değerini taşır ya da yüzeyleri daraltır; `nonRejecting` işaretli bir kontrol istese de reddedemez |
|
|
88
88
|
| 12 | `dailyBudget({ limit, bypassPriority })` | kullanıcının yerel gün sayacı sınırdaysa | `evaluate` okur, `commit` atomik artırır ve yine de reddedebilir |
|
|
89
89
|
|
|
90
|
+
### Güne göre değişen sessiz saatler
|
|
91
|
+
|
|
92
|
+
Çalışma haftası her yerde pazartesiden cumaya değildir ve tatil günü zaten hafta içi
|
|
93
|
+
değildir. `quietHours` tek bir pencerenin yanında bir çizelge de alır:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
quietHours: {
|
|
97
|
+
default: { start: "22:00", end: "08:00" },
|
|
98
|
+
days: { fri: { start: "00:00", end: "23:59" }, sat: { start: "00:00", end: "23:59" }, sun: null },
|
|
99
|
+
dates: { "2026-12-25": { start: "00:00", end: "23:59" } },
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Tarih haftanın gününü, o da varsayılanı yener; `null` o günün sessiz saati yok demektir ve
|
|
104
|
+
varsayılanın içinden bir iş günü böyle oyulur. Bir pencere açıldığı güne aittir, yani gece
|
|
105
|
+
yarısını geçen bir pencere ertesi sabahı susturur ve gerekçe hangi günden geldiğini söyler.
|
|
106
|
+
|
|
107
|
+
Bunun bilerek yapmadığı iki şey var. Gömülü bir tatil takvimi yok: hangi tarihleri
|
|
108
|
+
tuttuğunuz size aittir, gömülü olan ise kimse fark etmeden bayatlar. Ve tek bir satır 24
|
|
109
|
+
saatten fazlasını anlatamaz, yani cuma akşamından cumartesi akşamına uzanan bir sessizlik
|
|
110
|
+
iki satırdır: `fri: 18:00 to 00:00` ve `sat: 00:00 to 20:00`.
|
|
111
|
+
|
|
112
|
+
Tek pencere geçmek eskisi gibi çalışır ve yaygın durum olmayı sürdürür; her günü aynı
|
|
113
|
+
pencereye çıkan bir çizelge, o pencereyle birebir aynı davranır.
|
|
114
|
+
|
|
90
115
|
Sıra bir tasarım kararıdır ve görünür olmalıdır. Rıza her şeyden önce gelmelidir. Sessiz
|
|
91
116
|
saatler bütçeden önce gelmelidir, yoksa reddedilen bir aday hiç yapmadığı bir teslimi
|
|
92
117
|
tüketir. İstediğiniz gibi yeniden sıralayın; iz ne yaptığınızı gösterecektir.
|
|
@@ -227,22 +252,24 @@ işyerinde sürekli ulaşılabilir olmaları beklendiği için katılmayı redde
|
|
|
227
252
|
seçmediği bir sessizliğin bir bedeli var ve o bedel bu kütüphanenin yazdığı hiçbir izde
|
|
228
253
|
görünmüyor.
|
|
229
254
|
|
|
230
|
-
## Benimsemeden önce bilmeniz gereken
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
**Hafta, ISO haftasıdır; haftalık bütçe pazartesi yenilenir.**
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
255
|
+
## Benimsemeden önce bilmeniz gereken bir sınır
|
|
256
|
+
|
|
257
|
+
Hata değil ve testle sabitlendi, böylece ileride değişecekse bilerek değişir.
|
|
258
|
+
|
|
259
|
+
**Hafta, ISO haftasıdır; haftalık bütçe pazartesi yenilenir.** Pazartesi, çoğu insan için
|
|
260
|
+
haftanın başladığı gün değildir: en kalabalık yirmi ülkeden CLDR'ye göre yedisinde
|
|
261
|
+
pazartesi, on birinde pazar, ikisinde cumartesi başlar; bunu kendiniz
|
|
262
|
+
`new Intl.Locale("und-EG").getWeekInfo().firstDay` ile okuyabilirsiniz. Çalışma haftası
|
|
263
|
+
pazardan perşembeye uzanan yerlerde ISO yenilenmesi haftanın birinci gününe denk gelir:
|
|
264
|
+
pazar günü bütçesini harcayan bir kullanıcı pazartesi sabahı bütçesini geri alır ve önünde
|
|
265
|
+
hâlâ dört iş günü vardır. Anahtar yine de ISO, iki nedenle. Deponuzdaki sayaç bu anahtarla
|
|
266
|
+
tutuluyor ve anahtarı taşımak her kullanıcıyı haftanın ortasında sessizce sıfırlar. Ayrıca
|
|
267
|
+
sayacın döndüğü gün, kullanıcının korunduğu gün değildir: sessiz saatler kullanıcının kendi
|
|
268
|
+
haftalık gününü zaten okuyor, cuma ya da Şabat penceresi dahil, ve bildirimin ne zaman
|
|
269
|
+
verilebileceğine onlar karar veriyor. Bütçe yalnız kaç tane olacağına karar verir. ISO
|
|
270
|
+
haftası sizin kullanıcılarınız için yanlışsa kendi bütçe kontrolünüzü istediğiniz anahtarla
|
|
271
|
+
yazın: `id` ve `run` taşıyan bir nesnedir, istediğiniz sırada dizilir ve izde yerleşik
|
|
272
|
+
kontrollerin yanında görünür.
|
|
246
273
|
|
|
247
274
|
## Hazır paketler: platform kotaları ve yasal sınırlar, kaynaklarıyla
|
|
248
275
|
|
|
@@ -463,6 +490,18 @@ başına bir anahtar ve sessiz saati aşan bir öncelik tabanı verir. Horvitz'i
|
|
|
463
490
|
çalışmaları iki isteğe bağlı kontrolü sağladı. Bu paket o fikirleri izli tek bir listeye
|
|
464
491
|
koyar ve onların dışarıda bıraktığı parçayı ekler: gönderim anında tüketilen bütçe.
|
|
465
492
|
|
|
493
|
+
## Atıf
|
|
494
|
+
|
|
495
|
+
Her sürüm Zenodo'da bir DOI ile arşivleniyor, böylece bir makale ya da rapor tam olarak
|
|
496
|
+
çalıştırdığı koda işaret edebiliyor.
|
|
497
|
+
|
|
498
|
+
[](https://doi.org/10.5281/zenodo.22393512)
|
|
499
|
+
|
|
500
|
+
Bu **kavram** DOI'si: her zaman en yeni sürüme çözümlenir. Çalıştırdığınız sürümün kendisini
|
|
501
|
+
atıflamak için o sayfayı açıp yan çubuktan sürümü seçin ve orada yazan DOI'yi kullanın.
|
|
502
|
+
Depodaki `CITATION.cff` aynı tanımlayıcıyı taşıyor, bu yüzden GitHub'ın "Cite this repository"
|
|
503
|
+
düğmesi elle kopyalama olmadan doğru BibTeX ve APA üretiyor.
|
|
504
|
+
|
|
466
505
|
## Geliştirme
|
|
467
506
|
|
|
468
507
|
```
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Store } from "./types.js";
|
|
2
|
+
export interface StoreContractHandle {
|
|
3
|
+
store: Store;
|
|
4
|
+
teardown?: () => void | Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
export type StoreContractFactory = (clock?: () => number) => Store | StoreContractHandle | Promise<Store | StoreContractHandle>;
|
|
7
|
+
export interface StoreContractOptions {
|
|
8
|
+
expiry?: "injected" | "skip";
|
|
9
|
+
skip?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function storeContract(name: string, factory: StoreContractFactory, options?: StoreContractOptions): void;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { MemoryStore } from "./stores.js";
|
|
4
|
+
function asHandle(value) {
|
|
5
|
+
return "store" in value ? value : { store: value };
|
|
6
|
+
}
|
|
7
|
+
export function storeContract(name, factory, options = {}) {
|
|
8
|
+
const expiry = options.expiry ?? "injected";
|
|
9
|
+
const skip = options.skip;
|
|
10
|
+
const testOptions = skip ? { skip } : {};
|
|
11
|
+
const expiryOptions = expiry === "skip" ? { skip: "expiry cases skipped: this store does not accept an injected clock" } : testOptions;
|
|
12
|
+
const withStore = async (clock, run) => {
|
|
13
|
+
const handle = asHandle(await factory(clock));
|
|
14
|
+
try {
|
|
15
|
+
return await run(handle.store);
|
|
16
|
+
}
|
|
17
|
+
finally {
|
|
18
|
+
await handle.teardown?.();
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
test(`${name}: get, set and del`, testOptions, async () => {
|
|
22
|
+
await withStore(undefined, async (store) => {
|
|
23
|
+
assert.equal(await store.get("missing"), null);
|
|
24
|
+
await store.set("key", "value");
|
|
25
|
+
assert.equal(await store.get("key"), "value");
|
|
26
|
+
await store.del("key");
|
|
27
|
+
assert.equal(await store.get("key"), null);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
test(`${name}: incr from absent starts at one`, testOptions, async () => {
|
|
31
|
+
await withStore(undefined, async (store) => {
|
|
32
|
+
assert.equal(await store.incr("counter"), 1);
|
|
33
|
+
assert.equal(await store.incr("counter"), 2);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
test(`${name}: incr is atomic`, testOptions, async () => {
|
|
37
|
+
await withStore(undefined, async (store) => {
|
|
38
|
+
const results = await Promise.all(Array.from({ length: 100 }, () => store.incr("counter")));
|
|
39
|
+
assert.deepEqual([...results].sort((a, b) => a - b), Array.from({ length: 100 }, (_, i) => i + 1));
|
|
40
|
+
assert.equal(await store.get("counter"), "100");
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
test(`${name}: set and incr TTLs expire at the same boundary`, expiryOptions, async () => {
|
|
44
|
+
let now = 0;
|
|
45
|
+
const clock = () => now;
|
|
46
|
+
await withStore(clock, async (store) => {
|
|
47
|
+
await store.set("set", "value", 2);
|
|
48
|
+
await store.incr("incr", 2);
|
|
49
|
+
now = 1999;
|
|
50
|
+
assert.equal(await store.get("set"), "value");
|
|
51
|
+
assert.equal(await store.get("incr"), "1");
|
|
52
|
+
now = 2000;
|
|
53
|
+
assert.equal(await store.get("set"), null);
|
|
54
|
+
assert.equal(await store.get("incr"), null);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
test(`${name}: expiry is inclusive at the boundary`, expiryOptions, async () => {
|
|
58
|
+
let now = 1000;
|
|
59
|
+
const clock = () => now;
|
|
60
|
+
await withStore(clock, async (store) => {
|
|
61
|
+
await store.set("key", "value", 1);
|
|
62
|
+
assert.equal(await store.get("key"), "value");
|
|
63
|
+
now = 1999;
|
|
64
|
+
assert.equal(await store.get("key"), "value");
|
|
65
|
+
now = 2000;
|
|
66
|
+
assert.equal(await store.get("key"), null);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
test(`${name}: random operations match MemoryStore`, testOptions, async () => {
|
|
70
|
+
for (let seed = 1; seed <= 40; seed++) {
|
|
71
|
+
let now = 0;
|
|
72
|
+
const clock = () => now;
|
|
73
|
+
await withStore(expiry === "injected" ? clock : undefined, async (store) => {
|
|
74
|
+
const reference = new MemoryStore(clock);
|
|
75
|
+
const keys = ["a", "b", "c"];
|
|
76
|
+
let state = 0x6d2b79f5 ^ seed;
|
|
77
|
+
const random = () => {
|
|
78
|
+
state = (Math.imul(state ^ (state >>> 16), 2246822507) + 3266489909) >>> 0;
|
|
79
|
+
return state / 4294967296;
|
|
80
|
+
};
|
|
81
|
+
try {
|
|
82
|
+
for (let step = 0; step < 40; step++) {
|
|
83
|
+
const key = keys[Math.floor(random() * keys.length)];
|
|
84
|
+
const ttl = expiry === "injected" && random() > 0.5 ? 1 + Math.floor(random() * 3) : undefined;
|
|
85
|
+
const op = Math.floor(random() * 5);
|
|
86
|
+
if (op === 0) {
|
|
87
|
+
const value = String(Math.floor(random() * 100));
|
|
88
|
+
await reference.set(key, value, ttl);
|
|
89
|
+
await store.set(key, value, ttl);
|
|
90
|
+
}
|
|
91
|
+
else if (op === 1) {
|
|
92
|
+
assert.equal(await store.incr(key, ttl), await reference.incr(key, ttl), `seed ${seed} step ${step}: incr disagreed`);
|
|
93
|
+
}
|
|
94
|
+
else if (op === 2) {
|
|
95
|
+
await reference.del(key);
|
|
96
|
+
await store.del(key);
|
|
97
|
+
}
|
|
98
|
+
else if (op === 3) {
|
|
99
|
+
if (expiry === "injected")
|
|
100
|
+
now += Math.floor(random() * 3000);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
assert.equal(await store.get(key), await reference.get(key), `seed ${seed} step ${step}: get disagreed on ${key}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
for (const key of keys) {
|
|
107
|
+
assert.equal(await store.get(key), await reference.get(key), `seed ${seed}: final state disagreed on ${key}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
finally {
|
|
111
|
+
await reference.del("a");
|
|
112
|
+
await reference.del("b");
|
|
113
|
+
await reference.del("c");
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "proactive-gate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Decide whether a proactive AI agent may reach a user right now, and log why not. Ordered checks as code or JSON, a conformance spec, presets for platform and legal limits, adapters for AI SDK, Mastra, LangChain and OpenAI Agents, and a Python sibling.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/src/index.js",
|
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
"types": "./dist/src/presets.d.ts",
|
|
15
15
|
"import": "./dist/src/presets.js"
|
|
16
16
|
},
|
|
17
|
+
"./store-contract": {
|
|
18
|
+
"types": "./dist/src/store-contract.d.ts",
|
|
19
|
+
"import": "./dist/src/store-contract.js"
|
|
20
|
+
},
|
|
17
21
|
"./ai-sdk": {
|
|
18
22
|
"types": "./dist/src/adapters/ai-sdk.d.ts",
|
|
19
23
|
"import": "./dist/src/adapters/ai-sdk.js"
|
|
@@ -65,9 +69,9 @@
|
|
|
65
69
|
"agents",
|
|
66
70
|
"proactive",
|
|
67
71
|
"notifications",
|
|
68
|
-
"rate-limit",
|
|
69
72
|
"quiet-hours",
|
|
70
73
|
"consent",
|
|
74
|
+
"rate-limit",
|
|
71
75
|
"budget",
|
|
72
76
|
"llm",
|
|
73
77
|
"policy",
|