@anuma/sdk 1.0.0 → 1.1.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 (87) hide show
  1. package/README.md +54 -53
  2. package/dist/api/spec.cjs +30 -0
  3. package/dist/api/spec.d.mts +3 -0
  4. package/dist/api/spec.d.ts +3 -0
  5. package/dist/api/spec.mjs +12 -0
  6. package/dist/chunk-4ETHWSXJ.mjs +25 -0
  7. package/dist/client/index.cjs +2344 -0
  8. package/dist/client/index.d.mts +10368 -0
  9. package/dist/client/index.d.ts +10368 -0
  10. package/dist/client/index.mjs +2168 -0
  11. package/dist/clientConfig-WITO4T6L.mjs +12 -0
  12. package/dist/constants/index.cjs +30 -0
  13. package/dist/constants/index.d.mts +20 -0
  14. package/dist/constants/index.d.ts +20 -0
  15. package/dist/constants/index.mjs +5 -0
  16. package/dist/design/index.cjs +1523 -0
  17. package/dist/design/index.d.mts +561 -0
  18. package/dist/design/index.d.ts +561 -0
  19. package/dist/design/index.mjs +1468 -0
  20. package/dist/expo/chunk-DFVCS3QQ.mjs +246 -0
  21. package/dist/{react/chunk-MJJIYFAX.mjs → expo/chunk-GYKJOWEO.mjs} +13 -1
  22. package/dist/expo/chunk-PUKP5H4F.mjs +5278 -0
  23. package/dist/expo/chunk-Y7XT2VNQ.mjs +646 -0
  24. package/dist/expo/clientConfig-VPOGQRNP.mjs +12 -0
  25. package/dist/expo/consolidate-HEMQGOUD.mjs +131 -0
  26. package/dist/expo/index.cjs +16784 -6689
  27. package/dist/expo/index.d.mts +5746 -1474
  28. package/dist/expo/index.d.ts +5746 -1474
  29. package/dist/expo/index.mjs +9669 -6189
  30. package/dist/expo/recall-YRWAAU6K.mjs +8 -0
  31. package/dist/index.cjs +2992 -42
  32. package/dist/index.d.mts +7719 -1835
  33. package/dist/index.d.ts +7719 -1835
  34. package/dist/index.mjs +2859 -39
  35. package/dist/next/index.cjs +6 -2
  36. package/dist/next/index.d.mts +24 -1
  37. package/dist/next/index.d.ts +24 -1
  38. package/dist/next/index.mjs +6 -2
  39. package/dist/pii/transformers.cjs +126 -0
  40. package/dist/pii/transformers.d.mts +103 -0
  41. package/dist/pii/transformers.d.ts +103 -0
  42. package/dist/pii/transformers.mjs +90 -0
  43. package/dist/react/chunk-DFVCS3QQ.mjs +246 -0
  44. package/dist/{expo/chunk-MJJIYFAX.mjs → react/chunk-GYKJOWEO.mjs} +13 -1
  45. package/dist/react/chunk-Q2ANFWEP.mjs +5596 -0
  46. package/dist/react/chunk-TP6CJZ25.mjs +645 -0
  47. package/dist/react/clientConfig-VPOGQRNP.mjs +12 -0
  48. package/dist/react/consolidate-IJH7LD2T.mjs +131 -0
  49. package/dist/react/index.cjs +25453 -11029
  50. package/dist/react/index.d.mts +7388 -1406
  51. package/dist/react/index.d.ts +7388 -1406
  52. package/dist/react/index.mjs +16101 -8648
  53. package/dist/react/recall-YBC7YCNC.mjs +8 -0
  54. package/dist/server/chunk-FMGZTVXQ.mjs +62 -0
  55. package/dist/server/chunk-HPURS22B.mjs +19452 -0
  56. package/dist/server/chunk-PXN5Q3MD.mjs +643 -0
  57. package/dist/server/chunk-RCCKRTBI.mjs +230 -0
  58. package/dist/server/clientConfig-GMADOBPK.mjs +12 -0
  59. package/dist/server/consolidate-A2ZIX5WF.mjs +131 -0
  60. package/dist/server/index.cjs +32109 -0
  61. package/dist/server/index.d.mts +7310 -0
  62. package/dist/server/index.d.ts +7310 -0
  63. package/dist/server/index.mjs +11168 -0
  64. package/dist/server/recall-PFYFVYMS.mjs +8 -0
  65. package/dist/tools/index.cjs +12682 -34
  66. package/dist/tools/index.d.mts +2733 -18
  67. package/dist/tools/index.d.ts +2733 -18
  68. package/dist/tools/index.mjs +12565 -33
  69. package/dist/utils/index.cjs +165 -0
  70. package/dist/utils/index.d.mts +14 -0
  71. package/dist/utils/index.d.ts +14 -0
  72. package/dist/utils/index.mjs +145 -0
  73. package/dist/vercel/index.d.mts +0 -3
  74. package/dist/vercel/index.d.ts +0 -3
  75. package/package.json +127 -16
  76. package/dist/expo/chunk-LJYAMK62.mjs +0 -25
  77. package/dist/expo/chunk-PJCZO4BQ.mjs +0 -25
  78. package/dist/expo/clientConfig-2MI4KULF.mjs +0 -10
  79. package/dist/expo/clientConfig-QDAXFL3W.mjs +0 -10
  80. package/dist/expo/clientConfig-R4IOW7I2.mjs +0 -10
  81. package/dist/react/chunk-LJYAMK62.mjs +0 -25
  82. package/dist/react/chunk-PJCZO4BQ.mjs +0 -25
  83. package/dist/react/clientConfig-2MI4KULF.mjs +0 -10
  84. package/dist/react/clientConfig-QDAXFL3W.mjs +0 -10
  85. package/dist/react/clientConfig-R4IOW7I2.mjs +0 -10
  86. package/dist/tools/chunk-KDFGY4SK.mjs +0 -13
  87. package/dist/tools/clientConfig-RMDOT5YM.mjs +0 -10
@@ -0,0 +1,230 @@
1
+ import {
2
+ BASE_URL
3
+ } from "./chunk-FMGZTVXQ.mjs";
4
+
5
+ // src/lib/logger.ts
6
+ var consoleLogger = {
7
+ debug: console.log.bind(console),
8
+ info: console.info.bind(console),
9
+ warn: console.warn.bind(console),
10
+ error: console.error.bind(console)
11
+ };
12
+ var currentLogger = consoleLogger;
13
+ function getLogger() {
14
+ return currentLogger;
15
+ }
16
+
17
+ // src/lib/memory/portalLlm.ts
18
+ function defaultBaseUrl() {
19
+ return typeof process !== "undefined" && process.env?.ANUMA_PORTAL_BASE_URL || BASE_URL;
20
+ }
21
+ var RESPONSE_FORMAT_OK = /* @__PURE__ */ new Set(["openai", "inclusionai", "deepseek"]);
22
+ var RESPONSE_SCHEMA_OK = /* @__PURE__ */ new Set(["openai"]);
23
+ function supportsResponseFormat(model, variant = "json_object") {
24
+ const allow = variant === "json_schema" ? RESPONSE_SCHEMA_OK : RESPONSE_FORMAT_OK;
25
+ return model.split("/").some((seg) => allow.has(seg));
26
+ }
27
+ var RETRYABLE_HTTP = /* @__PURE__ */ new Set([408, 409, 425, 429]);
28
+ function isRetryableStatus(status) {
29
+ return status >= 500 || RETRYABLE_HTTP.has(status);
30
+ }
31
+ function parseRetryAfterMs(header) {
32
+ if (!header) return null;
33
+ const secs = Number(header);
34
+ if (Number.isFinite(secs)) return Math.max(0, secs * 1e3);
35
+ const dateMs = Date.parse(header);
36
+ if (Number.isFinite(dateMs)) return Math.max(0, dateMs - Date.now());
37
+ return null;
38
+ }
39
+ function defaultBackoffMs(attempt) {
40
+ const base = Math.min(2e3, 250 * 2 ** (attempt - 1));
41
+ return base + Math.floor(Math.random() * 100);
42
+ }
43
+ function sleep(ms) {
44
+ return new Promise((resolve) => setTimeout(resolve, ms));
45
+ }
46
+ async function resolvePortalAuthHeaders(auth, tag) {
47
+ if (auth.apiKey) {
48
+ return { "x-api-key": auth.apiKey };
49
+ }
50
+ if (auth.getToken) {
51
+ let token;
52
+ try {
53
+ token = await auth.getToken();
54
+ } catch (err) {
55
+ getLogger().warn(`[${tag}] getToken threw`, err);
56
+ return null;
57
+ }
58
+ if (!token) {
59
+ getLogger().warn(`[${tag}] getToken returned no token`);
60
+ return null;
61
+ }
62
+ return { Authorization: `Bearer ${token}` };
63
+ }
64
+ throw new Error(`[${tag}] Either apiKey or getToken must be provided`);
65
+ }
66
+ async function callPortalJsonCompletion(req) {
67
+ const log = getLogger();
68
+ const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
69
+ const startedAt = Date.now();
70
+ const overBudget = () => req.totalTimeoutMs !== void 0 && Date.now() - startedAt >= req.totalTimeoutMs;
71
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
72
+ if (attempt > 1 && overBudget()) {
73
+ log.warn(`[${req.tag}] over time budget before attempt ${attempt}, giving up`);
74
+ break;
75
+ }
76
+ const attemptReq = req.totalTimeoutMs !== void 0 ? {
77
+ ...req,
78
+ timeoutMs: Math.max(
79
+ 1,
80
+ Math.min(req.timeoutMs ?? 6e4, req.totalTimeoutMs - (Date.now() - startedAt))
81
+ )
82
+ } : req;
83
+ const outcome = await attemptPortalJson(attemptReq);
84
+ if (outcome.kind === "ok") return outcome.value;
85
+ if (outcome.kind === "terminal") {
86
+ log.warn(`[${req.tag}] ${outcome.reason}`);
87
+ return null;
88
+ }
89
+ if (attempt >= maxAttempts) {
90
+ log.warn(`[${req.tag}] ${outcome.reason} \u2014 attempt ${attempt}/${maxAttempts}, giving up`);
91
+ break;
92
+ }
93
+ const backoff = (req.backoffMs ?? defaultBackoffMs)(attempt);
94
+ const delay = Math.max(backoff, outcome.retryAfterMs ?? 0);
95
+ if (overBudget() || req.totalTimeoutMs !== void 0 && Date.now() - startedAt + delay >= req.totalTimeoutMs) {
96
+ log.warn(
97
+ `[${req.tag}] ${outcome.reason} \u2014 attempt ${attempt}/${maxAttempts}, over time budget, giving up`
98
+ );
99
+ break;
100
+ }
101
+ log.warn(`[${req.tag}] ${outcome.reason} \u2014 attempt ${attempt}/${maxAttempts}, retrying`);
102
+ if (delay > 0) await sleep(delay);
103
+ }
104
+ return null;
105
+ }
106
+ async function attemptPortalJson(req) {
107
+ const baseUrl = req.baseUrl ?? defaultBaseUrl();
108
+ const fetchImpl = req.fetchFn ?? fetch;
109
+ const timeoutMs = req.timeoutMs ?? 6e4;
110
+ const authHeaders = await resolvePortalAuthHeaders(req, req.tag);
111
+ if (authHeaders === null) return { kind: "terminal", reason: "auth unavailable (no token)" };
112
+ const isAnthropic = req.model.startsWith("anthropic/");
113
+ const prefill = isAnthropic ? "{" : "";
114
+ const messages = [
115
+ { role: "system", content: req.systemPrompt },
116
+ { role: "user", content: req.userMessage }
117
+ ];
118
+ if (prefill) messages.push({ role: "assistant", content: prefill });
119
+ const supportsJsonObjectFormat = supportsResponseFormat(req.model);
120
+ const controller = new AbortController();
121
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
122
+ const requestBody = {
123
+ model: req.model,
124
+ messages,
125
+ ...supportsJsonObjectFormat && { response_format: { type: "json_object" } },
126
+ ...req.extra
127
+ };
128
+ if (!supportsJsonObjectFormat) delete requestBody.response_format;
129
+ let response;
130
+ try {
131
+ response = await fetchImpl(`${baseUrl}/api/v1/chat/completions`, {
132
+ method: "POST",
133
+ headers: { ...authHeaders, "Content-Type": "application/json" },
134
+ body: JSON.stringify(requestBody),
135
+ signal: controller.signal
136
+ });
137
+ } catch (err) {
138
+ clearTimeout(timer);
139
+ return { kind: "retryable", reason: `fetch failed: ${err.message}` };
140
+ }
141
+ if (!response.ok) {
142
+ clearTimeout(timer);
143
+ const reason = `portal returned ${response.status}`;
144
+ if (response.status === 401) {
145
+ const tokenAuth = !req.apiKey && !!req.getToken;
146
+ return tokenAuth ? { kind: "retryable", reason: `${reason} (token may be expired; refreshing)` } : { kind: "terminal", reason };
147
+ }
148
+ if (!isRetryableStatus(response.status)) return { kind: "terminal", reason };
149
+ const retryAfterMs = parseRetryAfterMs(response.headers.get("retry-after"));
150
+ return retryAfterMs !== null ? { kind: "retryable", reason, retryAfterMs } : { kind: "retryable", reason };
151
+ }
152
+ let body;
153
+ try {
154
+ body = await response.json();
155
+ } catch (err) {
156
+ clearTimeout(timer);
157
+ return { kind: "retryable", reason: `response body parse failed: ${err.message}` };
158
+ }
159
+ clearTimeout(timer);
160
+ const rawContent = extractCompletionContent(body);
161
+ if (!rawContent) {
162
+ return { kind: "retryable", reason: "portal response had no completion content" };
163
+ }
164
+ const looksLikeContinuation = prefill && /^\s*"/.test(rawContent);
165
+ const content = looksLikeContinuation ? prefill + rawContent : rawContent;
166
+ const candidate = extractJsonCandidate(content);
167
+ let value;
168
+ try {
169
+ value = JSON.parse(candidate);
170
+ } catch (err) {
171
+ return {
172
+ kind: "retryable",
173
+ reason: `completion was not valid JSON: ${err.message}`
174
+ };
175
+ }
176
+ if (value === null) {
177
+ return { kind: "retryable", reason: "completion parsed to null" };
178
+ }
179
+ return { kind: "ok", value };
180
+ }
181
+ function extractJsonCandidate(raw) {
182
+ const trimmed = raw.trim();
183
+ const fence = trimmed.match(/```(?:json)?\s*([\s\S]*?)```/i);
184
+ const body = fence ? fence[1].trim() : trimmed;
185
+ const start = body.search(/[{[]/);
186
+ if (start < 0) return body;
187
+ const open = body[start];
188
+ const close = open === "{" ? "}" : "]";
189
+ let depth = 0;
190
+ let inString = false;
191
+ let escape = false;
192
+ for (let i = start; i < body.length; i++) {
193
+ const ch = body[i];
194
+ if (escape) {
195
+ escape = false;
196
+ continue;
197
+ }
198
+ if (ch === "\\" && inString) {
199
+ escape = true;
200
+ continue;
201
+ }
202
+ if (ch === '"') {
203
+ inString = !inString;
204
+ continue;
205
+ }
206
+ if (inString) continue;
207
+ if (ch === open) depth++;
208
+ else if (ch === close) {
209
+ depth--;
210
+ if (depth === 0) return body.slice(start, i + 1);
211
+ }
212
+ }
213
+ return body;
214
+ }
215
+ function extractCompletionContent(body) {
216
+ if (typeof body !== "object" || body === null) return null;
217
+ const choices = body.choices;
218
+ if (!Array.isArray(choices) || choices.length === 0) return null;
219
+ const first = choices[0];
220
+ const content = first?.message?.content;
221
+ return typeof content === "string" ? content : null;
222
+ }
223
+
224
+ export {
225
+ getLogger,
226
+ supportsResponseFormat,
227
+ resolvePortalAuthHeaders,
228
+ callPortalJsonCompletion,
229
+ extractJsonCandidate
230
+ };
@@ -0,0 +1,12 @@
1
+ import {
2
+ BASE_URL,
3
+ MCP_R2_DOMAIN,
4
+ createClientConfig,
5
+ resolveBaseUrl
6
+ } from "./chunk-FMGZTVXQ.mjs";
7
+ export {
8
+ BASE_URL,
9
+ MCP_R2_DOMAIN,
10
+ createClientConfig,
11
+ resolveBaseUrl
12
+ };
@@ -0,0 +1,131 @@
1
+ import {
2
+ resolvePiiRedactor
3
+ } from "./chunk-PXN5Q3MD.mjs";
4
+ import {
5
+ callPortalJsonCompletion,
6
+ getLogger
7
+ } from "./chunk-RCCKRTBI.mjs";
8
+ import "./chunk-FMGZTVXQ.mjs";
9
+
10
+ // src/lib/memory/consolidate.ts
11
+ var DEFAULT_MODEL = "inclusionai/ling-2.6-flash";
12
+ var DEFAULT_CONSOLIDATE_ATTEMPTS = 3;
13
+ var DEFAULT_CONSOLIDATE_TOTAL_TIMEOUT_MS = 2e4;
14
+ var SYSTEM_PROMPT = `You consolidate a new memory against existing memories from the same user.
15
+
16
+ A "memory" is a self-contained natural-language fact about the user. Multiple memories about the same EXACT FACET (the same dimension of the same subject) should never coexist \u2014 they should be merged into one. Different facets on the same subject (e.g. user's dog's name vs user's dog's age) are SEPARATE memories.
17
+
18
+ Decide one of three actions:
19
+
20
+ - "create": the new memory describes a distinct fact not covered by any existing memory. Write it as new.
21
+ - "update": the new memory describes the SAME FACET as exactly one existing memory. Either it adds detail, corrects a value, or rephrases the same fact. Return targetId of that existing memory + the consolidated content (richest version of the two).
22
+ - "noop": the new memory is already fully captured by an existing memory \u2014 same facet, no new information. Skip the write.
23
+
24
+ RULES (carry these strictly):
25
+
26
+ 1. ONE OBSERVATION PER DISTINCT FACET. If the new memory is about "user's aunt's twins" and an existing memory is also about "user's aunt's twins", they are the same facet \u2192 update, never create.
27
+ 2. MATCH BY FACET, NOT TOPIC. Two memories both mentioning "Zara" is not enough to merge \u2014 only merge if they describe the same property (e.g. both about "user's pending Zara boot exchange"). Two memories about Zara on different topics (e.g. "user shops at Zara" + "user returned a sweater to Zara last week") are separate facets.
28
+ 3. NO COMPUTATION. Do not sum counts, decrement quantities, or derive new facts from existing ones. If the new memory says "user spent $200 today" and an existing memory says "user spent $150 yesterday", these are TWO SEPARATE EVENTS \u2014 create.
29
+ 4. Events with different occurredAt dates are different memories even if the same activity ("user went to gym Monday" vs "user went to gym Friday" \u2014 separate events).
30
+ 5. When in doubt between create and update, choose create. Over-merging loses information; under-merging is recoverable.
31
+
32
+ OUTPUT \u2014 strict JSON, no prose:
33
+ {
34
+ "action": "create" | "update" | "noop",
35
+ "targetId": "<existing memory id, required for update/noop, omit for create>",
36
+ "content": "<consolidated content, required for create/update, omit for noop>"
37
+ }
38
+
39
+ For "create": content is the new memory verbatim (or a slight refinement).
40
+ For "update": content is the merged richest-version, \u226480 words.
41
+ For "noop": no content (existing memory is already correct).`;
42
+ async function consolidateMemory(newContent, candidates, options) {
43
+ const fallback = {
44
+ action: "create",
45
+ content: newContent
46
+ };
47
+ const trimmed = newContent.trim();
48
+ if (trimmed.length === 0) return fallback;
49
+ if (candidates.length === 0) return fallback;
50
+ const redactor = resolvePiiRedactor(options.piiRedaction);
51
+ const safeTrimmed = redactor ? redactor.redactText(trimmed).text : trimmed;
52
+ const candidateText = candidates.map((c, i) => {
53
+ const safeContent = redactor ? redactor.redactText(c.content).text : c.content;
54
+ return `[${i + 1}] (id: ${c.id}, sim: ${c.similarity.toFixed(2)})
55
+ ${safeContent}`;
56
+ }).join("\n");
57
+ const userMessage = `New memory:
58
+ ${safeTrimmed}
59
+
60
+ Existing memories (top ${candidates.length} by cosine):
61
+ ${candidateText}`;
62
+ let parsed;
63
+ try {
64
+ parsed = await callPortalJsonCompletion({
65
+ ...options.apiKey !== void 0 && { apiKey: options.apiKey },
66
+ ...options.getToken !== void 0 && { getToken: options.getToken },
67
+ ...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
68
+ model: options.model ?? DEFAULT_MODEL,
69
+ systemPrompt: SYSTEM_PROMPT,
70
+ userMessage,
71
+ tag: "memory/consolidate",
72
+ // Retry TRANSIENT failures only (network/timeout/5xx/429/empty) before
73
+ // degrading to create — a transient blip would otherwise leave a
74
+ // permanent below-floor paraphrase that never self-heals (see
75
+ // DEFAULT_CONSOLIDATE_ATTEMPTS). The happy path still resolves in one
76
+ // attempt; terminal failures (400/auth) and schema violations never
77
+ // retry. A total budget keeps a hanging portal from stalling retain.
78
+ maxAttempts: options.maxAttempts ?? DEFAULT_CONSOLIDATE_ATTEMPTS,
79
+ totalTimeoutMs: options.totalTimeoutMs ?? DEFAULT_CONSOLIDATE_TOTAL_TIMEOUT_MS,
80
+ ...options.backoffMs && { backoffMs: options.backoffMs },
81
+ ...options.fetchFn && { fetchFn: options.fetchFn }
82
+ });
83
+ } catch (err) {
84
+ return degrade("llm_error", fallback, options, err);
85
+ }
86
+ if (parsed === null) return degrade("llm_error", fallback, options);
87
+ const validIds = new Set(candidates.map((c) => c.id));
88
+ const result = validate(parsed, trimmed, validIds);
89
+ if (!result) return degrade("invalid_response", fallback, options);
90
+ if (redactor && result.content !== void 0) {
91
+ const restored = redactor.restoreForStorage(result.content);
92
+ if (restored.unresolved) {
93
+ return degrade("invalid_response", fallback, options);
94
+ }
95
+ return { ...result, content: restored.text };
96
+ }
97
+ return result;
98
+ }
99
+ function degrade(reason, fallback, options, detail) {
100
+ if (detail !== void 0) {
101
+ getLogger().warn(`memory/consolidate: degraded to create (${reason})`, detail);
102
+ } else {
103
+ getLogger().warn(`memory/consolidate: degraded to create (${reason})`);
104
+ }
105
+ try {
106
+ options.onFallback?.(reason);
107
+ } catch {
108
+ }
109
+ return { ...fallback, fallbackReason: reason };
110
+ }
111
+ function validate(parsed, newContent, validIds) {
112
+ if (typeof parsed !== "object" || parsed === null) return null;
113
+ const obj = parsed;
114
+ const action = obj.action;
115
+ if (action !== "create" && action !== "update" && action !== "noop") return null;
116
+ if (action === "create") {
117
+ const c2 = typeof obj.content === "string" ? obj.content.trim() : "";
118
+ return { action: "create", content: c2.length > 0 ? c2 : newContent };
119
+ }
120
+ const targetId = typeof obj.targetId === "string" ? obj.targetId : null;
121
+ if (!targetId || !validIds.has(targetId)) return null;
122
+ if (action === "noop") {
123
+ return { action: "noop", targetId };
124
+ }
125
+ const c = typeof obj.content === "string" ? obj.content.trim() : "";
126
+ if (c.length === 0) return null;
127
+ return { action: "update", targetId, content: c };
128
+ }
129
+ export {
130
+ consolidateMemory
131
+ };