@anuma/sdk 6.33.1 → 6.33.2
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/dist/design/index.cjs +0 -2
- package/dist/design/index.d.mts +0 -7
- package/dist/design/index.d.ts +0 -7
- package/dist/design/index.mjs +0 -2
- package/dist/expo/{chunk-XD6WOQ5I.mjs → chunk-GQBTAM6Y.mjs} +0 -70
- package/dist/expo/{consolidate-7DBUHQRK.mjs → consolidate-3H2WY3FU.mjs} +1 -8
- package/dist/expo/index.cjs +15394 -16278
- package/dist/expo/index.d.mts +5734 -6660
- package/dist/expo/index.d.ts +5734 -6660
- package/dist/expo/index.mjs +15231 -16034
- package/dist/index.cjs +2258 -2411
- package/dist/index.d.mts +914 -1054
- package/dist/index.d.ts +914 -1054
- package/dist/index.mjs +2258 -2409
- package/dist/memory/context.d.mts +0 -73
- package/dist/memory/context.d.ts +0 -73
- package/dist/next/index.cjs +1 -8
- package/dist/next/index.mjs +1 -8
- package/dist/pii/transformers.d.mts +0 -32
- package/dist/pii/transformers.d.ts +0 -32
- package/dist/react/{chunk-XNQRJBIH.mjs → chunk-UFO4W3JX.mjs} +0 -70
- package/dist/react/{consolidate-5DVINCUE.mjs → consolidate-RHIAUBT4.mjs} +1 -8
- package/dist/react/index.cjs +32415 -33395
- package/dist/react/index.d.mts +13354 -14553
- package/dist/react/index.d.ts +13354 -14553
- package/dist/react/index.mjs +32556 -33457
- package/dist/server/{chunk-KSYV7UO2.mjs → chunk-4RGGAOAJ.mjs} +835 -905
- package/dist/server/{consolidate-MCNBSUXD.mjs → consolidate-YEGACWLR.mjs} +1 -8
- package/dist/server/index.cjs +22313 -23120
- package/dist/server/index.d.mts +5353 -6300
- package/dist/server/index.d.ts +5353 -6300
- package/dist/server/index.mjs +18789 -19531
- package/dist/telemetry/index.cjs +0 -9
- package/dist/telemetry/index.d.mts +88 -198
- package/dist/telemetry/index.d.ts +88 -198
- package/dist/telemetry/index.mjs +0 -9
- package/dist/tools/index.cjs +13036 -13347
- package/dist/tools/index.d.mts +2434 -2729
- package/dist/tools/index.d.ts +2434 -2729
- package/dist/tools/index.mjs +13036 -13347
- package/dist/tools/selection/index.cjs +0 -116
- package/dist/tools/selection/index.d.mts +0 -159
- package/dist/tools/selection/index.d.ts +0 -159
- package/dist/tools/selection/index.mjs +0 -116
- package/package.json +1 -1
|
@@ -174,44 +174,6 @@ interface EntityOperationsContext {
|
|
|
174
174
|
allowUnscopedRows?: boolean;
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
-
/**
|
|
178
|
-
* Shared portal LLM call for the memory pipeline.
|
|
179
|
-
*
|
|
180
|
-
* The three LLM-driven steps (`extractFacts`, `consolidateMemory`,
|
|
181
|
-
* `decomposeQuery`) share the same shape: POST to `/api/v1/chat/completions`
|
|
182
|
-
* with a system+user prompt and `response_format: json_object`, parse
|
|
183
|
-
* `choices[0].message.content` as JSON, validate, return null on any failure.
|
|
184
|
-
* This helper owns the fetch+timeout+parse+log boilerplate so each caller
|
|
185
|
-
* stays focused on its prompt and validator.
|
|
186
|
-
*
|
|
187
|
-
* PROMPT CACHING. The portal inserts explicit prompt-cache breakpoints only for
|
|
188
|
-
* `anthropic/` models. Its request schema does carry OpenAI's
|
|
189
|
-
* `prompt_cache_key`, but that is a routing hint for OpenAI's own implicit
|
|
190
|
-
* cache rather than a switch that enables caching, and we deliberately don't
|
|
191
|
-
* send it: the memory pipeline runs open-weights models by default (gpt-oss for
|
|
192
|
-
* extraction/topics, ling for consolidation), and this module already has one
|
|
193
|
-
* hard lesson about OpenAI-standard fields a non-OpenAI provider hard-400s on
|
|
194
|
-
* (`response_format`, below). Revisit only with a verified per-provider gate.
|
|
195
|
-
*
|
|
196
|
-
* So on the models this pipeline actually uses, the only cache that can hit is
|
|
197
|
-
* the provider's own implicit prefix cache — which makes prefix stability the
|
|
198
|
-
* one lever a caller controls. Messages are assembled system-first (below), so
|
|
199
|
-
* every caller must pass a CONSTANT `systemPrompt` and keep all per-call
|
|
200
|
-
* material in `userMessage`: a single interpolated timestamp, id, or count in a
|
|
201
|
-
* system prompt shifts every byte after it and misses the cache on every
|
|
202
|
-
* request thereafter. The memory callers are regression-gated on that property
|
|
203
|
-
* in `promptPrefixStability.test.ts`.
|
|
204
|
-
*
|
|
205
|
-
* Whether those implicit caches hit is observable: each successful response
|
|
206
|
-
* logs the portal's reported token counts at debug level, including
|
|
207
|
-
* `portal.cached_tokens` (the prompt tokens the provider served from cache —
|
|
208
|
-
* the portal omits the field when there was no hit). See {@link logPortalUsage}.
|
|
209
|
-
*
|
|
210
|
-
* There is no batch/async-bulk route on the portal, so a backfill or reindex
|
|
211
|
-
* has no discounted-throughput path either; its only levers are the same stable
|
|
212
|
-
* prefix and caller-side batching (e.g. topicExtract's 10-memories-per-call).
|
|
213
|
-
*/
|
|
214
|
-
|
|
215
177
|
/**
|
|
216
178
|
* Auth for portal LLM calls (extraction, consolidation, decomposition,
|
|
217
179
|
* reflection). Mirrors `memoryEngine`'s `EmbeddingOptions` dual-auth:
|
|
@@ -231,16 +193,6 @@ interface PortalLlmAuth {
|
|
|
231
193
|
getToken?: () => Promise<string | null>;
|
|
232
194
|
}
|
|
233
195
|
|
|
234
|
-
/**
|
|
235
|
-
* Linear recency decay multiplier — applied post-fusion to nudge fresh
|
|
236
|
-
* memories above stale ones with otherwise comparable scores.
|
|
237
|
-
*
|
|
238
|
-
* Formula:
|
|
239
|
-
* multiplier(ageDays) = max(floor, 1 - perYearDecay * (ageDays / 365))
|
|
240
|
-
*
|
|
241
|
-
* Memories without an `updatedAt` get a neutral 0.5 (Hindsight pattern —
|
|
242
|
-
* neither boost nor penalty when freshness is unknown).
|
|
243
|
-
*/
|
|
244
196
|
interface RecencyOptions {
|
|
245
197
|
/** Override "now" — useful for deterministic tests and back-dated benchmarks. */
|
|
246
198
|
now?: Date;
|
|
@@ -263,16 +215,6 @@ interface RecencyOptions {
|
|
|
263
215
|
*/
|
|
264
216
|
type ObservationTrend = "new" | "strengthening" | "stable" | "weakening" | "stale";
|
|
265
217
|
|
|
266
|
-
/**
|
|
267
|
-
* Unified memory layer types — the Recall / Retain API.
|
|
268
|
-
*
|
|
269
|
-
* This module defines the public surface for the new unified memory layer
|
|
270
|
-
* that sits above `memoryVault` (curated facts) and `memoryEngine` (raw
|
|
271
|
-
* conversation chunks). Callers should prefer these types over the legacy
|
|
272
|
-
* `VaultSearchResult` / `ChunkSearchResult` shapes; the underlying stores
|
|
273
|
-
* may converge later, the API will not.
|
|
274
|
-
*/
|
|
275
|
-
|
|
276
218
|
type MemoryKind = "fact" | "chunk";
|
|
277
219
|
/**
|
|
278
220
|
* Budget controls retrieval depth/cost. Higher budgets enable more
|
|
@@ -704,21 +646,6 @@ interface RecallDiagnostics {
|
|
|
704
646
|
degraded: RecallDegradation[];
|
|
705
647
|
}
|
|
706
648
|
|
|
707
|
-
/**
|
|
708
|
-
* Auto-extraction worker — W2.
|
|
709
|
-
*
|
|
710
|
-
* After each assistant turn, this pipeline reads the recent conversation,
|
|
711
|
-
* asks an LLM to identify durable user facts, and writes them to the
|
|
712
|
-
* vault via retain(). The user never needs to ask Anuma to remember
|
|
713
|
-
* something — durable facts are captured automatically.
|
|
714
|
-
*
|
|
715
|
-
* Two-stage pipeline (extract → retain). The retain step uses
|
|
716
|
-
* write-time auto-merge (W4) so the same fact re-observed in a later
|
|
717
|
-
* conversation increments proof_count instead of duplicating.
|
|
718
|
-
*
|
|
719
|
-
* Spec: see `tasks/hackathon/auto-extraction-prompt.md`.
|
|
720
|
-
*/
|
|
721
|
-
|
|
722
649
|
declare const FACT_TYPES: readonly ["identity", "preference", "relationship", "plan", "ongoing_context", "constraint", "other"];
|
|
723
650
|
type FactType = (typeof FACT_TYPES)[number];
|
|
724
651
|
|
package/dist/memory/context.d.ts
CHANGED
|
@@ -174,44 +174,6 @@ interface EntityOperationsContext {
|
|
|
174
174
|
allowUnscopedRows?: boolean;
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
-
/**
|
|
178
|
-
* Shared portal LLM call for the memory pipeline.
|
|
179
|
-
*
|
|
180
|
-
* The three LLM-driven steps (`extractFacts`, `consolidateMemory`,
|
|
181
|
-
* `decomposeQuery`) share the same shape: POST to `/api/v1/chat/completions`
|
|
182
|
-
* with a system+user prompt and `response_format: json_object`, parse
|
|
183
|
-
* `choices[0].message.content` as JSON, validate, return null on any failure.
|
|
184
|
-
* This helper owns the fetch+timeout+parse+log boilerplate so each caller
|
|
185
|
-
* stays focused on its prompt and validator.
|
|
186
|
-
*
|
|
187
|
-
* PROMPT CACHING. The portal inserts explicit prompt-cache breakpoints only for
|
|
188
|
-
* `anthropic/` models. Its request schema does carry OpenAI's
|
|
189
|
-
* `prompt_cache_key`, but that is a routing hint for OpenAI's own implicit
|
|
190
|
-
* cache rather than a switch that enables caching, and we deliberately don't
|
|
191
|
-
* send it: the memory pipeline runs open-weights models by default (gpt-oss for
|
|
192
|
-
* extraction/topics, ling for consolidation), and this module already has one
|
|
193
|
-
* hard lesson about OpenAI-standard fields a non-OpenAI provider hard-400s on
|
|
194
|
-
* (`response_format`, below). Revisit only with a verified per-provider gate.
|
|
195
|
-
*
|
|
196
|
-
* So on the models this pipeline actually uses, the only cache that can hit is
|
|
197
|
-
* the provider's own implicit prefix cache — which makes prefix stability the
|
|
198
|
-
* one lever a caller controls. Messages are assembled system-first (below), so
|
|
199
|
-
* every caller must pass a CONSTANT `systemPrompt` and keep all per-call
|
|
200
|
-
* material in `userMessage`: a single interpolated timestamp, id, or count in a
|
|
201
|
-
* system prompt shifts every byte after it and misses the cache on every
|
|
202
|
-
* request thereafter. The memory callers are regression-gated on that property
|
|
203
|
-
* in `promptPrefixStability.test.ts`.
|
|
204
|
-
*
|
|
205
|
-
* Whether those implicit caches hit is observable: each successful response
|
|
206
|
-
* logs the portal's reported token counts at debug level, including
|
|
207
|
-
* `portal.cached_tokens` (the prompt tokens the provider served from cache —
|
|
208
|
-
* the portal omits the field when there was no hit). See {@link logPortalUsage}.
|
|
209
|
-
*
|
|
210
|
-
* There is no batch/async-bulk route on the portal, so a backfill or reindex
|
|
211
|
-
* has no discounted-throughput path either; its only levers are the same stable
|
|
212
|
-
* prefix and caller-side batching (e.g. topicExtract's 10-memories-per-call).
|
|
213
|
-
*/
|
|
214
|
-
|
|
215
177
|
/**
|
|
216
178
|
* Auth for portal LLM calls (extraction, consolidation, decomposition,
|
|
217
179
|
* reflection). Mirrors `memoryEngine`'s `EmbeddingOptions` dual-auth:
|
|
@@ -231,16 +193,6 @@ interface PortalLlmAuth {
|
|
|
231
193
|
getToken?: () => Promise<string | null>;
|
|
232
194
|
}
|
|
233
195
|
|
|
234
|
-
/**
|
|
235
|
-
* Linear recency decay multiplier — applied post-fusion to nudge fresh
|
|
236
|
-
* memories above stale ones with otherwise comparable scores.
|
|
237
|
-
*
|
|
238
|
-
* Formula:
|
|
239
|
-
* multiplier(ageDays) = max(floor, 1 - perYearDecay * (ageDays / 365))
|
|
240
|
-
*
|
|
241
|
-
* Memories without an `updatedAt` get a neutral 0.5 (Hindsight pattern —
|
|
242
|
-
* neither boost nor penalty when freshness is unknown).
|
|
243
|
-
*/
|
|
244
196
|
interface RecencyOptions {
|
|
245
197
|
/** Override "now" — useful for deterministic tests and back-dated benchmarks. */
|
|
246
198
|
now?: Date;
|
|
@@ -263,16 +215,6 @@ interface RecencyOptions {
|
|
|
263
215
|
*/
|
|
264
216
|
type ObservationTrend = "new" | "strengthening" | "stable" | "weakening" | "stale";
|
|
265
217
|
|
|
266
|
-
/**
|
|
267
|
-
* Unified memory layer types — the Recall / Retain API.
|
|
268
|
-
*
|
|
269
|
-
* This module defines the public surface for the new unified memory layer
|
|
270
|
-
* that sits above `memoryVault` (curated facts) and `memoryEngine` (raw
|
|
271
|
-
* conversation chunks). Callers should prefer these types over the legacy
|
|
272
|
-
* `VaultSearchResult` / `ChunkSearchResult` shapes; the underlying stores
|
|
273
|
-
* may converge later, the API will not.
|
|
274
|
-
*/
|
|
275
|
-
|
|
276
218
|
type MemoryKind = "fact" | "chunk";
|
|
277
219
|
/**
|
|
278
220
|
* Budget controls retrieval depth/cost. Higher budgets enable more
|
|
@@ -704,21 +646,6 @@ interface RecallDiagnostics {
|
|
|
704
646
|
degraded: RecallDegradation[];
|
|
705
647
|
}
|
|
706
648
|
|
|
707
|
-
/**
|
|
708
|
-
* Auto-extraction worker — W2.
|
|
709
|
-
*
|
|
710
|
-
* After each assistant turn, this pipeline reads the recent conversation,
|
|
711
|
-
* asks an LLM to identify durable user facts, and writes them to the
|
|
712
|
-
* vault via retain(). The user never needs to ask Anuma to remember
|
|
713
|
-
* something — durable facts are captured automatically.
|
|
714
|
-
*
|
|
715
|
-
* Two-stage pipeline (extract → retain). The retain step uses
|
|
716
|
-
* write-time auto-merge (W4) so the same fact re-observed in a later
|
|
717
|
-
* conversation increments proof_count instead of duplicating.
|
|
718
|
-
*
|
|
719
|
-
* Spec: see `tasks/hackathon/auto-extraction-prompt.md`.
|
|
720
|
-
*/
|
|
721
|
-
|
|
722
649
|
declare const FACT_TYPES: readonly ["identity", "preference", "relationship", "plan", "ongoing_context", "constraint", "other"];
|
|
723
650
|
type FactType = (typeof FACT_TYPES)[number];
|
|
724
651
|
|
package/dist/next/index.cjs
CHANGED
|
@@ -26,14 +26,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
26
26
|
var withAnuma = (nextConfig = {}) => {
|
|
27
27
|
return {
|
|
28
28
|
...nextConfig,
|
|
29
|
-
serverExternalPackages: [
|
|
30
|
-
...nextConfig.serverExternalPackages ?? [],
|
|
31
|
-
"sharp",
|
|
32
|
-
// exceljs pulls in unzipper → fstream which calls process.umask() at
|
|
33
|
-
// module init time, crashing Cloudflare Workers and other edge runtimes.
|
|
34
|
-
// Externalizing prevents the server bundler from including it in SSR.
|
|
35
|
-
"exceljs"
|
|
36
|
-
],
|
|
29
|
+
serverExternalPackages: [...nextConfig.serverExternalPackages ?? [], "sharp", "exceljs"],
|
|
37
30
|
webpack: (config, options) => {
|
|
38
31
|
const { isServer } = options;
|
|
39
32
|
if (!isServer) {
|
package/dist/next/index.mjs
CHANGED
|
@@ -2,14 +2,7 @@
|
|
|
2
2
|
var withAnuma = (nextConfig = {}) => {
|
|
3
3
|
return {
|
|
4
4
|
...nextConfig,
|
|
5
|
-
serverExternalPackages: [
|
|
6
|
-
...nextConfig.serverExternalPackages ?? [],
|
|
7
|
-
"sharp",
|
|
8
|
-
// exceljs pulls in unzipper → fstream which calls process.umask() at
|
|
9
|
-
// module init time, crashing Cloudflare Workers and other edge runtimes.
|
|
10
|
-
// Externalizing prevents the server bundler from including it in SSR.
|
|
11
|
-
"exceljs"
|
|
12
|
-
],
|
|
5
|
+
serverExternalPackages: [...nextConfig.serverExternalPackages ?? [], "sharp", "exceljs"],
|
|
13
6
|
webpack: (config, options) => {
|
|
14
7
|
const { isServer } = options;
|
|
15
8
|
if (!isServer) {
|
|
@@ -6,23 +6,6 @@
|
|
|
6
6
|
*/
|
|
7
7
|
type PiiCategory = "EMAIL" | "PHONE" | "SSN" | "CREDIT_CARD" | "IP_ADDRESS" | "API_KEY" | "US_ADDRESS" | "DATE_OF_BIRTH";
|
|
8
8
|
|
|
9
|
-
/**
|
|
10
|
-
* NER detector contract for PII redaction.
|
|
11
|
-
*
|
|
12
|
-
* The regex layer in {@link ./patterns} handles *structured* PII (email, phone,
|
|
13
|
-
* SSN, credit card, …). It cannot detect *unstructured* PII — person names,
|
|
14
|
-
* locations, organizations — which need a named-entity-recognition model.
|
|
15
|
-
*
|
|
16
|
-
* Rather than bundle a model (and a runtime) into the SDK, we define a small
|
|
17
|
-
* runtime-agnostic contract: a {@link NerDetector} takes text and returns the
|
|
18
|
-
* spans it found. Consumers supply an implementation appropriate to their
|
|
19
|
-
* platform — a Transformers.js model in the browser/Node (see
|
|
20
|
-
* `./detectors/transformers`), an `onnxruntime-react-native` model on mobile,
|
|
21
|
-
* a remote service, or a fake in tests. The SDK keeps detection *on-device* by
|
|
22
|
-
* never calling out itself; it only consumes the spans a detector returns and
|
|
23
|
-
* merges them into the existing placeholder map.
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
9
|
/**
|
|
27
10
|
* A character-offset span of detected PII. `start`/`end` are indices into the
|
|
28
11
|
* text passed to {@link NerDetector.detect} (`end` exclusive). `category`
|
|
@@ -51,21 +34,6 @@ interface NerDetector {
|
|
|
51
34
|
detect(text: string): Promise<PiiSpan[]>;
|
|
52
35
|
}
|
|
53
36
|
|
|
54
|
-
/**
|
|
55
|
-
* Reference {@link NerDetector} backed by Transformers.js (`@huggingface/transformers`).
|
|
56
|
-
*
|
|
57
|
-
* Runs a quantized BERT NER model fully on-device (browser via the
|
|
58
|
-
* onnxruntime-web/WASM backend, or Node) — no network call, so PII never leaves
|
|
59
|
-
* the device. The model is loaded lazily on first `detect()` and cached, so
|
|
60
|
-
* importing this module is cheap and apps that never enable NER pay nothing.
|
|
61
|
-
*
|
|
62
|
-
* `@huggingface/transformers` is an OPTIONAL peer dependency: it is `import()`-ed
|
|
63
|
-
* dynamically (matching `lib/memory/reranker.ts`) so it is only required when a
|
|
64
|
-
* caller actually constructs this detector. React Native cannot use this
|
|
65
|
-
* detector (its WASM backend doesn't run under Hermes) — supply an
|
|
66
|
-
* `onnxruntime-react-native`-based {@link NerDetector} there instead.
|
|
67
|
-
*/
|
|
68
|
-
|
|
69
37
|
interface TransformersNerDetectorOptions {
|
|
70
38
|
/** Hugging Face model id. Default: `Xenova/bert-base-NER`. */
|
|
71
39
|
model?: string;
|
|
@@ -6,23 +6,6 @@
|
|
|
6
6
|
*/
|
|
7
7
|
type PiiCategory = "EMAIL" | "PHONE" | "SSN" | "CREDIT_CARD" | "IP_ADDRESS" | "API_KEY" | "US_ADDRESS" | "DATE_OF_BIRTH";
|
|
8
8
|
|
|
9
|
-
/**
|
|
10
|
-
* NER detector contract for PII redaction.
|
|
11
|
-
*
|
|
12
|
-
* The regex layer in {@link ./patterns} handles *structured* PII (email, phone,
|
|
13
|
-
* SSN, credit card, …). It cannot detect *unstructured* PII — person names,
|
|
14
|
-
* locations, organizations — which need a named-entity-recognition model.
|
|
15
|
-
*
|
|
16
|
-
* Rather than bundle a model (and a runtime) into the SDK, we define a small
|
|
17
|
-
* runtime-agnostic contract: a {@link NerDetector} takes text and returns the
|
|
18
|
-
* spans it found. Consumers supply an implementation appropriate to their
|
|
19
|
-
* platform — a Transformers.js model in the browser/Node (see
|
|
20
|
-
* `./detectors/transformers`), an `onnxruntime-react-native` model on mobile,
|
|
21
|
-
* a remote service, or a fake in tests. The SDK keeps detection *on-device* by
|
|
22
|
-
* never calling out itself; it only consumes the spans a detector returns and
|
|
23
|
-
* merges them into the existing placeholder map.
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
9
|
/**
|
|
27
10
|
* A character-offset span of detected PII. `start`/`end` are indices into the
|
|
28
11
|
* text passed to {@link NerDetector.detect} (`end` exclusive). `category`
|
|
@@ -51,21 +34,6 @@ interface NerDetector {
|
|
|
51
34
|
detect(text: string): Promise<PiiSpan[]>;
|
|
52
35
|
}
|
|
53
36
|
|
|
54
|
-
/**
|
|
55
|
-
* Reference {@link NerDetector} backed by Transformers.js (`@huggingface/transformers`).
|
|
56
|
-
*
|
|
57
|
-
* Runs a quantized BERT NER model fully on-device (browser via the
|
|
58
|
-
* onnxruntime-web/WASM backend, or Node) — no network call, so PII never leaves
|
|
59
|
-
* the device. The model is loaded lazily on first `detect()` and cached, so
|
|
60
|
-
* importing this module is cheap and apps that never enable NER pay nothing.
|
|
61
|
-
*
|
|
62
|
-
* `@huggingface/transformers` is an OPTIONAL peer dependency: it is `import()`-ed
|
|
63
|
-
* dynamically (matching `lib/memory/reranker.ts`) so it is only required when a
|
|
64
|
-
* caller actually constructs this detector. React Native cannot use this
|
|
65
|
-
* detector (its WASM backend doesn't run under Hermes) — supply an
|
|
66
|
-
* `onnxruntime-react-native`-based {@link NerDetector} there instead.
|
|
67
|
-
*/
|
|
68
|
-
|
|
69
37
|
interface TransformersNerDetectorOptions {
|
|
70
38
|
/** Hugging Face model id. Default: `Xenova/bert-base-NER`. */
|
|
71
39
|
model?: string;
|
|
@@ -59,15 +59,10 @@ function luhnCheck(digits) {
|
|
|
59
59
|
return sum % 10 === 0;
|
|
60
60
|
}
|
|
61
61
|
var PII_PATTERNS = [
|
|
62
|
-
// Email — standard RFC-ish pattern.
|
|
63
|
-
// Quantifiers are bounded (local-part ≤ 64, domain ≤ 255, TLD ≤ 24 —
|
|
64
|
-
// all at or above real RFC 5321 limits) so the engine cannot backtrack
|
|
65
|
-
// quadratically on adversarial input like "a.a.a.a…" with no "@".
|
|
66
62
|
{
|
|
67
63
|
category: "EMAIL",
|
|
68
64
|
regex: /\b[a-zA-Z0-9._%+-]{1,64}@[a-zA-Z0-9.-]{1,255}\.[a-zA-Z]{2,24}\b/g
|
|
69
65
|
},
|
|
70
|
-
// SSN — US Social Security Number, dashed form (must run before phone)
|
|
71
66
|
{
|
|
72
67
|
category: "SSN",
|
|
73
68
|
regex: /\b\d{3}-\d{2}-\d{4}\b/g,
|
|
@@ -77,9 +72,6 @@ var PII_PATTERNS = [
|
|
|
77
72
|
return area !== 0 && area !== 666 && area < 900;
|
|
78
73
|
}
|
|
79
74
|
},
|
|
80
|
-
// SSN — dashless or space-separated form. Only redacted with an "SSN" /
|
|
81
|
-
// "social security" cue nearby: a bare 9-digit run is too ambiguous
|
|
82
|
-
// (ZIP+4, account numbers, etc.) to redact unconditionally.
|
|
83
75
|
{
|
|
84
76
|
category: "SSN",
|
|
85
77
|
regex: /\b\d{3}[ ]?\d{2}[ ]?\d{4}\b/g,
|
|
@@ -91,8 +83,6 @@ var PII_PATTERNS = [
|
|
|
91
83
|
return area !== 0 && area !== 666 && area < 900;
|
|
92
84
|
}
|
|
93
85
|
},
|
|
94
|
-
// Credit card numbers — 13-19 contiguous digits or groups of 4 separated by spaces/dashes
|
|
95
|
-
// Must run before phone to avoid partial matches
|
|
96
86
|
{
|
|
97
87
|
category: "CREDIT_CARD",
|
|
98
88
|
regex: /\b\d{4}[\s-]\d{4}[\s-]\d{4}[\s-]\d{1,7}\b|\b\d{13,19}\b/g,
|
|
@@ -102,7 +92,6 @@ var PII_PATTERNS = [
|
|
|
102
92
|
return luhnCheck(digits);
|
|
103
93
|
}
|
|
104
94
|
},
|
|
105
|
-
// IPv4 addresses (must run before phone to avoid partial matches)
|
|
106
95
|
{
|
|
107
96
|
category: "IP_ADDRESS",
|
|
108
97
|
regex: /\b(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\b/g,
|
|
@@ -110,31 +99,15 @@ var PII_PATTERNS = [
|
|
|
110
99
|
return match !== "0.0.0.0" && match !== "127.0.0.1" && match !== "255.255.255.255";
|
|
111
100
|
}
|
|
112
101
|
},
|
|
113
|
-
// IPv6 addresses — full and compressed (::) forms. Each alternative requires
|
|
114
|
-
// either a full 8-group address or a "::" compression, so ordinary
|
|
115
|
-
// colon-separated text (timestamps like 12:34:56) does not match. Loopback
|
|
116
|
-
// (::1) and unspecified (::) are excluded.
|
|
117
102
|
{
|
|
118
103
|
category: "IP_ADDRESS",
|
|
119
104
|
regex: /(?:(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,7}:|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:(?::[0-9a-fA-F]{1,4}){1,6}|:(?:(?::[0-9a-fA-F]{1,4}){1,7}|:))/g,
|
|
120
105
|
validate: (match) => match !== "::1" && match !== "::"
|
|
121
106
|
},
|
|
122
|
-
// Phone numbers. The separated form requires separator characters (dashes,
|
|
123
|
-
// spaces, dots, parens) to avoid matching bare digit sequences that are
|
|
124
|
-
// actually credit cards, IPs, or years. A second alternative matches E.164
|
|
125
|
-
// (a leading "+" then 10–15 digits, e.g. +14155552671), which is
|
|
126
|
-
// unambiguous; a bare 10-digit run with no "+" and no separators is
|
|
127
|
-
// intentionally not matched to avoid false positives.
|
|
128
107
|
{
|
|
129
108
|
category: "PHONE",
|
|
130
109
|
regex: /(?:\+\d{1,3}[\s.-])?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}\b|\+\d{10,15}\b/g
|
|
131
110
|
},
|
|
132
|
-
// API keys / secrets — long token with a key-like prefix. The validator
|
|
133
|
-
// requires entropy (at least one digit, or a mix of upper- and lower-case)
|
|
134
|
-
// so long all-lowercase prose identifiers like
|
|
135
|
-
// "accessibility_is_important_for_everyone" or
|
|
136
|
-
// "access-control-list-management-feature" are not redacted. Real keys and
|
|
137
|
-
// tokens essentially always contain digits or mixed case.
|
|
138
111
|
{
|
|
139
112
|
category: "API_KEY",
|
|
140
113
|
regex: /\b(?:sk|pk|api|key|token|secret|bearer|access)[_-]?[a-zA-Z0-9_-]{20,}\b/gi,
|
|
@@ -144,13 +117,6 @@ var PII_PATTERNS = [
|
|
|
144
117
|
return hasDigit || hasMixedCase;
|
|
145
118
|
}
|
|
146
119
|
},
|
|
147
|
-
// US street addresses — house number + Title-Case street name + suffix.
|
|
148
|
-
// Intentionally NOT case-insensitive: the `[A-Z][a-z]+` guard requires
|
|
149
|
-
// properly-capitalized street words, so "123 main street", "100 MAIN
|
|
150
|
-
// STREET" and prose like "3 blocks down the road" / "5 minutes to drive"
|
|
151
|
-
// are not treated as addresses. Whitespace is `[ \t]` only (no newline
|
|
152
|
-
// spanning), and the suffix must end the segment (punctuation / newline /
|
|
153
|
-
// end of string) so "Driveway" or "Wayfair" don't match on the suffix.
|
|
154
120
|
{
|
|
155
121
|
category: "US_ADDRESS",
|
|
156
122
|
regex: /\b\d{1,5}[ \t]+(?:[A-Z][a-z]+[ \t]+){1,3}(?:St(?:reet)?|Ave(?:nue)?|Blvd|Boulevard|Dr(?:ive)?|Ln|Lane|Rd|Road|Ct|Court|Pl(?:ace)?|Way|Cir(?:cle)?|Pkwy|Parkway|Hwy|Highway)\.?(?=[\s,.;:!?)]|$)/g,
|
|
@@ -158,11 +124,6 @@ var PII_PATTERNS = [
|
|
|
158
124
|
return !/^0/.test(match.trim());
|
|
159
125
|
}
|
|
160
126
|
},
|
|
161
|
-
// Dates of birth — common US date formats. Only redacted when a birth-date
|
|
162
|
-
// cue ("DOB", "born", "birthday", "date of birth") appears just before the
|
|
163
|
-
// date, so ordinary calendar dates ("meeting 12/25/2024", deadlines,
|
|
164
|
-
// invoices) are left intact for the model. A calendar validator also rejects
|
|
165
|
-
// impossible dates like 02/31/1990.
|
|
166
127
|
{
|
|
167
128
|
category: "DATE_OF_BIRTH",
|
|
168
129
|
regex: /\b(?:(?:0?[1-9]|1[0-2])[/-](?:0?[1-9]|[12]\d|3[01])[/-](?:19|20)\d{2})\b/g,
|
|
@@ -343,12 +304,6 @@ var PiiRedactor = class {
|
|
|
343
304
|
maskText(text) {
|
|
344
305
|
return this.scan(text, (category) => `[${category}]`).text;
|
|
345
306
|
}
|
|
346
|
-
// ───────────────────────────────────────────────────────────────────────
|
|
347
|
-
// Async (regex + NER) path. Mirrors the sync API but additionally folds in
|
|
348
|
-
// an optional {@link NerDetector}'s spans. When no detector is configured,
|
|
349
|
-
// each async method delegates to its sync counterpart and is byte-for-byte
|
|
350
|
-
// identical — so it is a safe drop-in.
|
|
351
|
-
// ───────────────────────────────────────────────────────────────────────
|
|
352
307
|
/** All regex matches as spans on the ORIGINAL text (priority 0). Uses the
|
|
353
308
|
* same {@link findMatches} guards as the sync scan. */
|
|
354
309
|
collectRegexSpans(text) {
|
|
@@ -892,16 +847,7 @@ async function attemptPortalJson(req, endpoint) {
|
|
|
892
847
|
const usesPrefill = req.transport !== "responses" && req.model.startsWith("anthropic/");
|
|
893
848
|
const prefill = usesPrefill ? "{" : "";
|
|
894
849
|
const messages = [
|
|
895
|
-
// Every caller of this helper is a first-party BACKGROUND op (fact extraction,
|
|
896
|
-
// topic sweep, consolidation, classifiers, graph traversal, query
|
|
897
|
-
// decomposition). Marking here — the one place they all funnel through — is what
|
|
898
|
-
// keeps the portal's detector reading them as genuine rather than markerless.
|
|
899
|
-
// See ../internalFlowMarker.
|
|
900
850
|
{ role: "system", content: withInternalFlowMarker(req.systemPrompt) },
|
|
901
|
-
// Retry-only. Kept as a SEPARATE message rather than appended to the system
|
|
902
|
-
// prompt so the marked prompt above stays byte-identical across attempts —
|
|
903
|
-
// the portal's internal-flow detector reads that one, and rewriting it on a
|
|
904
|
-
// retry would change what the detector sees for reasons unrelated to auth.
|
|
905
851
|
...req.reinforceJsonContract ? [{ role: "system", content: JSON_CONTRACT_REMINDER }] : [],
|
|
906
852
|
{ role: "user", content: req.userMessage }
|
|
907
853
|
];
|
|
@@ -911,22 +857,8 @@ async function attemptPortalJson(req, endpoint) {
|
|
|
911
857
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
912
858
|
const requestBody = req.transport === "responses" ? {
|
|
913
859
|
model: req.model,
|
|
914
|
-
// Same system+user pair under the Responses-API field name. No prefill
|
|
915
|
-
// entry to strip: `usesPrefill` is false on this transport, so it was
|
|
916
|
-
// never pushed and the response-side restore is disarmed with it. An
|
|
917
|
-
// earlier version pushed it and sliced it back off here, which left
|
|
918
|
-
// `prefill` truthy and the restore still armed — the fix belonged at
|
|
919
|
-
// the decision, not at the two symptoms.
|
|
920
860
|
input: messages,
|
|
921
861
|
...req.reasoning && { reasoning: req.reasoning },
|
|
922
|
-
// NO response_format. The Responses API spells structured output
|
|
923
|
-
// differently (`text.format`), and it is unverified against this
|
|
924
|
-
// portal — so this transport relies on the same strict-JSON system
|
|
925
|
-
// prompt plus `extractJsonCandidate` that every response_format-
|
|
926
|
-
// rejecting model already relies on. Verified end to end on dev:
|
|
927
|
-
// luna returns clean parseable JSON here without it. Add the field
|
|
928
|
-
// only with a per-provider check, exactly as RESPONSE_FORMAT_OK was
|
|
929
|
-
// earned.
|
|
930
862
|
...responsesExtra(req.extra)
|
|
931
863
|
} : {
|
|
932
864
|
model: req.model,
|
|
@@ -941,8 +873,6 @@ async function attemptPortalJson(req, endpoint) {
|
|
|
941
873
|
try {
|
|
942
874
|
response = await fetchImpl(`${baseUrl}${endpoint}`, {
|
|
943
875
|
method: "POST",
|
|
944
|
-
// Attached HERE, at the one transport every background memory op shares, so
|
|
945
|
-
// a new flow gets the provenance by construction rather than by remembering.
|
|
946
876
|
headers: {
|
|
947
877
|
...authHeaders,
|
|
948
878
|
...taskTypeHeader(req.taskType),
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
callPortalJsonCompletion,
|
|
3
3
|
notifyConsolidationFallback,
|
|
4
4
|
resolvePiiRedactor
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-UFO4W3JX.mjs";
|
|
6
6
|
import "./chunk-GYKJOWEO.mjs";
|
|
7
7
|
|
|
8
8
|
// src/lib/memory/consolidate.ts
|
|
@@ -80,12 +80,6 @@ ${candidateText}`;
|
|
|
80
80
|
systemPrompt: SYSTEM_PROMPT,
|
|
81
81
|
userMessage,
|
|
82
82
|
tag: "memory/consolidate",
|
|
83
|
-
// Retry TRANSIENT failures only (network/timeout/5xx/429/empty) before
|
|
84
|
-
// degrading to create — a transient blip would otherwise leave a
|
|
85
|
-
// permanent below-floor paraphrase that never self-heals (see
|
|
86
|
-
// DEFAULT_CONSOLIDATE_ATTEMPTS). The happy path still resolves in one
|
|
87
|
-
// attempt; terminal failures (400/auth) and schema violations never
|
|
88
|
-
// retry. A total budget keeps a hanging portal from stalling retain.
|
|
89
83
|
maxAttempts: options.maxAttempts ?? DEFAULT_CONSOLIDATE_ATTEMPTS,
|
|
90
84
|
totalTimeoutMs: options.totalTimeoutMs ?? DEFAULT_CONSOLIDATE_TOTAL_TIMEOUT_MS,
|
|
91
85
|
...options.backoffMs && { backoffMs: options.backoffMs },
|
|
@@ -162,7 +156,6 @@ function validate(parsed, newContent, validIds) {
|
|
|
162
156
|
const positional = Array.isArray(obj.targetSubjects) ? obj.targetSubjects : [];
|
|
163
157
|
const statedSubjects = [
|
|
164
158
|
...positional.map((s) => subjectKey(s)),
|
|
165
|
-
// The singular pair, which is the whole story for a one-target supersede.
|
|
166
159
|
subjectKey(obj.targetSubject)
|
|
167
160
|
];
|
|
168
161
|
if (statedSubjects.some((s) => s.length > 0 && s !== newSubject)) {
|