@schlessera/brain-ui-server 0.18.0 → 0.20.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.
Files changed (130) hide show
  1. package/README.md +5 -1
  2. package/data/model-prices.json +63 -0
  3. package/dist/activity/digest.d.ts +29 -0
  4. package/dist/activity/digest.d.ts.map +1 -0
  5. package/dist/activity/digest.js +89 -0
  6. package/dist/activity/digest.js.map +1 -0
  7. package/dist/activity/notify.d.ts +62 -0
  8. package/dist/activity/notify.d.ts.map +1 -0
  9. package/dist/activity/notify.js +193 -0
  10. package/dist/activity/notify.js.map +1 -0
  11. package/dist/activity/push-sender.d.ts +63 -0
  12. package/dist/activity/push-sender.d.ts.map +1 -0
  13. package/dist/activity/push-sender.js +131 -0
  14. package/dist/activity/push-sender.js.map +1 -0
  15. package/dist/activity/query.d.ts +16 -0
  16. package/dist/activity/query.d.ts.map +1 -0
  17. package/dist/activity/query.js +155 -0
  18. package/dist/activity/query.js.map +1 -0
  19. package/dist/activity/recorder.d.ts +53 -0
  20. package/dist/activity/recorder.d.ts.map +1 -0
  21. package/dist/activity/recorder.js +238 -0
  22. package/dist/activity/recorder.js.map +1 -0
  23. package/dist/activity/runtime.d.ts +37 -0
  24. package/dist/activity/runtime.d.ts.map +1 -0
  25. package/dist/activity/runtime.js +127 -0
  26. package/dist/activity/runtime.js.map +1 -0
  27. package/dist/activity/span-sink.d.ts +22 -0
  28. package/dist/activity/span-sink.d.ts.map +1 -0
  29. package/dist/activity/span-sink.js +138 -0
  30. package/dist/activity/span-sink.js.map +1 -0
  31. package/dist/activity/store.d.ts +256 -0
  32. package/dist/activity/store.d.ts.map +1 -0
  33. package/dist/activity/store.js +657 -0
  34. package/dist/activity/store.js.map +1 -0
  35. package/dist/activity/stream.d.ts +49 -0
  36. package/dist/activity/stream.d.ts.map +1 -0
  37. package/dist/activity/stream.js +353 -0
  38. package/dist/activity/stream.js.map +1 -0
  39. package/dist/agent/backend.d.ts +13 -4
  40. package/dist/agent/backend.d.ts.map +1 -1
  41. package/dist/agent/backend.js +68 -5
  42. package/dist/agent/backend.js.map +1 -1
  43. package/dist/app.d.ts.map +1 -1
  44. package/dist/app.js +33 -2
  45. package/dist/app.js.map +1 -1
  46. package/dist/config/env.d.ts +36 -0
  47. package/dist/config/env.d.ts.map +1 -1
  48. package/dist/config/env.js +66 -2
  49. package/dist/config/env.js.map +1 -1
  50. package/dist/cron/scheduler.d.ts.map +1 -1
  51. package/dist/cron/scheduler.js +20 -5
  52. package/dist/cron/scheduler.js.map +1 -1
  53. package/dist/db/client.d.ts.map +1 -1
  54. package/dist/db/client.js +32 -6
  55. package/dist/db/client.js.map +1 -1
  56. package/dist/db/settings.d.ts +15 -0
  57. package/dist/db/settings.d.ts.map +1 -1
  58. package/dist/db/settings.js +43 -0
  59. package/dist/db/settings.js.map +1 -1
  60. package/dist/index.d.ts +4 -0
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +7 -0
  63. package/dist/index.js.map +1 -1
  64. package/dist/pricing/model-pricing.d.ts +61 -0
  65. package/dist/pricing/model-pricing.d.ts.map +1 -0
  66. package/dist/pricing/model-pricing.js +379 -0
  67. package/dist/pricing/model-pricing.js.map +1 -0
  68. package/dist/routes/activity.d.ts +20 -0
  69. package/dist/routes/activity.d.ts.map +1 -0
  70. package/dist/routes/activity.js +308 -0
  71. package/dist/routes/activity.js.map +1 -0
  72. package/dist/routes/models.d.ts +6 -0
  73. package/dist/routes/models.d.ts.map +1 -1
  74. package/dist/routes/models.js +38 -3
  75. package/dist/routes/models.js.map +1 -1
  76. package/dist/routes/push.d.ts +6 -0
  77. package/dist/routes/push.d.ts.map +1 -0
  78. package/dist/routes/push.js +73 -0
  79. package/dist/routes/push.js.map +1 -0
  80. package/dist/routes/sessions.d.ts.map +1 -1
  81. package/dist/routes/sessions.js +20 -4
  82. package/dist/routes/sessions.js.map +1 -1
  83. package/dist/ws/bridge.d.ts +2 -1
  84. package/dist/ws/bridge.d.ts.map +1 -1
  85. package/dist/ws/bridge.js +27 -2
  86. package/dist/ws/bridge.js.map +1 -1
  87. package/dist/ws/connection.d.ts.map +1 -1
  88. package/dist/ws/connection.js +9 -1
  89. package/dist/ws/connection.js.map +1 -1
  90. package/dist/ws/dispatch.d.ts.map +1 -1
  91. package/dist/ws/dispatch.js +11 -0
  92. package/dist/ws/dispatch.js.map +1 -1
  93. package/dist/ws/host.d.ts +16 -0
  94. package/dist/ws/host.d.ts.map +1 -1
  95. package/dist/ws/host.js +2 -0
  96. package/dist/ws/host.js.map +1 -1
  97. package/dist/ws/run-session.d.ts.map +1 -1
  98. package/dist/ws/run-session.js +55 -1
  99. package/dist/ws/run-session.js.map +1 -1
  100. package/migrations/007_activity.sql +114 -0
  101. package/migrations/008_push_subscriptions.sql +24 -0
  102. package/migrations/009_activity_followups.sql +22 -0
  103. package/migrations/010_effective_cost.sql +21 -0
  104. package/package.json +6 -3
  105. package/src/activity/digest.ts +120 -0
  106. package/src/activity/notify.ts +307 -0
  107. package/src/activity/push-sender.ts +215 -0
  108. package/src/activity/query.ts +187 -0
  109. package/src/activity/recorder.ts +313 -0
  110. package/src/activity/runtime.ts +169 -0
  111. package/src/activity/span-sink.ts +152 -0
  112. package/src/activity/store.ts +1069 -0
  113. package/src/activity/stream.ts +396 -0
  114. package/src/agent/backend.ts +91 -10
  115. package/src/app.ts +35 -2
  116. package/src/config/env.ts +90 -2
  117. package/src/cron/scheduler.ts +28 -8
  118. package/src/db/client.ts +31 -6
  119. package/src/db/settings.ts +56 -0
  120. package/src/index.ts +23 -0
  121. package/src/pricing/model-pricing.ts +497 -0
  122. package/src/routes/activity.ts +371 -0
  123. package/src/routes/models.ts +57 -6
  124. package/src/routes/push.ts +90 -0
  125. package/src/routes/sessions.ts +24 -4
  126. package/src/ws/bridge.ts +29 -2
  127. package/src/ws/connection.ts +9 -1
  128. package/src/ws/dispatch.ts +13 -0
  129. package/src/ws/host.ts +18 -0
  130. package/src/ws/run-session.ts +71 -2
package/dist/db/client.js CHANGED
@@ -5,6 +5,12 @@ export function createUiDb(dbPath, options = {}) {
5
5
  const db = new Database(dbPath, { create: true });
6
6
  db.exec("PRAGMA journal_mode = WAL");
7
7
  db.exec("PRAGMA foreign_keys = ON");
8
+ // Two processes write this database (the server and the cron wrapper). The
9
+ // timeout makes a writer wait for a held lock instead of failing on it.
10
+ // It does NOT rescue a deferred transaction that loses the snapshot-upgrade
11
+ // race (that still throws SQLITE_BUSY) — which is why activity writes use
12
+ // immediate transactions; see src/activity/store.ts.
13
+ db.exec("PRAGMA busy_timeout = 5000");
8
14
  runMigrations(db, options.log);
9
15
  return db;
10
16
  }
@@ -40,12 +46,32 @@ function runMigrations(database, log) {
40
46
  continue;
41
47
  log?.emit({ severityText: "INFO", body: "applying migration", attributes: { file } });
42
48
  const sql = readFileSync(join(migrationsDir, file), "utf-8");
43
- database.transaction(() => {
44
- database.exec(sql);
45
- database
46
- .prepare("INSERT INTO _migrations (filename, applied_at) VALUES (?, ?)")
47
- .run(file, Date.now());
48
- })();
49
+ try {
50
+ database.transaction(() => {
51
+ database.exec(sql);
52
+ database
53
+ .prepare("INSERT INTO _migrations (filename, applied_at) VALUES (?, ?)")
54
+ .run(file, Date.now());
55
+ })();
56
+ }
57
+ catch (err) {
58
+ // Two processes racing a first boot: the loser's transaction fails on
59
+ // the UNIQUE _migrations.filename insert (or on DDL the winner already
60
+ // ran). If the file is now recorded as applied, treat it as such and
61
+ // move on; anything else is a real migration failure.
62
+ const nowApplied = database
63
+ .query("SELECT 1 FROM _migrations WHERE filename = ?")
64
+ .get(file);
65
+ const uniqueViolation = err instanceof Error &&
66
+ err.message.includes("UNIQUE constraint failed: _migrations.filename");
67
+ if (!nowApplied && !uniqueViolation)
68
+ throw err;
69
+ log?.emit({
70
+ severityText: "INFO",
71
+ body: "migration applied concurrently by another process; skipping",
72
+ attributes: { file },
73
+ });
74
+ }
49
75
  }
50
76
  }
51
77
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/db/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAsB5B,MAAM,UAAU,UAAU,CAAC,MAAc,EAAE,UAA6B,EAAE;IACxE,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,EAAE,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IACrC,EAAE,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;IACpC,aAAa,CAAC,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAC/B,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,aAAa,CAAC,QAAkB,EAAE,GAAY;IACrD,kCAAkC;IAClC,QAAQ,CAAC,IAAI,CAAC;;;;;;GAMb,CAAC,CAAC;IAEH,uEAAuE;IACvE,yEAAyE;IACzE,6EAA6E;IAC7E,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC;IAChE,IAAI,KAAe,CAAC;IACpB,IAAI,CAAC;QACH,KAAK,GAAG,WAAW,CAAC,aAAa,CAAC;aAC/B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;aACjC,IAAI,EAAE,CAAC;IACZ,CAAC;IAAC,MAAM,CAAC;QACP,GAAG,EAAE,IAAI,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,8CAA8C,EAAE,CAAC,CAAC;QAC1F,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,GAAG,CACrB,QAAQ;SACL,KAAK,CAAC,kCAAkC,CAAC;SACzC,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAC/B,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS;QAEhC,GAAG,EAAE,IAAI,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,oBAAoB,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;QACtF,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;QAE7D,QAAQ,CAAC,WAAW,CAAC,GAAG,EAAE;YACxB,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACnB,QAAQ;iBACL,OAAO,CAAC,8DAA8D,CAAC;iBACvE,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAC3B,CAAC,CAAC,EAAE,CAAC;IACP,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/db/client.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,24 @@
1
1
  import type { Logger } from "@opentelemetry/api-logs";
2
2
  import type { Database } from "bun:sqlite";
3
+ import { type BillingMode } from "@schlessera/brain-ui-sdk/protocol";
3
4
  export declare function getSetting<T>(db: Database, key: string, fallback: T, log?: Logger): T;
4
5
  export declare function setSetting(db: Database, key: string, value: unknown): void;
5
6
  /** Profile ids the user keeps out of the model picker. */
6
7
  export declare function getHiddenModelIds(db: Database, log?: Logger): string[];
7
8
  /** Replace the hidden set (the client always sends the full list, not a delta). */
8
9
  export declare function setHiddenModelIds(db: Database, ids: string[]): void;
10
+ /**
11
+ * Per-profile billing-mode overrides: profile id → forced classification. A
12
+ * profile absent from the record is "auto" (the registry's derived mode
13
+ * applies). Anything that is not exactly "subscription" or "api" is dropped
14
+ * on read, so a corrupt row degrades to auto rather than misbilling.
15
+ */
16
+ export declare function getBillingOverrides(db: Database, log?: Logger): Record<string, BillingMode>;
17
+ /** Replace the override record (the client always sends the full record, not a delta). */
18
+ export declare function setBillingOverrides(db: Database, overrides: Record<string, BillingMode>): void;
19
+ /** Minimum days a finished run keeps its detail (spans/events) before the
20
+ * digest-covered prune may take it. 0 is valid (prune as soon as covered);
21
+ * anything non-numeric or negative degrades to the default. */
22
+ export declare function getDetailRetentionDays(db: Database, log?: Logger): number;
23
+ export declare function setDetailRetentionDays(db: Database, days: number): void;
9
24
  //# sourceMappingURL=settings.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/db/settings.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3C,wBAAgB,UAAU,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,CAerF;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAK1E;AAED,0DAA0D;AAC1D,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAItE;AAED,mFAAmF;AACnF,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,CAGnE"}
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/db/settings.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAOpF,wBAAgB,UAAU,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,CAerF;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAK1E;AAED,0DAA0D;AAC1D,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAItE;AAED,mFAAmF;AACnF,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,CAGnE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,QAAQ,EACZ,GAAG,CAAC,EAAE,MAAM,GACX,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAa7B;AAED,0FAA0F;AAC1F,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,QAAQ,EACZ,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GACrC,IAAI,CAON;AAED;;gEAEgE;AAChE,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAMzE;AAED,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAEvE"}
@@ -5,7 +5,11 @@
5
5
  // browser. Values are stored as JSON text; readers are total — a missing or
6
6
  // corrupt row degrades to the caller's fallback rather than throwing, because
7
7
  // a bad preference must never take a route down.
8
+ import { isBillingMode } from "@schlessera/brain-ui-sdk/protocol";
8
9
  const HIDDEN_MODELS_KEY = "models.hidden";
10
+ const BILLING_OVERRIDES_KEY = "models.billing";
11
+ const DETAIL_RETENTION_KEY = "activity.retention.detailDays";
12
+ const DETAIL_RETENTION_DEFAULT_DAYS = 7;
9
13
  export function getSetting(db, key, fallback, log) {
10
14
  const row = db
11
15
  .query("SELECT value FROM settings WHERE key = ?")
@@ -40,4 +44,43 @@ export function setHiddenModelIds(db, ids) {
40
44
  const unique = [...new Set(ids.filter((id) => typeof id === "string" && id))];
41
45
  setSetting(db, HIDDEN_MODELS_KEY, unique);
42
46
  }
47
+ /**
48
+ * Per-profile billing-mode overrides: profile id → forced classification. A
49
+ * profile absent from the record is "auto" (the registry's derived mode
50
+ * applies). Anything that is not exactly "subscription" or "api" is dropped
51
+ * on read, so a corrupt row degrades to auto rather than misbilling.
52
+ */
53
+ export function getBillingOverrides(db, log) {
54
+ const value = getSetting(db, BILLING_OVERRIDES_KEY, {}, log);
55
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
56
+ return Object.create(null);
57
+ }
58
+ // Null-prototype: profile ids are user-supplied strings — an id like
59
+ // "__proto__" must be an ordinary key, and a "constructor" lookup by a
60
+ // consumer must not resolve a prototype member.
61
+ const overrides = Object.create(null);
62
+ for (const [profileId, mode] of Object.entries(value)) {
63
+ if (isBillingMode(mode))
64
+ overrides[profileId] = mode;
65
+ }
66
+ return overrides;
67
+ }
68
+ /** Replace the override record (the client always sends the full record, not a delta). */
69
+ export function setBillingOverrides(db, overrides) {
70
+ const clean = Object.fromEntries(Object.entries(overrides).filter(([profileId, mode]) => profileId && isBillingMode(mode)));
71
+ setSetting(db, BILLING_OVERRIDES_KEY, clean);
72
+ }
73
+ /** Minimum days a finished run keeps its detail (spans/events) before the
74
+ * digest-covered prune may take it. 0 is valid (prune as soon as covered);
75
+ * anything non-numeric or negative degrades to the default. */
76
+ export function getDetailRetentionDays(db, log) {
77
+ const value = getSetting(db, DETAIL_RETENTION_KEY, DETAIL_RETENTION_DEFAULT_DAYS, log);
78
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
79
+ return DETAIL_RETENTION_DEFAULT_DAYS;
80
+ }
81
+ return value;
82
+ }
83
+ export function setDetailRetentionDays(db, days) {
84
+ setSetting(db, DETAIL_RETENTION_KEY, days);
85
+ }
43
86
  //# sourceMappingURL=settings.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/db/settings.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,EAAE;AACF,yEAAyE;AACzE,6EAA6E;AAC7E,4EAA4E;AAC5E,8EAA8E;AAC9E,iDAAiD;AAKjD,MAAM,iBAAiB,GAAG,eAAe,CAAC;AAE1C,MAAM,UAAU,UAAU,CAAI,EAAY,EAAE,GAAW,EAAE,QAAW,EAAE,GAAY;IAChF,MAAM,GAAG,GAAG,EAAE;SACX,KAAK,CAAC,0CAA0C,CAAC;SACjD,GAAG,CAAC,GAAG,CAA6B,CAAC;IACxC,IAAI,CAAC,GAAG;QAAE,OAAO,QAAQ,CAAC;IAC1B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAM,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,GAAG,EAAE,IAAI,CAAC;YACR,YAAY,EAAE,MAAM;YACpB,IAAI,EAAE,0CAA0C;YAChD,UAAU,EAAE,EAAE,GAAG,EAAE;SACpB,CAAC,CAAC;QACH,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,EAAY,EAAE,GAAW,EAAE,KAAc;IAClE,EAAE,CAAC,OAAO,CACR;6FACyF,CAC1F,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;AAChD,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,iBAAiB,CAAC,EAAY,EAAE,GAAY;IAC1D,MAAM,KAAK,GAAG,UAAU,CAAU,EAAE,EAAE,iBAAiB,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;IAClE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACrC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,EAAgB,EAAE,CAAC,OAAO,EAAE,KAAK,QAAQ,CAAC,CAAC;AACpE,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,iBAAiB,CAAC,EAAY,EAAE,GAAa;IAC3D,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC9E,UAAU,CAAC,EAAE,EAAE,iBAAiB,EAAE,MAAM,CAAC,CAAC;AAC5C,CAAC"}
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/db/settings.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -21,6 +21,10 @@ export { resolveTurnTarget } from "./ws/routing.js";
21
21
  export { createSessionCatalog, type SessionCatalog, } from "./ws/session-catalog.js";
22
22
  export { createBrainClient, type BrainClient } from "./brain/client.js";
23
23
  export { recordCronRun, type CronRunRecord } from "./cron/scheduler.js";
24
+ export { createActivityStore, SPAN_OUTCOMES, type ActivityStore, type SpanRow, type SpanEventRow, type SpanOutcome, type SpanUsage, type ActivityChange, type RollupPricing, } from "./activity/store.js";
25
+ export { createActivityStream, type ActivityStream } from "./activity/stream.js";
26
+ export { ingestSpanSink } from "./activity/span-sink.js";
27
+ export { generateActivityDigest, latestActivityDigest, DIGEST_JOB_NAME, type ActivityDigest, } from "./activity/digest.js";
24
28
  export { pruneShareStaging, shareStagingRoot } from "./share/staging.js";
25
29
  export { createObservability, createRecordingObservability, createSilentObservability, createConsoleLoggerProvider, createRecordingLoggerProvider, createSilentLoggerProvider, createInMemoryMeterProvider, SEVERITIES, severityRank, seriesKey, } from "./observability/index.js";
26
30
  export type { Observability, ObservabilityOptions, RecordingObservability, RecordingLoggerProvider, InMemoryMeterProvider, LogReader, LogWriter, MetricsReader, Severity, CapturedLog, LogQuery, MetricPoint, MetricSnapshot, } from "./observability/index.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,SAAS,EACT,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,WAAW,GACjB,MAAM,UAAU,CAAC;AAIlB,OAAO,EACL,QAAQ,EACR,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,WAAW,GACjB,MAAM,iBAAiB,CAAC;AAIzB,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,2BAA2B,EAC3B,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,GACzB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,eAAe,EACf,KAAK,QAAQ,EACb,KAAK,WAAW,GACjB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAI5C,OAAO,EACL,WAAW,EACX,WAAW,EACX,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,EACL,mBAAmB,EACnB,aAAa,EACb,KAAK,eAAe,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EACL,oBAAoB,EACpB,KAAK,cAAc,GACpB,MAAM,yBAAyB,CAAC;AAIjC,OAAO,EAAE,iBAAiB,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAKxE,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIxE,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAKzE,OAAO,EACL,mBAAmB,EACnB,4BAA4B,EAC5B,yBAAyB,EACzB,2BAA2B,EAC3B,6BAA6B,EAC7B,0BAA0B,EAC1B,2BAA2B,EAC3B,UAAU,EACV,YAAY,EACZ,SAAS,GACV,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,aAAa,EACb,oBAAoB,EACpB,sBAAsB,EACtB,uBAAuB,EACvB,qBAAqB,EACrB,SAAS,EACT,SAAS,EACT,aAAa,EACb,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,WAAW,EACX,cAAc,GACf,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EACL,aAAa,EACb,UAAU,EACV,KAAK,eAAe,GACrB,MAAM,4BAA4B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,SAAS,EACT,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,WAAW,GACjB,MAAM,UAAU,CAAC;AAIlB,OAAO,EACL,QAAQ,EACR,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,WAAW,GACjB,MAAM,iBAAiB,CAAC;AAIzB,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,2BAA2B,EAC3B,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,GACzB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,eAAe,EACf,KAAK,QAAQ,EACb,KAAK,WAAW,GACjB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAI5C,OAAO,EACL,WAAW,EACX,WAAW,EACX,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,EACL,mBAAmB,EACnB,aAAa,EACb,KAAK,eAAe,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EACL,oBAAoB,EACpB,KAAK,cAAc,GACpB,MAAM,yBAAyB,CAAC;AAIjC,OAAO,EAAE,iBAAiB,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAKxE,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAKxE,OAAO,EACL,mBAAmB,EACnB,aAAa,EACb,KAAK,aAAa,EAClB,KAAK,OAAO,EACZ,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,aAAa,GACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,oBAAoB,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,eAAe,EACf,KAAK,cAAc,GACpB,MAAM,sBAAsB,CAAC;AAI9B,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAKzE,OAAO,EACL,mBAAmB,EACnB,4BAA4B,EAC5B,yBAAyB,EACzB,2BAA2B,EAC3B,6BAA6B,EAC7B,0BAA0B,EAC1B,2BAA2B,EAC3B,UAAU,EACV,YAAY,EACZ,SAAS,GACV,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,aAAa,EACb,oBAAoB,EACpB,sBAAsB,EACtB,uBAAuB,EACvB,qBAAqB,EACrB,SAAS,EACT,SAAS,EACT,aAAa,EACb,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,WAAW,EACX,cAAc,GACf,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EACL,aAAa,EACb,UAAU,EACV,KAAK,eAAe,GACrB,MAAM,4BAA4B,CAAC"}
package/dist/index.js CHANGED
@@ -34,6 +34,13 @@ export { createBrainClient } from "./brain/client.js";
34
34
  // an external scheduler's wrapper records each run here so /api/status's
35
35
  // `cronJobs` reflects what actually ran.
36
36
  export { recordCronRun } from "./cron/scheduler.js";
37
+ // The activity record. The cron wrapper is a second PROCESS writing spans
38
+ // into the same store (root span + heartbeat + span-sink ingest); everything
39
+ // else consumes it through the app.
40
+ export { createActivityStore, SPAN_OUTCOMES, } from "./activity/store.js";
41
+ export { createActivityStream } from "./activity/stream.js";
42
+ export { ingestSpanSink } from "./activity/span-sink.js";
43
+ export { generateActivityDigest, latestActivityDigest, DIGEST_JOB_NAME, } from "./activity/digest.js";
37
44
  // Share staging: a deployment can sweep expired staging dirs at boot; the
38
45
  // intake route also sweeps opportunistically on every share.
39
46
  export { pruneShareStaging, shareStagingRoot } from "./share/staging.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,SAAS,GAIV,MAAM,UAAU,CAAC;AAElB,6EAA6E;AAC7E,8EAA8E;AAC9E,OAAO,EACL,QAAQ,EACR,mBAAmB,GAOpB,MAAM,iBAAiB,CAAC;AAEzB,4EAA4E;AAC5E,+BAA+B;AAC/B,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,2BAA2B,GAK5B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,eAAe,GAGhB,MAAM,sBAAsB,CAAC;AAE9B,gEAAgE;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,uEAAuE;AACvE,qBAAqB;AACrB,OAAO,EACL,WAAW,EACX,WAAW,EACX,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,kBAAkB,CAAC;AAE1B,+CAA+C;AAC/C,OAAO,EAAE,MAAM,EAAsB,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,EACL,mBAAmB,EACnB,aAAa,GAEd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EACL,oBAAoB,GAErB,MAAM,yBAAyB,CAAC;AAEjC,0EAA0E;AAC1E,2BAA2B;AAC3B,OAAO,EAAE,iBAAiB,EAAoB,MAAM,mBAAmB,CAAC;AAExE,8EAA8E;AAC9E,yEAAyE;AACzE,yCAAyC;AACzC,OAAO,EAAE,aAAa,EAAsB,MAAM,qBAAqB,CAAC;AAExE,0EAA0E;AAC1E,6DAA6D;AAC7D,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEzE,4EAA4E;AAC5E,+EAA+E;AAC/E,2EAA2E;AAC3E,OAAO,EACL,mBAAmB,EACnB,4BAA4B,EAC5B,yBAAyB,EACzB,2BAA2B,EAC3B,6BAA6B,EAC7B,0BAA0B,EAC1B,2BAA2B,EAC3B,UAAU,EACV,YAAY,EACZ,SAAS,GACV,MAAM,0BAA0B,CAAC;AAiBlC,wEAAwE;AACxE,OAAO,EACL,aAAa,EACb,UAAU,GAEX,MAAM,4BAA4B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,SAAS,GAIV,MAAM,UAAU,CAAC;AAElB,6EAA6E;AAC7E,8EAA8E;AAC9E,OAAO,EACL,QAAQ,EACR,mBAAmB,GAOpB,MAAM,iBAAiB,CAAC;AAEzB,4EAA4E;AAC5E,+BAA+B;AAC/B,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,2BAA2B,GAK5B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,eAAe,GAGhB,MAAM,sBAAsB,CAAC;AAE9B,gEAAgE;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,uEAAuE;AACvE,qBAAqB;AACrB,OAAO,EACL,WAAW,EACX,WAAW,EACX,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,kBAAkB,CAAC;AAE1B,+CAA+C;AAC/C,OAAO,EAAE,MAAM,EAAsB,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,EACL,mBAAmB,EACnB,aAAa,GAEd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EACL,oBAAoB,GAErB,MAAM,yBAAyB,CAAC;AAEjC,0EAA0E;AAC1E,2BAA2B;AAC3B,OAAO,EAAE,iBAAiB,EAAoB,MAAM,mBAAmB,CAAC;AAExE,8EAA8E;AAC9E,yEAAyE;AACzE,yCAAyC;AACzC,OAAO,EAAE,aAAa,EAAsB,MAAM,qBAAqB,CAAC;AAExE,0EAA0E;AAC1E,6EAA6E;AAC7E,oCAAoC;AACpC,OAAO,EACL,mBAAmB,EACnB,aAAa,GAQd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,oBAAoB,EAAuB,MAAM,sBAAsB,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,eAAe,GAEhB,MAAM,sBAAsB,CAAC;AAE9B,0EAA0E;AAC1E,6DAA6D;AAC7D,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEzE,4EAA4E;AAC5E,+EAA+E;AAC/E,2EAA2E;AAC3E,OAAO,EACL,mBAAmB,EACnB,4BAA4B,EAC5B,yBAAyB,EACzB,2BAA2B,EAC3B,6BAA6B,EAC7B,0BAA0B,EAC1B,2BAA2B,EAC3B,UAAU,EACV,YAAY,EACZ,SAAS,GACV,MAAM,0BAA0B,CAAC;AAiBlC,wEAAwE;AACxE,OAAO,EACL,aAAa,EACb,UAAU,GAEX,MAAM,4BAA4B,CAAC"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Per-token USD rates for one model. `cacheRead`/`cacheWrite` are null when
3
+ * the source lacks them — a caller whose run consumed cache tokens must then
4
+ * treat the whole run as unpriced, never price the gap at zero.
5
+ */
6
+ export interface PricingRates {
7
+ input: number;
8
+ output: number;
9
+ cacheRead: number | null;
10
+ cacheWrite: number | null;
11
+ /** True when the rates came from the bundled snapshot (genuinely dated). */
12
+ estimate: boolean;
13
+ source: "litellm" | "openrouter" | "snapshot";
14
+ }
15
+ /** Cache path: alongside the discovery and keyterm caches, on the brain volume. */
16
+ export declare function pricingCachePath(brainPath: string): string;
17
+ export interface ModelPricingOptions {
18
+ /** Brain repo path; the cache lives under its `.brain-ui/` directory. */
19
+ brainPath: string;
20
+ /** How long a fetched table is considered fresh. Default 24h. */
21
+ ttlMs?: number;
22
+ /** Set false to disable pricing entirely (resolve() always null). */
23
+ enabled?: boolean;
24
+ /** @internal Test seam — inject fetch. */
25
+ fetchImpl?: typeof fetch;
26
+ /** @internal Test seam — inject the clock. */
27
+ now?: () => number;
28
+ }
29
+ export interface ModelPricingState {
30
+ enabled: boolean;
31
+ /** When a refresh last succeeded (either source); null when none ever has. */
32
+ fetchedAt: number | null;
33
+ /** The current table is older than the TTL (or was never fetched). */
34
+ stale: boolean;
35
+ /** What the table is served from: remote data (cache included) or the snapshot. */
36
+ source: "remote" | "snapshot";
37
+ /** Per-source freshness — a partial refresh leaves the failed side behind. */
38
+ litellmFetchedAt: number | null;
39
+ openrouterFetchedAt: number | null;
40
+ /** Last refresh failure, if the current table is served despite one. */
41
+ error?: string;
42
+ }
43
+ /**
44
+ * A lazily-refreshed model-price table.
45
+ *
46
+ * `resolve()` is synchronous and never touches the network, so the rollup
47
+ * transaction can price a run without blocking on a catalog being reachable.
48
+ * `ensureFresh()` awaits only on a cold start (no remote data at all — the
49
+ * snapshot still serves through the wait) and otherwise refreshes behind the
50
+ * current table.
51
+ */
52
+ export interface ModelPricing {
53
+ resolve(modelId: string): PricingRates | null;
54
+ state(): ModelPricingState;
55
+ /** Refresh if stale. Awaits only when no remote data has ever been fetched. */
56
+ ensureFresh(): Promise<void>;
57
+ /** Force a refresh regardless of TTL. Rejects only when BOTH sources fail. */
58
+ refresh(): Promise<void>;
59
+ }
60
+ export declare function createModelPricing(options: ModelPricingOptions): ModelPricing;
61
+ //# sourceMappingURL=model-pricing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-pricing.d.ts","sourceRoot":"","sources":["../../src/pricing/model-pricing.ts"],"names":[],"mappings":"AA6CA;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,4EAA4E;IAC5E,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,SAAS,GAAG,YAAY,GAAG,UAAU,CAAC;CAC/C;AAqJD,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE1D;AA4FD,MAAM,WAAW,mBAAmB;IAClC,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,8CAA8C;IAC9C,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,8EAA8E;IAC9E,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,sEAAsE;IACtE,KAAK,EAAE,OAAO,CAAC;IACf,mFAAmF;IACnF,MAAM,EAAE,QAAQ,GAAG,UAAU,CAAC;IAC9B,8EAA8E;IAC9E,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAAC;IAC9C,KAAK,IAAI,iBAAiB,CAAC;IAC3B,+EAA+E;IAC/E,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,8EAA8E;IAC9E,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAoJ7E"}