@anuma/sdk 3.6.3 → 3.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/expo/{chunk-FKACNV6X.mjs → chunk-AAB7OG7Q.mjs} +2 -2
- package/dist/expo/{chunk-DFVCS3QQ.mjs → chunk-BOY27A2C.mjs} +30 -3
- package/dist/expo/{consolidate-3QQPUWD6.mjs → consolidate-HKN32P5W.mjs} +25 -11
- package/dist/expo/index.cjs +107 -42
- package/dist/expo/index.d.mts +9 -0
- package/dist/expo/index.d.ts +9 -0
- package/dist/expo/index.mjs +51 -33
- package/dist/{react/recall-JOLS3V4B.mjs → expo/recall-YVU7OSSJ.mjs} +2 -2
- package/dist/react/{chunk-ZGMHRWOR.mjs → chunk-3VPEZDYL.mjs} +2 -2
- package/dist/react/{chunk-DFVCS3QQ.mjs → chunk-BOY27A2C.mjs} +30 -3
- package/dist/react/{consolidate-3MXZV3G7.mjs → consolidate-7UUX56GM.mjs} +25 -11
- package/dist/react/index.cjs +107 -42
- package/dist/react/index.d.mts +9 -0
- package/dist/react/index.d.ts +9 -0
- package/dist/react/index.mjs +51 -33
- package/dist/{expo/recall-VZHV7ILE.mjs → react/recall-Z7BWJ67X.mjs} +2 -2
- package/dist/server/{chunk-66UWDXS3.mjs → chunk-LSKFJNLF.mjs} +2 -2
- package/dist/server/{chunk-AHJT66EO.mjs → chunk-MIXEASUP.mjs} +30 -3
- package/dist/server/{consolidate-CN2GQV4D.mjs → consolidate-BKLNVH5Y.mjs} +25 -11
- package/dist/server/index.cjs +107 -42
- package/dist/server/index.d.mts +36 -0
- package/dist/server/index.d.ts +36 -0
- package/dist/server/index.mjs +51 -33
- package/dist/server/{recall-UTVH2XPK.mjs → recall-XEOLXA6P.mjs} +2 -2
- package/package.json +3 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
callPortalJsonCompletion,
|
|
3
3
|
getLogger
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-MIXEASUP.mjs";
|
|
5
5
|
import {
|
|
6
6
|
BASE_URL,
|
|
7
7
|
__commonJS,
|
|
@@ -19554,7 +19554,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
19554
19554
|
legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
|
|
19555
19555
|
);
|
|
19556
19556
|
}
|
|
19557
|
-
const { recall: recall2 } = await import("./recall-
|
|
19557
|
+
const { recall: recall2 } = await import("./recall-XEOLXA6P.mjs");
|
|
19558
19558
|
const result = await recall2(
|
|
19559
19559
|
query,
|
|
19560
19560
|
{ vaultCtx, embeddingOptions, vaultCache: cache },
|
|
@@ -14,6 +14,24 @@ function getLogger() {
|
|
|
14
14
|
return currentLogger;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
// src/lib/chat/endpointOverride.ts
|
|
18
|
+
function validateEndpointOverride(override) {
|
|
19
|
+
const trimmed = override.trim();
|
|
20
|
+
if (trimmed === "") {
|
|
21
|
+
return {
|
|
22
|
+
valid: false,
|
|
23
|
+
message: 'endpointOverride must be a non-empty, root-relative path (e.g. "/api/v1/utility/responses"); received an empty or whitespace-only string'
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
if (trimmed.startsWith("//") || trimmed.includes("://")) {
|
|
27
|
+
return {
|
|
28
|
+
valid: false,
|
|
29
|
+
message: `endpointOverride must be a root-relative path (e.g. "/api/v1/utility/responses"), not a protocol-relative or absolute URL; received "${trimmed}"`
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
return { valid: true, endpoint: trimmed.startsWith("/") ? trimmed : `/${trimmed}` };
|
|
33
|
+
}
|
|
34
|
+
|
|
17
35
|
// src/lib/memory/portalLlm.ts
|
|
18
36
|
function defaultBaseUrl() {
|
|
19
37
|
return typeof process !== "undefined" && process.env?.ANUMA_PORTAL_BASE_URL || BASE_URL;
|
|
@@ -65,6 +83,14 @@ async function resolvePortalAuthHeaders(auth, tag) {
|
|
|
65
83
|
}
|
|
66
84
|
async function callPortalJsonCompletion(req) {
|
|
67
85
|
const log = getLogger();
|
|
86
|
+
let endpoint = "/api/v1/chat/completions";
|
|
87
|
+
if (req.endpointOverride !== void 0) {
|
|
88
|
+
const overrideValidation = validateEndpointOverride(req.endpointOverride);
|
|
89
|
+
if (!overrideValidation.valid) {
|
|
90
|
+
throw new Error(overrideValidation.message);
|
|
91
|
+
}
|
|
92
|
+
endpoint = overrideValidation.endpoint;
|
|
93
|
+
}
|
|
68
94
|
const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
|
|
69
95
|
const startedAt = Date.now();
|
|
70
96
|
const overBudget = () => req.totalTimeoutMs !== void 0 && Date.now() - startedAt >= req.totalTimeoutMs;
|
|
@@ -80,7 +106,7 @@ async function callPortalJsonCompletion(req) {
|
|
|
80
106
|
Math.min(req.timeoutMs ?? 6e4, req.totalTimeoutMs - (Date.now() - startedAt))
|
|
81
107
|
)
|
|
82
108
|
} : req;
|
|
83
|
-
const outcome = await attemptPortalJson(attemptReq);
|
|
109
|
+
const outcome = await attemptPortalJson(attemptReq, endpoint);
|
|
84
110
|
if (outcome.kind === "ok") return outcome.value;
|
|
85
111
|
if (outcome.kind === "terminal") {
|
|
86
112
|
log.warn(`[${req.tag}] ${outcome.reason}`);
|
|
@@ -103,7 +129,7 @@ async function callPortalJsonCompletion(req) {
|
|
|
103
129
|
}
|
|
104
130
|
return null;
|
|
105
131
|
}
|
|
106
|
-
async function attemptPortalJson(req) {
|
|
132
|
+
async function attemptPortalJson(req, endpoint) {
|
|
107
133
|
const baseUrl = req.baseUrl ?? defaultBaseUrl();
|
|
108
134
|
const fetchImpl = req.fetchFn ?? fetch;
|
|
109
135
|
const timeoutMs = req.timeoutMs ?? 6e4;
|
|
@@ -128,7 +154,7 @@ async function attemptPortalJson(req) {
|
|
|
128
154
|
if (!supportsJsonObjectFormat) delete requestBody.response_format;
|
|
129
155
|
let response;
|
|
130
156
|
try {
|
|
131
|
-
response = await fetchImpl(`${baseUrl}
|
|
157
|
+
response = await fetchImpl(`${baseUrl}${endpoint}`, {
|
|
132
158
|
method: "POST",
|
|
133
159
|
headers: { ...authHeaders, "Content-Type": "application/json" },
|
|
134
160
|
body: JSON.stringify(requestBody),
|
|
@@ -223,6 +249,7 @@ function extractCompletionContent(body) {
|
|
|
223
249
|
|
|
224
250
|
export {
|
|
225
251
|
getLogger,
|
|
252
|
+
validateEndpointOverride,
|
|
226
253
|
supportsResponseFormat,
|
|
227
254
|
resolvePortalAuthHeaders,
|
|
228
255
|
callPortalJsonCompletion,
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
callPortalJsonCompletion,
|
|
6
6
|
getLogger
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-MIXEASUP.mjs";
|
|
8
8
|
import "./chunk-3RPGXXPZ.mjs";
|
|
9
9
|
|
|
10
10
|
// src/lib/memory/consolidate.ts
|
|
@@ -19,7 +19,7 @@ Decide one of four actions:
|
|
|
19
19
|
|
|
20
20
|
- "create": the new memory describes a distinct fact not covered by any existing memory. Write it as new.
|
|
21
21
|
- "update": the new memory describes the SAME FACET as exactly one existing memory and is COMPATIBLE with it \u2014 it adds detail, fixes an incomplete value, or rephrases the same still-true fact. Return targetId of that existing memory + the consolidated content (richest version of the two).
|
|
22
|
-
- "supersede": the new memory REPLACES a standing fact whose value has CHANGED and is now INCOMPATIBLE with an existing memory \u2014 the old fact was true before but is false now (a state change). Return
|
|
22
|
+
- "supersede": the new memory REPLACES a standing fact whose value has CHANGED and is now INCOMPATIBLE with an existing memory \u2014 the old fact was true before but is false now (a state change). Return "targetIds": an array of the ids of EVERY existing candidate that describes the SAME standing attribute now being changed \u2014 retire ALL stale duplicates of the old value, not just one (the candidate list may contain several paraphrases of the same old fact) + content = the NEW fact. The old memories are kept as history, not overwritten or deleted; do not re-state them.
|
|
23
23
|
- "noop": the new memory is already fully captured by an existing memory \u2014 same facet, no new information. Skip the write.
|
|
24
24
|
|
|
25
25
|
RULES (carry these strictly):
|
|
@@ -35,14 +35,15 @@ RULES (carry these strictly):
|
|
|
35
35
|
OUTPUT \u2014 strict JSON, no prose:
|
|
36
36
|
{
|
|
37
37
|
"action": "create" | "update" | "supersede" | "noop",
|
|
38
|
-
"targetId": "<existing memory id \u2014 required for update/
|
|
38
|
+
"targetId": "<existing memory id \u2014 required for update/noop, omit for create/supersede>",
|
|
39
|
+
"targetIds": ["<id>", ...],
|
|
39
40
|
"content": "<content \u2014 required for create/update/supersede, omit for noop>"
|
|
40
41
|
}
|
|
41
42
|
|
|
42
|
-
For "create": content is the new memory verbatim (or a slight refinement).
|
|
43
|
-
For "update": content is the merged richest-version, \u226480 words.
|
|
44
|
-
For "supersede": content is the NEW fact only (\u226480 words);
|
|
45
|
-
For "noop": no content (existing memory is already correct).`;
|
|
43
|
+
For "create": content is the new memory verbatim (or a slight refinement); omit targetId/targetIds.
|
|
44
|
+
For "update": content is the merged richest-version, \u226480 words; targetId is the single memory to update.
|
|
45
|
+
For "supersede": content is the NEW fact only (\u226480 words); "targetIds" lists EVERY stale memory being retired (all candidates describing the same now-changed attribute).
|
|
46
|
+
For "noop": no content (existing memory is already correct); targetId is that memory.`;
|
|
46
47
|
async function consolidateMemory(newContent, candidates, options) {
|
|
47
48
|
const fallback = {
|
|
48
49
|
action: "create",
|
|
@@ -123,14 +124,27 @@ function validate(parsed, newContent, validIds) {
|
|
|
123
124
|
const c2 = typeof obj.content === "string" ? obj.content.trim() : "";
|
|
124
125
|
return { action: "create", content: c2.length > 0 ? c2 : newContent };
|
|
125
126
|
}
|
|
126
|
-
const targetId = typeof obj.targetId === "string" ? obj.targetId : null;
|
|
127
|
-
if (!targetId || !validIds.has(targetId)) return null;
|
|
128
127
|
if (action === "noop") {
|
|
129
|
-
|
|
128
|
+
const targetId2 = typeof obj.targetId === "string" ? obj.targetId : null;
|
|
129
|
+
if (!targetId2 || !validIds.has(targetId2)) return null;
|
|
130
|
+
return { action: "noop", targetId: targetId2 };
|
|
130
131
|
}
|
|
131
132
|
const c = typeof obj.content === "string" ? obj.content.trim() : "";
|
|
132
133
|
if (c.length === 0) return null;
|
|
133
|
-
|
|
134
|
+
if (action === "supersede") {
|
|
135
|
+
const rawIds = [
|
|
136
|
+
...Array.isArray(obj.targetIds) ? obj.targetIds : [],
|
|
137
|
+
...typeof obj.targetId === "string" ? [obj.targetId] : []
|
|
138
|
+
];
|
|
139
|
+
const targetIds = [
|
|
140
|
+
...new Set(rawIds.filter((id) => typeof id === "string" && validIds.has(id)))
|
|
141
|
+
];
|
|
142
|
+
if (targetIds.length === 0) return null;
|
|
143
|
+
return { action: "supersede", targetId: targetIds[0], targetIds, content: c };
|
|
144
|
+
}
|
|
145
|
+
const targetId = typeof obj.targetId === "string" ? obj.targetId : null;
|
|
146
|
+
if (!targetId || !validIds.has(targetId)) return null;
|
|
147
|
+
return { action: "update", targetId, content: c };
|
|
134
148
|
}
|
|
135
149
|
export {
|
|
136
150
|
consolidateMemory
|
package/dist/server/index.cjs
CHANGED
|
@@ -19549,6 +19549,29 @@ var init_bm25 = __esm({
|
|
|
19549
19549
|
}
|
|
19550
19550
|
});
|
|
19551
19551
|
|
|
19552
|
+
// src/lib/chat/endpointOverride.ts
|
|
19553
|
+
function validateEndpointOverride(override) {
|
|
19554
|
+
const trimmed = override.trim();
|
|
19555
|
+
if (trimmed === "") {
|
|
19556
|
+
return {
|
|
19557
|
+
valid: false,
|
|
19558
|
+
message: 'endpointOverride must be a non-empty, root-relative path (e.g. "/api/v1/utility/responses"); received an empty or whitespace-only string'
|
|
19559
|
+
};
|
|
19560
|
+
}
|
|
19561
|
+
if (trimmed.startsWith("//") || trimmed.includes("://")) {
|
|
19562
|
+
return {
|
|
19563
|
+
valid: false,
|
|
19564
|
+
message: `endpointOverride must be a root-relative path (e.g. "/api/v1/utility/responses"), not a protocol-relative or absolute URL; received "${trimmed}"`
|
|
19565
|
+
};
|
|
19566
|
+
}
|
|
19567
|
+
return { valid: true, endpoint: trimmed.startsWith("/") ? trimmed : `/${trimmed}` };
|
|
19568
|
+
}
|
|
19569
|
+
var init_endpointOverride = __esm({
|
|
19570
|
+
"src/lib/chat/endpointOverride.ts"() {
|
|
19571
|
+
"use strict";
|
|
19572
|
+
}
|
|
19573
|
+
});
|
|
19574
|
+
|
|
19552
19575
|
// src/lib/memory/portalLlm.ts
|
|
19553
19576
|
function defaultBaseUrl() {
|
|
19554
19577
|
return typeof process !== "undefined" && process.env?.ANUMA_PORTAL_BASE_URL || BASE_URL;
|
|
@@ -19597,6 +19620,14 @@ async function resolvePortalAuthHeaders(auth, tag) {
|
|
|
19597
19620
|
}
|
|
19598
19621
|
async function callPortalJsonCompletion(req) {
|
|
19599
19622
|
const log = getLogger();
|
|
19623
|
+
let endpoint = "/api/v1/chat/completions";
|
|
19624
|
+
if (req.endpointOverride !== void 0) {
|
|
19625
|
+
const overrideValidation = validateEndpointOverride(req.endpointOverride);
|
|
19626
|
+
if (!overrideValidation.valid) {
|
|
19627
|
+
throw new Error(overrideValidation.message);
|
|
19628
|
+
}
|
|
19629
|
+
endpoint = overrideValidation.endpoint;
|
|
19630
|
+
}
|
|
19600
19631
|
const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
|
|
19601
19632
|
const startedAt = Date.now();
|
|
19602
19633
|
const overBudget = () => req.totalTimeoutMs !== void 0 && Date.now() - startedAt >= req.totalTimeoutMs;
|
|
@@ -19612,7 +19643,7 @@ async function callPortalJsonCompletion(req) {
|
|
|
19612
19643
|
Math.min(req.timeoutMs ?? 6e4, req.totalTimeoutMs - (Date.now() - startedAt))
|
|
19613
19644
|
)
|
|
19614
19645
|
} : req;
|
|
19615
|
-
const outcome = await attemptPortalJson(attemptReq);
|
|
19646
|
+
const outcome = await attemptPortalJson(attemptReq, endpoint);
|
|
19616
19647
|
if (outcome.kind === "ok") return outcome.value;
|
|
19617
19648
|
if (outcome.kind === "terminal") {
|
|
19618
19649
|
log.warn(`[${req.tag}] ${outcome.reason}`);
|
|
@@ -19635,7 +19666,7 @@ async function callPortalJsonCompletion(req) {
|
|
|
19635
19666
|
}
|
|
19636
19667
|
return null;
|
|
19637
19668
|
}
|
|
19638
|
-
async function attemptPortalJson(req) {
|
|
19669
|
+
async function attemptPortalJson(req, endpoint) {
|
|
19639
19670
|
const baseUrl = req.baseUrl ?? defaultBaseUrl();
|
|
19640
19671
|
const fetchImpl = req.fetchFn ?? fetch;
|
|
19641
19672
|
const timeoutMs = req.timeoutMs ?? 6e4;
|
|
@@ -19660,7 +19691,7 @@ async function attemptPortalJson(req) {
|
|
|
19660
19691
|
if (!supportsJsonObjectFormat) delete requestBody.response_format;
|
|
19661
19692
|
let response;
|
|
19662
19693
|
try {
|
|
19663
|
-
response = await fetchImpl(`${baseUrl}
|
|
19694
|
+
response = await fetchImpl(`${baseUrl}${endpoint}`, {
|
|
19664
19695
|
method: "POST",
|
|
19665
19696
|
headers: { ...authHeaders, "Content-Type": "application/json" },
|
|
19666
19697
|
body: JSON.stringify(requestBody),
|
|
@@ -19757,6 +19788,7 @@ var init_portalLlm = __esm({
|
|
|
19757
19788
|
"src/lib/memory/portalLlm.ts"() {
|
|
19758
19789
|
"use strict";
|
|
19759
19790
|
init_clientConfig();
|
|
19791
|
+
init_endpointOverride();
|
|
19760
19792
|
init_logger();
|
|
19761
19793
|
RESPONSE_FORMAT_OK = /* @__PURE__ */ new Set(["openai", "inclusionai", "deepseek"]);
|
|
19762
19794
|
RESPONSE_SCHEMA_OK = /* @__PURE__ */ new Set(["openai"]);
|
|
@@ -22426,14 +22458,27 @@ function validate2(parsed, newContent, validIds) {
|
|
|
22426
22458
|
const c2 = typeof obj.content === "string" ? obj.content.trim() : "";
|
|
22427
22459
|
return { action: "create", content: c2.length > 0 ? c2 : newContent };
|
|
22428
22460
|
}
|
|
22429
|
-
const targetId = typeof obj.targetId === "string" ? obj.targetId : null;
|
|
22430
|
-
if (!targetId || !validIds.has(targetId)) return null;
|
|
22431
22461
|
if (action === "noop") {
|
|
22432
|
-
|
|
22462
|
+
const targetId2 = typeof obj.targetId === "string" ? obj.targetId : null;
|
|
22463
|
+
if (!targetId2 || !validIds.has(targetId2)) return null;
|
|
22464
|
+
return { action: "noop", targetId: targetId2 };
|
|
22433
22465
|
}
|
|
22434
22466
|
const c = typeof obj.content === "string" ? obj.content.trim() : "";
|
|
22435
22467
|
if (c.length === 0) return null;
|
|
22436
|
-
|
|
22468
|
+
if (action === "supersede") {
|
|
22469
|
+
const rawIds = [
|
|
22470
|
+
...Array.isArray(obj.targetIds) ? obj.targetIds : [],
|
|
22471
|
+
...typeof obj.targetId === "string" ? [obj.targetId] : []
|
|
22472
|
+
];
|
|
22473
|
+
const targetIds = [
|
|
22474
|
+
...new Set(rawIds.filter((id) => typeof id === "string" && validIds.has(id)))
|
|
22475
|
+
];
|
|
22476
|
+
if (targetIds.length === 0) return null;
|
|
22477
|
+
return { action: "supersede", targetId: targetIds[0], targetIds, content: c };
|
|
22478
|
+
}
|
|
22479
|
+
const targetId = typeof obj.targetId === "string" ? obj.targetId : null;
|
|
22480
|
+
if (!targetId || !validIds.has(targetId)) return null;
|
|
22481
|
+
return { action: "update", targetId, content: c };
|
|
22437
22482
|
}
|
|
22438
22483
|
var DEFAULT_MODEL3, DEFAULT_CONSOLIDATE_ATTEMPTS, DEFAULT_CONSOLIDATE_TOTAL_TIMEOUT_MS, SYSTEM_PROMPT3;
|
|
22439
22484
|
var init_consolidate = __esm({
|
|
@@ -22453,7 +22498,7 @@ Decide one of four actions:
|
|
|
22453
22498
|
|
|
22454
22499
|
- "create": the new memory describes a distinct fact not covered by any existing memory. Write it as new.
|
|
22455
22500
|
- "update": the new memory describes the SAME FACET as exactly one existing memory and is COMPATIBLE with it \u2014 it adds detail, fixes an incomplete value, or rephrases the same still-true fact. Return targetId of that existing memory + the consolidated content (richest version of the two).
|
|
22456
|
-
- "supersede": the new memory REPLACES a standing fact whose value has CHANGED and is now INCOMPATIBLE with an existing memory \u2014 the old fact was true before but is false now (a state change). Return
|
|
22501
|
+
- "supersede": the new memory REPLACES a standing fact whose value has CHANGED and is now INCOMPATIBLE with an existing memory \u2014 the old fact was true before but is false now (a state change). Return "targetIds": an array of the ids of EVERY existing candidate that describes the SAME standing attribute now being changed \u2014 retire ALL stale duplicates of the old value, not just one (the candidate list may contain several paraphrases of the same old fact) + content = the NEW fact. The old memories are kept as history, not overwritten or deleted; do not re-state them.
|
|
22457
22502
|
- "noop": the new memory is already fully captured by an existing memory \u2014 same facet, no new information. Skip the write.
|
|
22458
22503
|
|
|
22459
22504
|
RULES (carry these strictly):
|
|
@@ -22469,14 +22514,15 @@ RULES (carry these strictly):
|
|
|
22469
22514
|
OUTPUT \u2014 strict JSON, no prose:
|
|
22470
22515
|
{
|
|
22471
22516
|
"action": "create" | "update" | "supersede" | "noop",
|
|
22472
|
-
"targetId": "<existing memory id \u2014 required for update/
|
|
22517
|
+
"targetId": "<existing memory id \u2014 required for update/noop, omit for create/supersede>",
|
|
22518
|
+
"targetIds": ["<id>", ...],
|
|
22473
22519
|
"content": "<content \u2014 required for create/update/supersede, omit for noop>"
|
|
22474
22520
|
}
|
|
22475
22521
|
|
|
22476
|
-
For "create": content is the new memory verbatim (or a slight refinement).
|
|
22477
|
-
For "update": content is the merged richest-version, \u226480 words.
|
|
22478
|
-
For "supersede": content is the NEW fact only (\u226480 words);
|
|
22479
|
-
For "noop": no content (existing memory is already correct).`;
|
|
22522
|
+
For "create": content is the new memory verbatim (or a slight refinement); omit targetId/targetIds.
|
|
22523
|
+
For "update": content is the merged richest-version, \u226480 words; targetId is the single memory to update.
|
|
22524
|
+
For "supersede": content is the NEW fact only (\u226480 words); "targetIds" lists EVERY stale memory being retired (all candidates describing the same now-changed attribute).
|
|
22525
|
+
For "noop": no content (existing memory is already correct); targetId is that memory.`;
|
|
22480
22526
|
}
|
|
22481
22527
|
});
|
|
22482
22528
|
|
|
@@ -27125,14 +27171,15 @@ init_portalLlm();
|
|
|
27125
27171
|
|
|
27126
27172
|
// src/lib/memory/retain.ts
|
|
27127
27173
|
init_operations3();
|
|
27174
|
+
init_logger();
|
|
27128
27175
|
init_constants();
|
|
27129
27176
|
init_embeddings();
|
|
27130
27177
|
init_vector();
|
|
27131
27178
|
init_searchTool();
|
|
27132
|
-
var DEFAULT_AUTO_MERGE_THRESHOLD = 0.
|
|
27179
|
+
var DEFAULT_AUTO_MERGE_THRESHOLD = 0.8;
|
|
27133
27180
|
var DEFAULT_SCOPE = "private";
|
|
27134
|
-
var DEFAULT_CONSOLIDATE_THRESHOLD = 0.
|
|
27135
|
-
var DEFAULT_CONSOLIDATE_TOP_K =
|
|
27181
|
+
var DEFAULT_CONSOLIDATE_THRESHOLD = 0.55;
|
|
27182
|
+
var DEFAULT_CONSOLIDATE_TOP_K = 20;
|
|
27136
27183
|
async function retain(content, ctx, options = {}) {
|
|
27137
27184
|
const trimmed = content.trim();
|
|
27138
27185
|
if (trimmed.length === 0) {
|
|
@@ -27141,18 +27188,18 @@ async function retain(content, ctx, options = {}) {
|
|
|
27141
27188
|
const enableAutoMerge = options.enableAutoMerge ?? true;
|
|
27142
27189
|
const threshold = options.autoMergeThreshold ?? DEFAULT_AUTO_MERGE_THRESHOLD;
|
|
27143
27190
|
const resolvedScope = options.scope ?? DEFAULT_SCOPE;
|
|
27144
|
-
let
|
|
27191
|
+
let supersedeTargetIds = [];
|
|
27145
27192
|
let supersedeContent;
|
|
27146
27193
|
if (enableAutoMerge) {
|
|
27147
27194
|
if (options.consolidateOptions) {
|
|
27148
27195
|
const outcome = await tryConsolidate(trimmed, ctx, options);
|
|
27149
27196
|
if (outcome) {
|
|
27150
27197
|
if ("done" in outcome) return outcome.done;
|
|
27151
|
-
|
|
27198
|
+
supersedeTargetIds = outcome.supersede;
|
|
27152
27199
|
supersedeContent = outcome.content;
|
|
27153
27200
|
}
|
|
27154
27201
|
}
|
|
27155
|
-
if (
|
|
27202
|
+
if (supersedeTargetIds.length === 0) {
|
|
27156
27203
|
const matches = await searchVaultMemories(
|
|
27157
27204
|
trimmed,
|
|
27158
27205
|
ctx.vaultCtx,
|
|
@@ -27256,18 +27303,42 @@ async function retain(content, ctx, options = {}) {
|
|
|
27256
27303
|
// memory's tier. The DB op re-validates against the known set.
|
|
27257
27304
|
...options.trustTier !== void 0 && { trustTier: options.trustTier }
|
|
27258
27305
|
};
|
|
27259
|
-
if (
|
|
27306
|
+
if (supersedeTargetIds.length > 0) {
|
|
27307
|
+
const [primaryTargetId, ...restTargetIds] = supersedeTargetIds;
|
|
27260
27308
|
const { created: created2, retired } = await createSupersedingMemoryOp(
|
|
27261
27309
|
ctx.vaultCtx,
|
|
27262
27310
|
createOpts,
|
|
27263
|
-
|
|
27311
|
+
primaryTargetId
|
|
27264
27312
|
);
|
|
27265
27313
|
if (created2 && retired) {
|
|
27266
27314
|
ctx.vaultCache.set(created2.uniqueId, Float32Array.from(embedding));
|
|
27315
|
+
const liveLeftovers = [];
|
|
27316
|
+
for (const staleId of restTargetIds) {
|
|
27317
|
+
let ok = false;
|
|
27318
|
+
try {
|
|
27319
|
+
ok = await supersedeVaultMemoryOp(ctx.vaultCtx, staleId, created2.uniqueId) === true;
|
|
27320
|
+
} catch {
|
|
27321
|
+
}
|
|
27322
|
+
if (ok) continue;
|
|
27323
|
+
const stillLive = await getVaultMemoryOp(ctx.vaultCtx, staleId).catch(() => null);
|
|
27324
|
+
if (stillLive && !stillLive.supersededBy) liveLeftovers.push(staleId);
|
|
27325
|
+
}
|
|
27326
|
+
if (liveLeftovers.length > 0) {
|
|
27327
|
+
getLogger().warn(
|
|
27328
|
+
"[memory/retain] supersede left duplicate row(s) live \u2014 will reconcile at next consolidation",
|
|
27329
|
+
{
|
|
27330
|
+
newMemoryId: created2.uniqueId,
|
|
27331
|
+
leftover: liveLeftovers.length,
|
|
27332
|
+
// Log the specific ids (opaque record ids, not content) so an
|
|
27333
|
+
// operator can identify exactly which rows are still active.
|
|
27334
|
+
leftoverIds: liveLeftovers
|
|
27335
|
+
}
|
|
27336
|
+
);
|
|
27337
|
+
}
|
|
27267
27338
|
return {
|
|
27268
27339
|
action: "supersede",
|
|
27269
27340
|
memoryId: created2.uniqueId,
|
|
27270
|
-
targetId:
|
|
27341
|
+
targetId: primaryTargetId,
|
|
27271
27342
|
proofCount: 1
|
|
27272
27343
|
};
|
|
27273
27344
|
}
|
|
@@ -27353,10 +27424,16 @@ async function tryConsolidate(trimmed, ctx, options) {
|
|
|
27353
27424
|
const { consolidateMemory: doConsolidate } = await Promise.resolve().then(() => (init_consolidate(), consolidate_exports));
|
|
27354
27425
|
const decision = await doConsolidate(trimmed, candidates, consolidateOptions);
|
|
27355
27426
|
if (decision.action === "create") return null;
|
|
27356
|
-
if (decision.action === "supersede" && decision.
|
|
27357
|
-
const
|
|
27358
|
-
if (
|
|
27359
|
-
|
|
27427
|
+
if (decision.action === "supersede" && decision.content) {
|
|
27428
|
+
const requestedIds = decision.targetIds?.length ? decision.targetIds : decision.targetId ? [decision.targetId] : [];
|
|
27429
|
+
if (requestedIds.length === 0) return null;
|
|
27430
|
+
const valid = [];
|
|
27431
|
+
for (const id of requestedIds) {
|
|
27432
|
+
const existing = await getVaultMemoryOp(ctx.vaultCtx, id);
|
|
27433
|
+
if (existing && !existing.supersededBy) valid.push(id);
|
|
27434
|
+
}
|
|
27435
|
+
if (valid.length === 0) return null;
|
|
27436
|
+
return { supersede: valid, content: decision.content };
|
|
27360
27437
|
}
|
|
27361
27438
|
if (decision.action === "noop" && decision.targetId) {
|
|
27362
27439
|
const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
|
|
@@ -29132,6 +29209,9 @@ When a memory refers to one of these, reuse the EXACT existing name (same spelli
|
|
|
29132
29209
|
...options.apiKey !== void 0 && { apiKey: options.apiKey },
|
|
29133
29210
|
...options.getToken !== void 0 && { getToken: options.getToken },
|
|
29134
29211
|
...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
|
|
29212
|
+
...options.endpointOverride !== void 0 && {
|
|
29213
|
+
endpointOverride: options.endpointOverride
|
|
29214
|
+
},
|
|
29135
29215
|
model: options.model ?? DEFAULT_EXTRACTION_MODEL,
|
|
29136
29216
|
systemPrompt: SYSTEM_PROMPT6,
|
|
29137
29217
|
userMessage: `${vocabularyNote}Memories:
|
|
@@ -31283,6 +31363,7 @@ init_serverSentEvents_gen();
|
|
|
31283
31363
|
init_clientConfig();
|
|
31284
31364
|
init_embeddings();
|
|
31285
31365
|
init_redactor();
|
|
31366
|
+
init_endpointOverride();
|
|
31286
31367
|
|
|
31287
31368
|
// src/lib/chat/runHooks.ts
|
|
31288
31369
|
function composeHooks(hooks) {
|
|
@@ -33433,22 +33514,6 @@ function linkAbortSignals(a, b) {
|
|
|
33433
33514
|
}
|
|
33434
33515
|
};
|
|
33435
33516
|
}
|
|
33436
|
-
function validateEndpointOverride(override) {
|
|
33437
|
-
const trimmed = override.trim();
|
|
33438
|
-
if (trimmed === "") {
|
|
33439
|
-
return {
|
|
33440
|
-
valid: false,
|
|
33441
|
-
message: 'endpointOverride must be a non-empty, root-relative path (e.g. "/api/v1/utility/responses"); received an empty or whitespace-only string'
|
|
33442
|
-
};
|
|
33443
|
-
}
|
|
33444
|
-
if (trimmed.startsWith("//") || trimmed.includes("://")) {
|
|
33445
|
-
return {
|
|
33446
|
-
valid: false,
|
|
33447
|
-
message: `endpointOverride must be a root-relative path (e.g. "/api/v1/utility/responses"), not a protocol-relative or absolute URL; received "${trimmed}"`
|
|
33448
|
-
};
|
|
33449
|
-
}
|
|
33450
|
-
return { valid: true, endpoint: trimmed.startsWith("/") ? trimmed : `/${trimmed}` };
|
|
33451
|
-
}
|
|
33452
33517
|
async function runToolLoop(options) {
|
|
33453
33518
|
const {
|
|
33454
33519
|
model,
|
package/dist/server/index.d.mts
CHANGED
|
@@ -2516,6 +2516,33 @@ type StreamingTransportResult = {
|
|
|
2516
2516
|
* transport both honor this contract.
|
|
2517
2517
|
*/
|
|
2518
2518
|
type StreamingTransport = (options: StreamingTransportOptions) => StreamingTransportResult;
|
|
2519
|
+
/**
|
|
2520
|
+
* Framework-agnostic tool execution loop.
|
|
2521
|
+
*
|
|
2522
|
+
* Sends a streaming completion request, auto-executes tools that have executors,
|
|
2523
|
+
* feeds results back to the model, and repeats until the model stops emitting
|
|
2524
|
+
* tool calls or hits the iteration limit.
|
|
2525
|
+
*
|
|
2526
|
+
* This is the same loop that powers `useChat` in the React SDK, extracted so
|
|
2527
|
+
* it can be used from Node.js servers, CLI tools, and background workers.
|
|
2528
|
+
*
|
|
2529
|
+
* @example
|
|
2530
|
+
* ```ts
|
|
2531
|
+
* import { runToolLoop } from "@anuma/sdk/server";
|
|
2532
|
+
*
|
|
2533
|
+
* const result = await runToolLoop({
|
|
2534
|
+
* messages: [{ role: "user", content: [{ type: "text", text: "What's the weather?" }] }],
|
|
2535
|
+
* model: "fireworks/accounts/fireworks/models/kimi-k2p5",
|
|
2536
|
+
* token: "my-api-token",
|
|
2537
|
+
* tools: [{
|
|
2538
|
+
* type: "function",
|
|
2539
|
+
* function: { name: "get_weather", parameters: { type: "object", properties: { city: { type: "string" } } } },
|
|
2540
|
+
* executor: async ({ city }) => fetchWeather(city),
|
|
2541
|
+
* }],
|
|
2542
|
+
* onData: (chunk) => process.stdout.write(chunk),
|
|
2543
|
+
* });
|
|
2544
|
+
* ```
|
|
2545
|
+
*/
|
|
2519
2546
|
declare function runToolLoop(options: RunToolLoopOptions): Promise<RunToolLoopResult>;
|
|
2520
2547
|
|
|
2521
2548
|
/**
|
|
@@ -8146,6 +8173,15 @@ interface TopicExtractionInput {
|
|
|
8146
8173
|
*/
|
|
8147
8174
|
interface TopicExtractOptions extends PortalLlmAuth {
|
|
8148
8175
|
baseUrl?: string;
|
|
8176
|
+
/**
|
|
8177
|
+
* Optional per-call request path override, forwarded to
|
|
8178
|
+
* {@link callPortalJsonCompletion}. When set, topic extraction POSTs to
|
|
8179
|
+
* `baseUrl + endpointOverride` instead of the default
|
|
8180
|
+
* `/api/v1/chat/completions` — path only, body unchanged. Lets callers route
|
|
8181
|
+
* this internal-utility pass to a dedicated endpoint. Invalid values throw at
|
|
8182
|
+
* call time (see {@link validateEndpointOverride}).
|
|
8183
|
+
*/
|
|
8184
|
+
endpointOverride?: string;
|
|
8149
8185
|
/** Defaults to {@link DEFAULT_EXTRACTION_MODEL} — the sanctioned extraction
|
|
8150
8186
|
* model. Don't point this at a second model without an eval. */
|
|
8151
8187
|
model?: string;
|
package/dist/server/index.d.ts
CHANGED
|
@@ -2516,6 +2516,33 @@ type StreamingTransportResult = {
|
|
|
2516
2516
|
* transport both honor this contract.
|
|
2517
2517
|
*/
|
|
2518
2518
|
type StreamingTransport = (options: StreamingTransportOptions) => StreamingTransportResult;
|
|
2519
|
+
/**
|
|
2520
|
+
* Framework-agnostic tool execution loop.
|
|
2521
|
+
*
|
|
2522
|
+
* Sends a streaming completion request, auto-executes tools that have executors,
|
|
2523
|
+
* feeds results back to the model, and repeats until the model stops emitting
|
|
2524
|
+
* tool calls or hits the iteration limit.
|
|
2525
|
+
*
|
|
2526
|
+
* This is the same loop that powers `useChat` in the React SDK, extracted so
|
|
2527
|
+
* it can be used from Node.js servers, CLI tools, and background workers.
|
|
2528
|
+
*
|
|
2529
|
+
* @example
|
|
2530
|
+
* ```ts
|
|
2531
|
+
* import { runToolLoop } from "@anuma/sdk/server";
|
|
2532
|
+
*
|
|
2533
|
+
* const result = await runToolLoop({
|
|
2534
|
+
* messages: [{ role: "user", content: [{ type: "text", text: "What's the weather?" }] }],
|
|
2535
|
+
* model: "fireworks/accounts/fireworks/models/kimi-k2p5",
|
|
2536
|
+
* token: "my-api-token",
|
|
2537
|
+
* tools: [{
|
|
2538
|
+
* type: "function",
|
|
2539
|
+
* function: { name: "get_weather", parameters: { type: "object", properties: { city: { type: "string" } } } },
|
|
2540
|
+
* executor: async ({ city }) => fetchWeather(city),
|
|
2541
|
+
* }],
|
|
2542
|
+
* onData: (chunk) => process.stdout.write(chunk),
|
|
2543
|
+
* });
|
|
2544
|
+
* ```
|
|
2545
|
+
*/
|
|
2519
2546
|
declare function runToolLoop(options: RunToolLoopOptions): Promise<RunToolLoopResult>;
|
|
2520
2547
|
|
|
2521
2548
|
/**
|
|
@@ -8146,6 +8173,15 @@ interface TopicExtractionInput {
|
|
|
8146
8173
|
*/
|
|
8147
8174
|
interface TopicExtractOptions extends PortalLlmAuth {
|
|
8148
8175
|
baseUrl?: string;
|
|
8176
|
+
/**
|
|
8177
|
+
* Optional per-call request path override, forwarded to
|
|
8178
|
+
* {@link callPortalJsonCompletion}. When set, topic extraction POSTs to
|
|
8179
|
+
* `baseUrl + endpointOverride` instead of the default
|
|
8180
|
+
* `/api/v1/chat/completions` — path only, body unchanged. Lets callers route
|
|
8181
|
+
* this internal-utility pass to a dedicated endpoint. Invalid values throw at
|
|
8182
|
+
* call time (see {@link validateEndpointOverride}).
|
|
8183
|
+
*/
|
|
8184
|
+
endpointOverride?: string;
|
|
8149
8185
|
/** Defaults to {@link DEFAULT_EXTRACTION_MODEL} — the sanctioned extraction
|
|
8150
8186
|
* model. Don't point this at a second model without an eval. */
|
|
8151
8187
|
model?: string;
|