@mongrov/analytics 0.1.0-alpha.8 → 0.1.0-alpha.9

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 (66) hide show
  1. package/dist/tools/__fakes__/engine.d.ts +25 -0
  2. package/dist/tools/__fakes__/engine.d.ts.map +1 -0
  3. package/dist/tools/__fakes__/engine.js +37 -0
  4. package/dist/tools/__fakes__/engine.js.map +1 -0
  5. package/dist/tools/audit.d.ts +31 -0
  6. package/dist/tools/audit.d.ts.map +1 -0
  7. package/dist/tools/audit.js +157 -0
  8. package/dist/tools/audit.js.map +1 -0
  9. package/dist/tools/authorize.d.ts +36 -0
  10. package/dist/tools/authorize.d.ts.map +1 -0
  11. package/dist/tools/authorize.js +87 -0
  12. package/dist/tools/authorize.js.map +1 -0
  13. package/dist/tools/budget.d.ts +15 -0
  14. package/dist/tools/budget.d.ts.map +1 -0
  15. package/dist/tools/budget.js +64 -0
  16. package/dist/tools/budget.js.map +1 -0
  17. package/dist/tools/factory.d.ts +43 -0
  18. package/dist/tools/factory.d.ts.map +1 -0
  19. package/dist/tools/factory.js +137 -0
  20. package/dist/tools/factory.js.map +1 -0
  21. package/dist/tools/formatters.d.ts +17 -0
  22. package/dist/tools/formatters.d.ts.map +1 -0
  23. package/dist/tools/formatters.js +30 -0
  24. package/dist/tools/formatters.js.map +1 -0
  25. package/dist/tools/impls/activity.d.ts +15 -0
  26. package/dist/tools/impls/activity.d.ts.map +1 -0
  27. package/dist/tools/impls/activity.js +61 -0
  28. package/dist/tools/impls/activity.js.map +1 -0
  29. package/dist/tools/impls/anomaly.d.ts +21 -0
  30. package/dist/tools/impls/anomaly.d.ts.map +1 -0
  31. package/dist/tools/impls/anomaly.js +70 -0
  32. package/dist/tools/impls/anomaly.js.map +1 -0
  33. package/dist/tools/impls/compare.d.ts +21 -0
  34. package/dist/tools/impls/compare.d.ts.map +1 -0
  35. package/dist/tools/impls/compare.js +68 -0
  36. package/dist/tools/impls/compare.js.map +1 -0
  37. package/dist/tools/impls/hrv.d.ts +15 -0
  38. package/dist/tools/impls/hrv.d.ts.map +1 -0
  39. package/dist/tools/impls/hrv.js +36 -0
  40. package/dist/tools/impls/hrv.js.map +1 -0
  41. package/dist/tools/impls/insights.d.ts +18 -0
  42. package/dist/tools/impls/insights.d.ts.map +1 -0
  43. package/dist/tools/impls/insights.js +41 -0
  44. package/dist/tools/impls/insights.js.map +1 -0
  45. package/dist/tools/impls/sleep.d.ts +15 -0
  46. package/dist/tools/impls/sleep.d.ts.map +1 -0
  47. package/dist/tools/impls/sleep.js +43 -0
  48. package/dist/tools/impls/sleep.js.map +1 -0
  49. package/dist/tools/index.d.ts +13 -1
  50. package/dist/tools/index.d.ts.map +1 -1
  51. package/dist/tools/index.js +21 -1
  52. package/dist/tools/index.js.map +1 -1
  53. package/dist/tools/rate-limit.d.ts +26 -0
  54. package/dist/tools/rate-limit.d.ts.map +1 -0
  55. package/dist/tools/rate-limit.js +67 -0
  56. package/dist/tools/rate-limit.js.map +1 -0
  57. package/dist/tools/types.d.ts +121 -0
  58. package/dist/tools/types.d.ts.map +1 -0
  59. package/dist/tools/types.js +16 -0
  60. package/dist/tools/types.js.map +1 -0
  61. package/dist/tools/wrap.d.ts +53 -0
  62. package/dist/tools/wrap.d.ts.map +1 -0
  63. package/dist/tools/wrap.js +135 -0
  64. package/dist/tools/wrap.js.map +1 -0
  65. package/package.json +18 -15
  66. package/LICENSE +0 -21
@@ -0,0 +1,25 @@
1
+ import type { AnalyticsEngine } from '../../core/types';
2
+ /**
3
+ * Scriptable AnalyticsEngine fake for tool tests.
4
+ *
5
+ * Unlike the rules-side fake (single global queue), this fake supports
6
+ * per-SQL-substring row queues so multi-query tools (compare, activity)
7
+ * can script distinct responses per call.
8
+ *
9
+ * Usage:
10
+ * const engine = createFakeEngine()
11
+ * engine.queueRows('FROM hrv', [{ day: '2026-07-08', avg_hrv: 45 }])
12
+ * engine.queueRows('FROM sleep_session', [...])
13
+ * // ...invoke tool...
14
+ * engine.calls.forEach(c => ...)
15
+ */
16
+ export interface FakeEngine extends AnalyticsEngine {
17
+ readonly calls: {
18
+ sql: string;
19
+ params: Record<string, unknown>;
20
+ }[];
21
+ queueRows: (sqlSubstring: string, rows: unknown[]) => void;
22
+ setError: (err: Error | null) => void;
23
+ }
24
+ export declare function createFakeEngine(): FakeEngine;
25
+ //# sourceMappingURL=engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/tools/__fakes__/engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAEvD;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,UAAW,SAAQ,eAAe;IACjD,QAAQ,CAAC,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,EAAE,CAAA;IAClE,SAAS,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IAC1D,QAAQ,EAAE,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,KAAK,IAAI,CAAA;CACtC;AAED,wBAAgB,gBAAgB,IAAI,UAAU,CAkC7C"}
@@ -0,0 +1,37 @@
1
+ export function createFakeEngine() {
2
+ const queues = [];
3
+ const calls = [];
4
+ let error = null;
5
+ const engine = {
6
+ async attach() { },
7
+ async detach() { },
8
+ async execute(sql, params) {
9
+ calls.push({ sql, params: params ?? {} });
10
+ if (error)
11
+ throw error;
12
+ const idx = queues.findIndex(q => sql.includes(q.substring));
13
+ if (idx === -1)
14
+ return [];
15
+ const [q] = queues.splice(idx, 1);
16
+ return q.rows;
17
+ },
18
+ stream() {
19
+ throw new Error('stream not implemented in fake');
20
+ },
21
+ createAppender() {
22
+ throw new Error('createAppender not implemented in fake');
23
+ },
24
+ state: 'attached',
25
+ lastError: null,
26
+ catalog: 'fake',
27
+ subscribe: () => () => { },
28
+ async setRetention() { },
29
+ async getLastAttach() { return null; },
30
+ async close() { },
31
+ calls,
32
+ queueRows(substring, rows) { queues.push({ substring, rows }); },
33
+ setError(err) { error = err; },
34
+ };
35
+ return engine;
36
+ }
37
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/tools/__fakes__/engine.ts"],"names":[],"mappings":"AAsBA,MAAM,UAAU,gBAAgB;IAC9B,MAAM,MAAM,GAA6C,EAAE,CAAA;IAC3D,MAAM,KAAK,GAAuD,EAAE,CAAA;IACpE,IAAI,KAAK,GAAiB,IAAI,CAAA;IAE9B,MAAM,MAAM,GAAe;QACzB,KAAK,CAAC,MAAM,KAAI,CAAC;QACjB,KAAK,CAAC,MAAM,KAAI,CAAC;QACjB,KAAK,CAAC,OAAO,CAAI,GAAW,EAAE,MAAgC;YAC5D,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE,EAAE,CAAC,CAAA;YACzC,IAAI,KAAK;gBAAE,MAAM,KAAK,CAAA;YACtB,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAA;YAC5D,IAAI,GAAG,KAAK,CAAC,CAAC;gBAAE,OAAO,EAAS,CAAA;YAChC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;YACjC,OAAO,CAAC,CAAC,IAAW,CAAA;QACtB,CAAC;QACD,MAAM;YACJ,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAA;QACnD,CAAC;QACD,cAAc;YACZ,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAA;QAC3D,CAAC;QACD,KAAK,EAAE,UAAU;QACjB,SAAS,EAAE,IAAI;QACf,OAAO,EAAE,MAAM;QACf,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,GAAE,CAAC;QACzB,KAAK,CAAC,YAAY,KAAI,CAAC;QACvB,KAAK,CAAC,aAAa,KAAK,OAAO,IAAI,CAAA,CAAC,CAAC;QACrC,KAAK,CAAC,KAAK,KAAI,CAAC;QAChB,KAAK;QACL,SAAS,CAAC,SAAS,EAAE,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA,CAAC,CAAC;QAC/D,QAAQ,CAAC,GAAG,IAAI,KAAK,GAAG,GAAG,CAAA,CAAC,CAAC;KAC9B,CAAA;IACD,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Batched writer for `tool_call_audit`.
3
+ *
4
+ * `record()` enqueues synchronously (non-blocking). The batch flushes
5
+ * whenever:
6
+ * - the pending queue reaches `batchSize` (default 10), or
7
+ * - the flush timer fires (`flushIntervalMs`, default 1000ms).
8
+ *
9
+ * `flush()` and `close()` are cooperative exit hooks — `close`
10
+ * additionally halts the timer.
11
+ *
12
+ * On flush failure the batch is retained and retried on the next
13
+ * tick. A defensive `MAX_CONSECUTIVE_FAILURES` cap drops the buffer
14
+ * after repeated errors to avoid unbounded growth on a stuck
15
+ * warehouse.
16
+ *
17
+ * SQL uses a single INSERT with a suffix-indexed VALUES tuple per
18
+ * row (`$p0_ts, $p0_brand, …, $p1_ts, …`). DuckDB honors named
19
+ * parameters in this form.
20
+ */
21
+ import type { AnalyticsEngine } from '../core/types';
22
+ import type { AuditWriter, ToolsLogger } from './types';
23
+ export interface CreateAuditWriterConfig {
24
+ analytics: AnalyticsEngine;
25
+ enabled?: boolean;
26
+ batchSize?: number;
27
+ flushIntervalMs?: number;
28
+ logger?: ToolsLogger;
29
+ }
30
+ export declare function createAuditWriter(cfg: CreateAuditWriterConfig): AuditWriter;
31
+ //# sourceMappingURL=audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/tools/audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACpD,OAAO,KAAK,EAAc,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAoBnE,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,eAAe,CAAA;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,uBAAuB,GAAG,WAAW,CA6F3E"}
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Batched writer for `tool_call_audit`.
3
+ *
4
+ * `record()` enqueues synchronously (non-blocking). The batch flushes
5
+ * whenever:
6
+ * - the pending queue reaches `batchSize` (default 10), or
7
+ * - the flush timer fires (`flushIntervalMs`, default 1000ms).
8
+ *
9
+ * `flush()` and `close()` are cooperative exit hooks — `close`
10
+ * additionally halts the timer.
11
+ *
12
+ * On flush failure the batch is retained and retried on the next
13
+ * tick. A defensive `MAX_CONSECUTIVE_FAILURES` cap drops the buffer
14
+ * after repeated errors to avoid unbounded growth on a stuck
15
+ * warehouse.
16
+ *
17
+ * SQL uses a single INSERT with a suffix-indexed VALUES tuple per
18
+ * row (`$p0_ts, $p0_brand, …, $p1_ts, …`). DuckDB honors named
19
+ * parameters in this form.
20
+ */
21
+ const DEFAULT_BATCH_SIZE = 10;
22
+ const DEFAULT_FLUSH_INTERVAL_MS = 1000;
23
+ const MAX_CONSECUTIVE_FAILURES = 5;
24
+ const COLUMNS = [
25
+ 'ts',
26
+ 'brand',
27
+ 'family_id',
28
+ 'requester_user_id',
29
+ 'tool_name',
30
+ 'args',
31
+ 'result_bytes',
32
+ 'result_row_count',
33
+ 'latency_ms',
34
+ 'outcome',
35
+ 'error_message',
36
+ ];
37
+ export function createAuditWriter(cfg) {
38
+ const enabled = cfg.enabled ?? true;
39
+ const batchSize = cfg.batchSize ?? DEFAULT_BATCH_SIZE;
40
+ const flushIntervalMs = cfg.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;
41
+ const logger = cfg.logger;
42
+ const pending = [];
43
+ let timer = null;
44
+ let consecutiveFailures = 0;
45
+ let inFlight = null;
46
+ let closed = false;
47
+ function ensureTimer() {
48
+ if (timer || closed)
49
+ return;
50
+ timer = setInterval(() => {
51
+ void doFlush();
52
+ }, flushIntervalMs);
53
+ // Node timers are keep-alive by default; unref so a lingering
54
+ // audit writer doesn't block process exit.
55
+ if (typeof timer.unref === 'function') {
56
+ timer.unref();
57
+ }
58
+ }
59
+ function clearFlushTimer() {
60
+ if (!timer)
61
+ return;
62
+ clearInterval(timer);
63
+ timer = null;
64
+ }
65
+ async function doFlush() {
66
+ if (inFlight)
67
+ return inFlight;
68
+ if (pending.length === 0)
69
+ return;
70
+ const batch = pending.splice(0, pending.length);
71
+ inFlight = (async () => {
72
+ try {
73
+ await writeBatch(cfg.analytics, batch);
74
+ consecutiveFailures = 0;
75
+ }
76
+ catch (err) {
77
+ consecutiveFailures += 1;
78
+ const errMsg = err instanceof Error ? err.message : String(err);
79
+ logger?.warn('audit flush failed', {
80
+ err: errMsg,
81
+ batchSize: batch.length,
82
+ consecutiveFailures,
83
+ });
84
+ if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {
85
+ logger?.error('audit flush cap reached, dropping batch', {
86
+ droppedRows: batch.length,
87
+ });
88
+ consecutiveFailures = 0;
89
+ }
90
+ else {
91
+ // Retain: prepend so retry preserves order.
92
+ pending.unshift(...batch);
93
+ }
94
+ }
95
+ finally {
96
+ inFlight = null;
97
+ }
98
+ })();
99
+ return inFlight;
100
+ }
101
+ return {
102
+ record(entry) {
103
+ if (!enabled || closed)
104
+ return;
105
+ pending.push(entry);
106
+ ensureTimer();
107
+ if (pending.length >= batchSize) {
108
+ void doFlush();
109
+ }
110
+ },
111
+ async flush() {
112
+ if (!enabled)
113
+ return;
114
+ await doFlush();
115
+ // If the flush swallowed a failure and re-queued, drain once
116
+ // more so callers get a best-effort guarantee.
117
+ if (pending.length > 0) {
118
+ await doFlush();
119
+ }
120
+ },
121
+ async close() {
122
+ closed = true;
123
+ clearFlushTimer();
124
+ if (!enabled)
125
+ return;
126
+ await doFlush();
127
+ if (pending.length > 0) {
128
+ await doFlush();
129
+ }
130
+ },
131
+ };
132
+ }
133
+ async function writeBatch(analytics, batch) {
134
+ if (batch.length === 0)
135
+ return;
136
+ const tuples = [];
137
+ const params = {};
138
+ batch.forEach((entry, i) => {
139
+ const prefix = `p${i}`;
140
+ const placeholders = COLUMNS.map(col => `$${prefix}_${col}`);
141
+ tuples.push(`(${placeholders.join(', ')})`);
142
+ params[`${prefix}_ts`] = entry.ts;
143
+ params[`${prefix}_brand`] = entry.brand;
144
+ params[`${prefix}_family_id`] = entry.familyId;
145
+ params[`${prefix}_requester_user_id`] = entry.requesterUserId;
146
+ params[`${prefix}_tool_name`] = entry.toolName;
147
+ params[`${prefix}_args`] = JSON.stringify(entry.args);
148
+ params[`${prefix}_result_bytes`] = entry.resultBytes;
149
+ params[`${prefix}_result_row_count`] = entry.resultRowCount;
150
+ params[`${prefix}_latency_ms`] = entry.latencyMs;
151
+ params[`${prefix}_outcome`] = entry.outcome;
152
+ params[`${prefix}_error_message`] = entry.errorMessage;
153
+ });
154
+ const sql = `INSERT INTO tool_call_audit (${COLUMNS.join(', ')}) VALUES ${tuples.join(', ')}`;
155
+ await analytics.execute(sql, params);
156
+ }
157
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/tools/audit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Authorize hooks for analytics tools.
3
+ *
4
+ * `familyScopeAuthorize` — grants access iff `args.userId` is either
5
+ * the requester themselves or another member of the requester's
6
+ * family. When `config.familyMembersProvider` is supplied (the
7
+ * factory path since T-11), membership resolves via that provider;
8
+ * otherwise the legacy SQL path against a `family_member` table is
9
+ * used (kept for standalone hook usage and backwards compat).
10
+ *
11
+ * Both hooks fail closed on any error — provider throws, engine
12
+ * throws, missing/malformed args — return `false` rather than
13
+ * surfacing the error to the LLM.
14
+ */
15
+ import type { AnalyticsEngine, FamilyMembersProvider } from '../core/types';
16
+ import type { AuthorizeFn } from './types';
17
+ export interface AuthorizeConfig {
18
+ /**
19
+ * When present, membership is resolved via the provider instead of
20
+ * SQL. This is the path wired by `createAnalyticsTools`.
21
+ */
22
+ familyMembersProvider?: FamilyMembersProvider;
23
+ }
24
+ export declare function familyScopeAuthorize(analytics: AnalyticsEngine, config?: AuthorizeConfig): AuthorizeFn;
25
+ /**
26
+ * `orgScopeAuthorize` — parity with family scope but against an
27
+ * `org_member` table. Orgs are not first-class in v0.1.0; the ctx
28
+ * `familyId` is treated as the org id until org membership is wired
29
+ * through `RequestContext`.
30
+ *
31
+ * When `familyMembersProvider` is supplied, the same provider is
32
+ * consulted (v0.1.0 shim — a dedicated `orgMembersProvider` will
33
+ * split out once orgs land).
34
+ */
35
+ export declare function orgScopeAuthorize(analytics: AnalyticsEngine, config?: AuthorizeConfig): AuthorizeFn;
36
+ //# sourceMappingURL=authorize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorize.d.ts","sourceRoot":"","sources":["../../src/tools/authorize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA;AAC3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAE1C,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,qBAAqB,CAAC,EAAE,qBAAqB,CAAA;CAC9C;AAED,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,eAAe,EAC1B,MAAM,GAAE,eAAoB,GAC3B,WAAW,CAmCb;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,eAAe,EAC1B,MAAM,GAAE,eAAoB,GAC3B,WAAW,CAmCb"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Authorize hooks for analytics tools.
3
+ *
4
+ * `familyScopeAuthorize` — grants access iff `args.userId` is either
5
+ * the requester themselves or another member of the requester's
6
+ * family. When `config.familyMembersProvider` is supplied (the
7
+ * factory path since T-11), membership resolves via that provider;
8
+ * otherwise the legacy SQL path against a `family_member` table is
9
+ * used (kept for standalone hook usage and backwards compat).
10
+ *
11
+ * Both hooks fail closed on any error — provider throws, engine
12
+ * throws, missing/malformed args — return `false` rather than
13
+ * surfacing the error to the LLM.
14
+ */
15
+ export function familyScopeAuthorize(analytics, config = {}) {
16
+ return async (_toolName, args, ctx) => {
17
+ const targetUserId = args.userId;
18
+ if (typeof targetUserId !== 'string' || targetUserId.length === 0) {
19
+ return false;
20
+ }
21
+ if (targetUserId === ctx.requesterUserId) {
22
+ return true;
23
+ }
24
+ if (config.familyMembersProvider) {
25
+ try {
26
+ const members = await config.familyMembersProvider({
27
+ brand: ctx.brand,
28
+ familyId: ctx.familyId,
29
+ });
30
+ return members.includes(targetUserId);
31
+ }
32
+ catch {
33
+ return false;
34
+ }
35
+ }
36
+ try {
37
+ const rows = await analytics.execute('SELECT 1 AS one FROM family_member '
38
+ + 'WHERE family_id = $familyId AND user_id = $userId LIMIT 1', { familyId: ctx.familyId, userId: targetUserId });
39
+ return rows.length > 0;
40
+ }
41
+ catch {
42
+ return false;
43
+ }
44
+ };
45
+ }
46
+ /**
47
+ * `orgScopeAuthorize` — parity with family scope but against an
48
+ * `org_member` table. Orgs are not first-class in v0.1.0; the ctx
49
+ * `familyId` is treated as the org id until org membership is wired
50
+ * through `RequestContext`.
51
+ *
52
+ * When `familyMembersProvider` is supplied, the same provider is
53
+ * consulted (v0.1.0 shim — a dedicated `orgMembersProvider` will
54
+ * split out once orgs land).
55
+ */
56
+ export function orgScopeAuthorize(analytics, config = {}) {
57
+ return async (_toolName, args, ctx) => {
58
+ const targetUserId = args.userId;
59
+ if (typeof targetUserId !== 'string' || targetUserId.length === 0) {
60
+ return false;
61
+ }
62
+ if (targetUserId === ctx.requesterUserId) {
63
+ return true;
64
+ }
65
+ if (config.familyMembersProvider) {
66
+ try {
67
+ const members = await config.familyMembersProvider({
68
+ brand: ctx.brand,
69
+ familyId: ctx.familyId,
70
+ });
71
+ return members.includes(targetUserId);
72
+ }
73
+ catch {
74
+ return false;
75
+ }
76
+ }
77
+ try {
78
+ const rows = await analytics.execute('SELECT 1 AS one FROM org_member '
79
+ + 'WHERE org_id = $orgId AND user_id = $userId LIMIT 1', { orgId: ctx.familyId, userId: targetUserId });
80
+ return rows.length > 0;
81
+ }
82
+ catch {
83
+ return false;
84
+ }
85
+ };
86
+ }
87
+ //# sourceMappingURL=authorize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorize.js","sourceRoot":"","sources":["../../src/tools/authorize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAaH,MAAM,UAAU,oBAAoB,CAClC,SAA0B,EAC1B,SAA0B,EAAE;IAE5B,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;QACpC,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAA;QAChC,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClE,OAAO,KAAK,CAAA;QACd,CAAC;QACD,IAAI,YAAY,KAAK,GAAG,CAAC,eAAe,EAAE,CAAC;YACzC,OAAO,IAAI,CAAA;QACb,CAAC;QAED,IAAI,MAAM,CAAC,qBAAqB,EAAE,CAAC;YACjC,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC;oBACjD,KAAK,EAAE,GAAG,CAAC,KAAK;oBAChB,QAAQ,EAAE,GAAG,CAAC,QAAQ;iBACvB,CAAC,CAAA;gBACF,OAAO,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAA;YACvC,CAAC;YACD,MAAM,CAAC;gBACL,OAAO,KAAK,CAAA;YACd,CAAC;QACH,CAAC;QAED,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,CAClC,qCAAqC;kBACnC,2DAA2D,EAC7D,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,CACjD,CAAA;YACD,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAA;QACxB,CAAC;QACD,MAAM,CAAC;YACL,OAAO,KAAK,CAAA;QACd,CAAC;IACH,CAAC,CAAA;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAC/B,SAA0B,EAC1B,SAA0B,EAAE;IAE5B,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;QACpC,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAA;QAChC,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClE,OAAO,KAAK,CAAA;QACd,CAAC;QACD,IAAI,YAAY,KAAK,GAAG,CAAC,eAAe,EAAE,CAAC;YACzC,OAAO,IAAI,CAAA;QACb,CAAC;QAED,IAAI,MAAM,CAAC,qBAAqB,EAAE,CAAC;YACjC,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC;oBACjD,KAAK,EAAE,GAAG,CAAC,KAAK;oBAChB,QAAQ,EAAE,GAAG,CAAC,QAAQ;iBACvB,CAAC,CAAA;gBACF,OAAO,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAA;YACvC,CAAC;YACD,MAAM,CAAC;gBACL,OAAO,KAAK,CAAA;YACd,CAAC;QACH,CAAC;QAED,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,CAClC,kCAAkC;kBAChC,qDAAqD,EACvD,EAAE,KAAK,EAAE,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,CAC9C,CAAA;YACD,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAA;QACxB,CAAC;QACD,MAAM,CAAC;YACL,OAAO,KAAK,CAAA;QACd,CAAC;IACH,CAAC,CAAA;AACH,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Output budget enforcement for tool results.
3
+ *
4
+ * `applyOutputBudget` truncates `ToolResult.text` when its UTF-8
5
+ * byte size exceeds `budget.maxBytes`, appending a `\n[truncated]`
6
+ * suffix. Truncation is UTF-8-safe: bytes are sliced and re-decoded
7
+ * with `fatal: false` so any partial multi-byte codepoint at the
8
+ * boundary is dropped rather than emitting invalid sequences.
9
+ *
10
+ * `budget.maxRows` is informational — tool impls limit row count
11
+ * via SQL LIMIT. This helper does not attempt row-level truncation.
12
+ */
13
+ import type { OutputBudget, ToolResult } from './types';
14
+ export declare function applyOutputBudget(result: ToolResult, budget: OutputBudget): ToolResult;
15
+ //# sourceMappingURL=budget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.d.ts","sourceRoot":"","sources":["../../src/tools/budget.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAIvD,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,YAAY,GACnB,UAAU,CAiBZ"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Output budget enforcement for tool results.
3
+ *
4
+ * `applyOutputBudget` truncates `ToolResult.text` when its UTF-8
5
+ * byte size exceeds `budget.maxBytes`, appending a `\n[truncated]`
6
+ * suffix. Truncation is UTF-8-safe: bytes are sliced and re-decoded
7
+ * with `fatal: false` so any partial multi-byte codepoint at the
8
+ * boundary is dropped rather than emitting invalid sequences.
9
+ *
10
+ * `budget.maxRows` is informational — tool impls limit row count
11
+ * via SQL LIMIT. This helper does not attempt row-level truncation.
12
+ */
13
+ const TRUNCATE_SUFFIX = '\n[truncated]';
14
+ export function applyOutputBudget(result, budget) {
15
+ if (result.bytes <= budget.maxBytes)
16
+ return result;
17
+ const encoder = new TextEncoder();
18
+ const suffixBytes = encoder.encode(TRUNCATE_SUFFIX).byteLength;
19
+ const targetBytes = Math.max(0, budget.maxBytes - suffixBytes);
20
+ const encoded = encoder.encode(result.text);
21
+ const safeEnd = utf8SafeBoundary(encoded, Math.min(targetBytes, encoded.byteLength));
22
+ const decoded = new TextDecoder('utf-8').decode(encoded.slice(0, safeEnd));
23
+ const truncated = `${decoded}${TRUNCATE_SUFFIX}`;
24
+ return {
25
+ text: truncated,
26
+ rowCount: result.rowCount,
27
+ bytes: encoder.encode(truncated).byteLength,
28
+ };
29
+ }
30
+ /**
31
+ * Walk `end` backward until it points to a valid UTF-8 codepoint
32
+ * boundary — i.e. either past-the-end of the array or at a byte
33
+ * whose top bits are not `10` (continuation). This guarantees that
34
+ * `bytes.slice(0, boundary)` decodes without emitting replacement
35
+ * characters for a partial trailing multibyte sequence.
36
+ */
37
+ function utf8SafeBoundary(bytes, end) {
38
+ let boundary = end;
39
+ // A continuation byte matches 10xxxxxx (0x80..0xBF).
40
+ while (boundary > 0 && (bytes[boundary] & 0xC0) === 0x80) {
41
+ boundary -= 1;
42
+ }
43
+ // If boundary now points to a lead byte (top bit set), check
44
+ // whether the full sequence fits inside `end`. If not, drop the
45
+ // lead byte as well.
46
+ if (boundary > 0 && boundary < bytes.byteLength) {
47
+ const lead = bytes[boundary];
48
+ let seqLen = 0;
49
+ if ((lead & 0x80) === 0x00)
50
+ seqLen = 1;
51
+ else if ((lead & 0xE0) === 0xC0)
52
+ seqLen = 2;
53
+ else if ((lead & 0xF0) === 0xE0)
54
+ seqLen = 3;
55
+ else if ((lead & 0xF8) === 0xF0)
56
+ seqLen = 4;
57
+ if (seqLen > 1 && boundary + seqLen > end) {
58
+ // Partial sequence — drop lead byte.
59
+ return boundary;
60
+ }
61
+ }
62
+ return boundary;
63
+ }
64
+ //# sourceMappingURL=budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.js","sourceRoot":"","sources":["../../src/tools/budget.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,MAAM,eAAe,GAAG,eAAe,CAAA;AAEvC,MAAM,UAAU,iBAAiB,CAC/B,MAAkB,EAClB,MAAoB;IAEpB,IAAI,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,QAAQ;QAAE,OAAO,MAAM,CAAA;IAElD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAA;IACjC,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,UAAU,CAAA;IAC9D,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,GAAG,WAAW,CAAC,CAAA;IAE9D,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAC3C,MAAM,OAAO,GAAG,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAA;IACpF,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAA;IAC1E,MAAM,SAAS,GAAG,GAAG,OAAO,GAAG,eAAe,EAAE,CAAA;IAEhD,OAAO;QACL,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,UAAU;KAC5C,CAAA;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAS,gBAAgB,CAAC,KAAiB,EAAE,GAAW;IACtD,IAAI,QAAQ,GAAG,GAAG,CAAA;IAClB,qDAAqD;IACrD,OAAO,QAAQ,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;QACzD,QAAQ,IAAI,CAAC,CAAA;IACf,CAAC;IACD,6DAA6D;IAC7D,gEAAgE;IAChE,qBAAqB;IACrB,IAAI,QAAQ,GAAG,CAAC,IAAI,QAAQ,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC;QAChD,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAA;QAC5B,IAAI,MAAM,GAAG,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,IAAI;YAAE,MAAM,GAAG,CAAC,CAAA;aACjC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,IAAI;YAAE,MAAM,GAAG,CAAC,CAAA;aACtC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,IAAI;YAAE,MAAM,GAAG,CAAC,CAAA;aACtC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,IAAI;YAAE,MAAM,GAAG,CAAC,CAAA;QAC3C,IAAI,MAAM,GAAG,CAAC,IAAI,QAAQ,GAAG,MAAM,GAAG,GAAG,EAAE,CAAC;YAC1C,qCAAqC;YACrC,OAAO,QAAQ,CAAA;QACjB,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * `createAnalyticsTools` — assemble the 6 wrapped AI SDK tools into
3
+ * a single map ready to hand to `streamText({ tools })` / `generateText`.
4
+ *
5
+ * Wires:
6
+ * - rate limiter (or `null` if `rateLimit: false`)
7
+ * - authorize hook (default `familyScopeAuthorize`, optionally with
8
+ * an injected `familyMembersProvider`)
9
+ * - audit writer (batched, optional)
10
+ * - output budget (default 4096 bytes / 100 rows)
11
+ *
12
+ * Per-request context threading: the AI SDK's `execute(input)` has no
13
+ * ctx arg. We hold a mutable `currentCtx` container and expose
14
+ * `setContext(ctx)`. Consumers (zivaone_app) call `setContext` before
15
+ * each LLM turn — matching how `@mongrov/ai`'s `AIProvider` threads
16
+ * per-request scopes. This design keeps rate-limiter buckets + audit
17
+ * writer state shared across requests rather than rebuilding the
18
+ * whole tool map per turn.
19
+ */
20
+ import type { AnalyticsToolsConfig, AuditWriter, ToolContext } from './types';
21
+ import { makeTool } from './wrap';
22
+ import { type GetActivityTotalInput } from './impls/activity';
23
+ import { type DetectAnomalyInput } from './impls/anomaly';
24
+ import { type CompareTrendInput } from './impls/compare';
25
+ import { type GetHRVInput } from './impls/hrv';
26
+ import { type GetInsightsInput } from './impls/insights';
27
+ import { type GetSleepSummaryInput } from './impls/sleep';
28
+ export interface AnalyticsToolMap {
29
+ getHRV: ReturnType<typeof makeTool<GetHRVInput>>;
30
+ getSleepSummary: ReturnType<typeof makeTool<GetSleepSummaryInput>>;
31
+ getActivityTotal: ReturnType<typeof makeTool<GetActivityTotalInput>>;
32
+ compareTrend: ReturnType<typeof makeTool<CompareTrendInput>>;
33
+ detectAnomaly: ReturnType<typeof makeTool<DetectAnomalyInput>>;
34
+ getInsights: ReturnType<typeof makeTool<GetInsightsInput>>;
35
+ }
36
+ export interface AnalyticsToolsHandle {
37
+ tools: AnalyticsToolMap;
38
+ setContext: (ctx: ToolContext | null) => void;
39
+ auditWriter: AuditWriter;
40
+ close: () => Promise<void>;
41
+ }
42
+ export declare function createAnalyticsTools(config: AnalyticsToolsConfig): AnalyticsToolsHandle;
43
+ //# sourceMappingURL=factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/tools/factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AASH,OAAO,KAAK,EACV,oBAAoB,EACpB,WAAW,EAEX,WAAW,EACZ,MAAM,SAAS,CAAA;AAChB,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAEjC,OAAO,EAGL,KAAK,qBAAqB,EAC3B,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAA6B,KAAK,WAAW,EAAE,MAAM,aAAa,CAAA;AACzE,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,eAAe,CAAA;AAoBtB,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAA;IAChD,eAAe,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,oBAAoB,CAAC,CAAC,CAAA;IAClE,gBAAgB,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,qBAAqB,CAAC,CAAC,CAAA;IACpE,YAAY,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAA;IAC5D,aAAa,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAA;IAC9D,WAAW,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAA;CAC3D;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,gBAAgB,CAAA;IACvB,UAAU,EAAE,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAA;IAC7C,WAAW,EAAE,WAAW,CAAA;IACxB,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3B;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,oBAAoB,GAC3B,oBAAoB,CAiGtB"}