@anuma/sdk 3.6.3 → 3.7.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.
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  callPortalJsonCompletion,
3
3
  getLogger
4
- } from "./chunk-DFVCS3QQ.mjs";
4
+ } from "./chunk-BOY27A2C.mjs";
5
5
  import {
6
6
  BASE_URL,
7
7
  createClientConfig
@@ -5363,7 +5363,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
5363
5363
  legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
5364
5364
  );
5365
5365
  }
5366
- const { recall: recall2 } = await import("./recall-VZHV7ILE.mjs");
5366
+ const { recall: recall2 } = await import("./recall-YVU7OSSJ.mjs");
5367
5367
  const result = await recall2(
5368
5368
  query,
5369
5369
  { vaultCtx, embeddingOptions, vaultCache: cache },
@@ -27,6 +27,24 @@ function getLogger() {
27
27
  return currentLogger;
28
28
  }
29
29
 
30
+ // src/lib/chat/endpointOverride.ts
31
+ function validateEndpointOverride(override) {
32
+ const trimmed = override.trim();
33
+ if (trimmed === "") {
34
+ return {
35
+ valid: false,
36
+ message: 'endpointOverride must be a non-empty, root-relative path (e.g. "/api/v1/utility/responses"); received an empty or whitespace-only string'
37
+ };
38
+ }
39
+ if (trimmed.startsWith("//") || trimmed.includes("://")) {
40
+ return {
41
+ valid: false,
42
+ message: `endpointOverride must be a root-relative path (e.g. "/api/v1/utility/responses"), not a protocol-relative or absolute URL; received "${trimmed}"`
43
+ };
44
+ }
45
+ return { valid: true, endpoint: trimmed.startsWith("/") ? trimmed : `/${trimmed}` };
46
+ }
47
+
30
48
  // src/lib/memory/portalLlm.ts
31
49
  function defaultBaseUrl() {
32
50
  return typeof process !== "undefined" && process.env?.ANUMA_PORTAL_BASE_URL || BASE_URL;
@@ -78,6 +96,14 @@ async function resolvePortalAuthHeaders(auth, tag) {
78
96
  }
79
97
  async function callPortalJsonCompletion(req) {
80
98
  const log = getLogger();
99
+ let endpoint = "/api/v1/chat/completions";
100
+ if (req.endpointOverride !== void 0) {
101
+ const overrideValidation = validateEndpointOverride(req.endpointOverride);
102
+ if (!overrideValidation.valid) {
103
+ throw new Error(overrideValidation.message);
104
+ }
105
+ endpoint = overrideValidation.endpoint;
106
+ }
81
107
  const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
82
108
  const startedAt = Date.now();
83
109
  const overBudget = () => req.totalTimeoutMs !== void 0 && Date.now() - startedAt >= req.totalTimeoutMs;
@@ -93,7 +119,7 @@ async function callPortalJsonCompletion(req) {
93
119
  Math.min(req.timeoutMs ?? 6e4, req.totalTimeoutMs - (Date.now() - startedAt))
94
120
  )
95
121
  } : req;
96
- const outcome = await attemptPortalJson(attemptReq);
122
+ const outcome = await attemptPortalJson(attemptReq, endpoint);
97
123
  if (outcome.kind === "ok") return outcome.value;
98
124
  if (outcome.kind === "terminal") {
99
125
  log.warn(`[${req.tag}] ${outcome.reason}`);
@@ -116,7 +142,7 @@ async function callPortalJsonCompletion(req) {
116
142
  }
117
143
  return null;
118
144
  }
119
- async function attemptPortalJson(req) {
145
+ async function attemptPortalJson(req, endpoint) {
120
146
  const baseUrl = req.baseUrl ?? defaultBaseUrl();
121
147
  const fetchImpl = req.fetchFn ?? fetch;
122
148
  const timeoutMs = req.timeoutMs ?? 6e4;
@@ -141,7 +167,7 @@ async function attemptPortalJson(req) {
141
167
  if (!supportsJsonObjectFormat) delete requestBody.response_format;
142
168
  let response;
143
169
  try {
144
- response = await fetchImpl(`${baseUrl}/api/v1/chat/completions`, {
170
+ response = await fetchImpl(`${baseUrl}${endpoint}`, {
145
171
  method: "POST",
146
172
  headers: { ...authHeaders, "Content-Type": "application/json" },
147
173
  body: JSON.stringify(requestBody),
@@ -239,6 +265,7 @@ export {
239
265
  noopLogger,
240
266
  setLogger,
241
267
  getLogger,
268
+ validateEndpointOverride,
242
269
  supportsResponseFormat,
243
270
  resolvePortalAuthHeaders,
244
271
  callPortalJsonCompletion,
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  callPortalJsonCompletion,
6
6
  getLogger
7
- } from "./chunk-DFVCS3QQ.mjs";
7
+ } from "./chunk-BOY27A2C.mjs";
8
8
  import "./chunk-GYKJOWEO.mjs";
9
9
 
10
10
  // src/lib/memory/consolidate.ts
@@ -3976,6 +3976,29 @@ var init_redactor = __esm({
3976
3976
  }
3977
3977
  });
3978
3978
 
3979
+ // src/lib/chat/endpointOverride.ts
3980
+ function validateEndpointOverride(override) {
3981
+ const trimmed = override.trim();
3982
+ if (trimmed === "") {
3983
+ return {
3984
+ valid: false,
3985
+ message: 'endpointOverride must be a non-empty, root-relative path (e.g. "/api/v1/utility/responses"); received an empty or whitespace-only string'
3986
+ };
3987
+ }
3988
+ if (trimmed.startsWith("//") || trimmed.includes("://")) {
3989
+ return {
3990
+ valid: false,
3991
+ message: `endpointOverride must be a root-relative path (e.g. "/api/v1/utility/responses"), not a protocol-relative or absolute URL; received "${trimmed}"`
3992
+ };
3993
+ }
3994
+ return { valid: true, endpoint: trimmed.startsWith("/") ? trimmed : `/${trimmed}` };
3995
+ }
3996
+ var init_endpointOverride = __esm({
3997
+ "src/lib/chat/endpointOverride.ts"() {
3998
+ "use strict";
3999
+ }
4000
+ });
4001
+
3979
4002
  // src/lib/db/entities/types.ts
3980
4003
  function normalizeEntityName(name) {
3981
4004
  return name.trim().toLowerCase();
@@ -5026,6 +5049,14 @@ async function resolvePortalAuthHeaders(auth, tag) {
5026
5049
  }
5027
5050
  async function callPortalJsonCompletion(req) {
5028
5051
  const log = getLogger();
5052
+ let endpoint = "/api/v1/chat/completions";
5053
+ if (req.endpointOverride !== void 0) {
5054
+ const overrideValidation = validateEndpointOverride(req.endpointOverride);
5055
+ if (!overrideValidation.valid) {
5056
+ throw new Error(overrideValidation.message);
5057
+ }
5058
+ endpoint = overrideValidation.endpoint;
5059
+ }
5029
5060
  const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
5030
5061
  const startedAt = Date.now();
5031
5062
  const overBudget = () => req.totalTimeoutMs !== void 0 && Date.now() - startedAt >= req.totalTimeoutMs;
@@ -5041,7 +5072,7 @@ async function callPortalJsonCompletion(req) {
5041
5072
  Math.min(req.timeoutMs ?? 6e4, req.totalTimeoutMs - (Date.now() - startedAt))
5042
5073
  )
5043
5074
  } : req;
5044
- const outcome = await attemptPortalJson(attemptReq);
5075
+ const outcome = await attemptPortalJson(attemptReq, endpoint);
5045
5076
  if (outcome.kind === "ok") return outcome.value;
5046
5077
  if (outcome.kind === "terminal") {
5047
5078
  log.warn(`[${req.tag}] ${outcome.reason}`);
@@ -5064,7 +5095,7 @@ async function callPortalJsonCompletion(req) {
5064
5095
  }
5065
5096
  return null;
5066
5097
  }
5067
- async function attemptPortalJson(req) {
5098
+ async function attemptPortalJson(req, endpoint) {
5068
5099
  const baseUrl = req.baseUrl ?? defaultBaseUrl();
5069
5100
  const fetchImpl = req.fetchFn ?? fetch;
5070
5101
  const timeoutMs = req.timeoutMs ?? 6e4;
@@ -5089,7 +5120,7 @@ async function attemptPortalJson(req) {
5089
5120
  if (!supportsJsonObjectFormat) delete requestBody.response_format;
5090
5121
  let response;
5091
5122
  try {
5092
- response = await fetchImpl(`${baseUrl}/api/v1/chat/completions`, {
5123
+ response = await fetchImpl(`${baseUrl}${endpoint}`, {
5093
5124
  method: "POST",
5094
5125
  headers: { ...authHeaders, "Content-Type": "application/json" },
5095
5126
  body: JSON.stringify(requestBody),
@@ -5186,6 +5217,7 @@ var init_portalLlm = __esm({
5186
5217
  "src/lib/memory/portalLlm.ts"() {
5187
5218
  "use strict";
5188
5219
  init_clientConfig();
5220
+ init_endpointOverride();
5189
5221
  init_logger();
5190
5222
  RESPONSE_FORMAT_OK = /* @__PURE__ */ new Set(["openai", "inclusionai", "deepseek"]);
5191
5223
  RESPONSE_SCHEMA_OK = /* @__PURE__ */ new Set(["openai"]);
@@ -8027,6 +8059,7 @@ init_serverSentEvents_gen();
8027
8059
  init_clientConfig();
8028
8060
  init_embeddings();
8029
8061
  init_redactor();
8062
+ init_endpointOverride();
8030
8063
 
8031
8064
  // src/lib/chat/runHooks.ts
8032
8065
  function composeHooks(hooks) {
@@ -10206,22 +10239,6 @@ function linkAbortSignals(a, b) {
10206
10239
  }
10207
10240
  };
10208
10241
  }
10209
- function validateEndpointOverride(override) {
10210
- const trimmed = override.trim();
10211
- if (trimmed === "") {
10212
- return {
10213
- valid: false,
10214
- message: 'endpointOverride must be a non-empty, root-relative path (e.g. "/api/v1/utility/responses"); received an empty or whitespace-only string'
10215
- };
10216
- }
10217
- if (trimmed.startsWith("//") || trimmed.includes("://")) {
10218
- return {
10219
- valid: false,
10220
- message: `endpointOverride must be a root-relative path (e.g. "/api/v1/utility/responses"), not a protocol-relative or absolute URL; received "${trimmed}"`
10221
- };
10222
- }
10223
- return { valid: true, endpoint: trimmed.startsWith("/") ? trimmed : `/${trimmed}` };
10224
- }
10225
10242
  async function runToolLoop(options) {
10226
10243
  const {
10227
10244
  model,
@@ -15991,6 +16008,9 @@ When a memory refers to one of these, reuse the EXACT existing name (same spelli
15991
16008
  ...options.apiKey !== void 0 && { apiKey: options.apiKey },
15992
16009
  ...options.getToken !== void 0 && { getToken: options.getToken },
15993
16010
  ...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
16011
+ ...options.endpointOverride !== void 0 && {
16012
+ endpointOverride: options.endpointOverride
16013
+ },
15994
16014
  model: options.model ?? DEFAULT_EXTRACTION_MODEL,
15995
16015
  systemPrompt: SYSTEM_PROMPT6,
15996
16016
  userMessage: `${vocabularyNote}Memories:
@@ -7456,6 +7456,15 @@ interface TopicExtractionInput {
7456
7456
  */
7457
7457
  interface TopicExtractOptions extends PortalLlmAuth {
7458
7458
  baseUrl?: string;
7459
+ /**
7460
+ * Optional per-call request path override, forwarded to
7461
+ * {@link callPortalJsonCompletion}. When set, topic extraction POSTs to
7462
+ * `baseUrl + endpointOverride` instead of the default
7463
+ * `/api/v1/chat/completions` — path only, body unchanged. Lets callers route
7464
+ * this internal-utility pass to a dedicated endpoint. Invalid values throw at
7465
+ * call time (see {@link validateEndpointOverride}).
7466
+ */
7467
+ endpointOverride?: string;
7459
7468
  /** Defaults to {@link DEFAULT_EXTRACTION_MODEL} — the sanctioned extraction
7460
7469
  * model. Don't point this at a second model without an eval. */
7461
7470
  model?: string;
@@ -7456,6 +7456,15 @@ interface TopicExtractionInput {
7456
7456
  */
7457
7457
  interface TopicExtractOptions extends PortalLlmAuth {
7458
7458
  baseUrl?: string;
7459
+ /**
7460
+ * Optional per-call request path override, forwarded to
7461
+ * {@link callPortalJsonCompletion}. When set, topic extraction POSTs to
7462
+ * `baseUrl + endpointOverride` instead of the default
7463
+ * `/api/v1/chat/completions` — path only, body unchanged. Lets callers route
7464
+ * this internal-utility pass to a dedicated endpoint. Invalid values throw at
7465
+ * call time (see {@link validateEndpointOverride}).
7466
+ */
7467
+ endpointOverride?: string;
7459
7468
  /** Defaults to {@link DEFAULT_EXTRACTION_MODEL} — the sanctioned extraction
7460
7469
  * model. Don't point this at a second model without an eval. */
7461
7470
  model?: string;
@@ -108,7 +108,7 @@ import {
108
108
  upsertMessageOp,
109
109
  useEncryption,
110
110
  vaultMemoryToStored
111
- } from "./chunk-FKACNV6X.mjs";
111
+ } from "./chunk-AAB7OG7Q.mjs";
112
112
  import {
113
113
  PII_PATTERNS,
114
114
  PiiRedactor,
@@ -124,8 +124,9 @@ import {
124
124
  noopLogger,
125
125
  resolvePortalAuthHeaders,
126
126
  setLogger,
127
- supportsResponseFormat
128
- } from "./chunk-DFVCS3QQ.mjs";
127
+ supportsResponseFormat,
128
+ validateEndpointOverride
129
+ } from "./chunk-BOY27A2C.mjs";
129
130
  import {
130
131
  BASE_URL,
131
132
  MCP_R2_DOMAIN,
@@ -2473,22 +2474,6 @@ function linkAbortSignals(a, b) {
2473
2474
  }
2474
2475
  };
2475
2476
  }
2476
- function validateEndpointOverride(override) {
2477
- const trimmed = override.trim();
2478
- if (trimmed === "") {
2479
- return {
2480
- valid: false,
2481
- message: 'endpointOverride must be a non-empty, root-relative path (e.g. "/api/v1/utility/responses"); received an empty or whitespace-only string'
2482
- };
2483
- }
2484
- if (trimmed.startsWith("//") || trimmed.includes("://")) {
2485
- return {
2486
- valid: false,
2487
- message: `endpointOverride must be a root-relative path (e.g. "/api/v1/utility/responses"), not a protocol-relative or absolute URL; received "${trimmed}"`
2488
- };
2489
- }
2490
- return { valid: true, endpoint: trimmed.startsWith("/") ? trimmed : `/${trimmed}` };
2491
- }
2492
2477
  async function runToolLoop(options) {
2493
2478
  const {
2494
2479
  model,
@@ -6430,7 +6415,7 @@ async function tryConsolidate(trimmed, ctx, options) {
6430
6415
  content: m.content,
6431
6416
  similarity: m.similarity
6432
6417
  }));
6433
- const { consolidateMemory: doConsolidate } = await import("./consolidate-3QQPUWD6.mjs");
6418
+ const { consolidateMemory: doConsolidate } = await import("./consolidate-J5PHQKKY.mjs");
6434
6419
  const decision = await doConsolidate(trimmed, candidates, consolidateOptions);
6435
6420
  if (decision.action === "create") return null;
6436
6421
  if (decision.action === "supersede" && decision.targetId && decision.content) {
@@ -8173,6 +8158,9 @@ When a memory refers to one of these, reuse the EXACT existing name (same spelli
8173
8158
  ...options.apiKey !== void 0 && { apiKey: options.apiKey },
8174
8159
  ...options.getToken !== void 0 && { getToken: options.getToken },
8175
8160
  ...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
8161
+ ...options.endpointOverride !== void 0 && {
8162
+ endpointOverride: options.endpointOverride
8163
+ },
8176
8164
  model: options.model ?? DEFAULT_EXTRACTION_MODEL,
8177
8165
  systemPrompt: SYSTEM_PROMPT4,
8178
8166
  userMessage: `${vocabularyNote}Memories:
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  recall
3
- } from "./chunk-ZGMHRWOR.mjs";
4
- import "./chunk-DFVCS3QQ.mjs";
3
+ } from "./chunk-AAB7OG7Q.mjs";
4
+ import "./chunk-BOY27A2C.mjs";
5
5
  import "./chunk-GYKJOWEO.mjs";
6
6
  export {
7
7
  recall
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  callPortalJsonCompletion,
3
3
  getLogger
4
- } from "./chunk-DFVCS3QQ.mjs";
4
+ } from "./chunk-BOY27A2C.mjs";
5
5
  import {
6
6
  BASE_URL,
7
7
  createClientConfig
@@ -5641,7 +5641,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
5641
5641
  legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
5642
5642
  );
5643
5643
  }
5644
- const { recall: recall2 } = await import("./recall-JOLS3V4B.mjs");
5644
+ const { recall: recall2 } = await import("./recall-Z7BWJ67X.mjs");
5645
5645
  const result = await recall2(
5646
5646
  query,
5647
5647
  { vaultCtx, embeddingOptions, vaultCache: cache },
@@ -27,6 +27,24 @@ function getLogger() {
27
27
  return currentLogger;
28
28
  }
29
29
 
30
+ // src/lib/chat/endpointOverride.ts
31
+ function validateEndpointOverride(override) {
32
+ const trimmed = override.trim();
33
+ if (trimmed === "") {
34
+ return {
35
+ valid: false,
36
+ message: 'endpointOverride must be a non-empty, root-relative path (e.g. "/api/v1/utility/responses"); received an empty or whitespace-only string'
37
+ };
38
+ }
39
+ if (trimmed.startsWith("//") || trimmed.includes("://")) {
40
+ return {
41
+ valid: false,
42
+ message: `endpointOverride must be a root-relative path (e.g. "/api/v1/utility/responses"), not a protocol-relative or absolute URL; received "${trimmed}"`
43
+ };
44
+ }
45
+ return { valid: true, endpoint: trimmed.startsWith("/") ? trimmed : `/${trimmed}` };
46
+ }
47
+
30
48
  // src/lib/memory/portalLlm.ts
31
49
  function defaultBaseUrl() {
32
50
  return typeof process !== "undefined" && process.env?.ANUMA_PORTAL_BASE_URL || BASE_URL;
@@ -78,6 +96,14 @@ async function resolvePortalAuthHeaders(auth, tag) {
78
96
  }
79
97
  async function callPortalJsonCompletion(req) {
80
98
  const log = getLogger();
99
+ let endpoint = "/api/v1/chat/completions";
100
+ if (req.endpointOverride !== void 0) {
101
+ const overrideValidation = validateEndpointOverride(req.endpointOverride);
102
+ if (!overrideValidation.valid) {
103
+ throw new Error(overrideValidation.message);
104
+ }
105
+ endpoint = overrideValidation.endpoint;
106
+ }
81
107
  const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
82
108
  const startedAt = Date.now();
83
109
  const overBudget = () => req.totalTimeoutMs !== void 0 && Date.now() - startedAt >= req.totalTimeoutMs;
@@ -93,7 +119,7 @@ async function callPortalJsonCompletion(req) {
93
119
  Math.min(req.timeoutMs ?? 6e4, req.totalTimeoutMs - (Date.now() - startedAt))
94
120
  )
95
121
  } : req;
96
- const outcome = await attemptPortalJson(attemptReq);
122
+ const outcome = await attemptPortalJson(attemptReq, endpoint);
97
123
  if (outcome.kind === "ok") return outcome.value;
98
124
  if (outcome.kind === "terminal") {
99
125
  log.warn(`[${req.tag}] ${outcome.reason}`);
@@ -116,7 +142,7 @@ async function callPortalJsonCompletion(req) {
116
142
  }
117
143
  return null;
118
144
  }
119
- async function attemptPortalJson(req) {
145
+ async function attemptPortalJson(req, endpoint) {
120
146
  const baseUrl = req.baseUrl ?? defaultBaseUrl();
121
147
  const fetchImpl = req.fetchFn ?? fetch;
122
148
  const timeoutMs = req.timeoutMs ?? 6e4;
@@ -141,7 +167,7 @@ async function attemptPortalJson(req) {
141
167
  if (!supportsJsonObjectFormat) delete requestBody.response_format;
142
168
  let response;
143
169
  try {
144
- response = await fetchImpl(`${baseUrl}/api/v1/chat/completions`, {
170
+ response = await fetchImpl(`${baseUrl}${endpoint}`, {
145
171
  method: "POST",
146
172
  headers: { ...authHeaders, "Content-Type": "application/json" },
147
173
  body: JSON.stringify(requestBody),
@@ -239,6 +265,7 @@ export {
239
265
  noopLogger,
240
266
  setLogger,
241
267
  getLogger,
268
+ validateEndpointOverride,
242
269
  supportsResponseFormat,
243
270
  resolvePortalAuthHeaders,
244
271
  callPortalJsonCompletion,
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  callPortalJsonCompletion,
6
6
  getLogger
7
- } from "./chunk-DFVCS3QQ.mjs";
7
+ } from "./chunk-BOY27A2C.mjs";
8
8
  import "./chunk-GYKJOWEO.mjs";
9
9
 
10
10
  // src/lib/memory/consolidate.ts
@@ -4175,6 +4175,29 @@ var init_redactor = __esm({
4175
4175
  }
4176
4176
  });
4177
4177
 
4178
+ // src/lib/chat/endpointOverride.ts
4179
+ function validateEndpointOverride(override) {
4180
+ const trimmed = override.trim();
4181
+ if (trimmed === "") {
4182
+ return {
4183
+ valid: false,
4184
+ message: 'endpointOverride must be a non-empty, root-relative path (e.g. "/api/v1/utility/responses"); received an empty or whitespace-only string'
4185
+ };
4186
+ }
4187
+ if (trimmed.startsWith("//") || trimmed.includes("://")) {
4188
+ return {
4189
+ valid: false,
4190
+ message: `endpointOverride must be a root-relative path (e.g. "/api/v1/utility/responses"), not a protocol-relative or absolute URL; received "${trimmed}"`
4191
+ };
4192
+ }
4193
+ return { valid: true, endpoint: trimmed.startsWith("/") ? trimmed : `/${trimmed}` };
4194
+ }
4195
+ var init_endpointOverride = __esm({
4196
+ "src/lib/chat/endpointOverride.ts"() {
4197
+ "use strict";
4198
+ }
4199
+ });
4200
+
4178
4201
  // src/lib/db/entities/types.ts
4179
4202
  function normalizeEntityName(name) {
4180
4203
  return name.trim().toLowerCase();
@@ -5304,6 +5327,14 @@ async function resolvePortalAuthHeaders(auth, tag) {
5304
5327
  }
5305
5328
  async function callPortalJsonCompletion(req) {
5306
5329
  const log = getLogger();
5330
+ let endpoint = "/api/v1/chat/completions";
5331
+ if (req.endpointOverride !== void 0) {
5332
+ const overrideValidation = validateEndpointOverride(req.endpointOverride);
5333
+ if (!overrideValidation.valid) {
5334
+ throw new Error(overrideValidation.message);
5335
+ }
5336
+ endpoint = overrideValidation.endpoint;
5337
+ }
5307
5338
  const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
5308
5339
  const startedAt = Date.now();
5309
5340
  const overBudget = () => req.totalTimeoutMs !== void 0 && Date.now() - startedAt >= req.totalTimeoutMs;
@@ -5319,7 +5350,7 @@ async function callPortalJsonCompletion(req) {
5319
5350
  Math.min(req.timeoutMs ?? 6e4, req.totalTimeoutMs - (Date.now() - startedAt))
5320
5351
  )
5321
5352
  } : req;
5322
- const outcome = await attemptPortalJson(attemptReq);
5353
+ const outcome = await attemptPortalJson(attemptReq, endpoint);
5323
5354
  if (outcome.kind === "ok") return outcome.value;
5324
5355
  if (outcome.kind === "terminal") {
5325
5356
  log.warn(`[${req.tag}] ${outcome.reason}`);
@@ -5342,7 +5373,7 @@ async function callPortalJsonCompletion(req) {
5342
5373
  }
5343
5374
  return null;
5344
5375
  }
5345
- async function attemptPortalJson(req) {
5376
+ async function attemptPortalJson(req, endpoint) {
5346
5377
  const baseUrl = req.baseUrl ?? defaultBaseUrl();
5347
5378
  const fetchImpl = req.fetchFn ?? fetch;
5348
5379
  const timeoutMs = req.timeoutMs ?? 6e4;
@@ -5367,7 +5398,7 @@ async function attemptPortalJson(req) {
5367
5398
  if (!supportsJsonObjectFormat) delete requestBody.response_format;
5368
5399
  let response;
5369
5400
  try {
5370
- response = await fetchImpl(`${baseUrl}/api/v1/chat/completions`, {
5401
+ response = await fetchImpl(`${baseUrl}${endpoint}`, {
5371
5402
  method: "POST",
5372
5403
  headers: { ...authHeaders, "Content-Type": "application/json" },
5373
5404
  body: JSON.stringify(requestBody),
@@ -5464,6 +5495,7 @@ var init_portalLlm = __esm({
5464
5495
  "src/lib/memory/portalLlm.ts"() {
5465
5496
  "use strict";
5466
5497
  init_clientConfig();
5498
+ init_endpointOverride();
5467
5499
  init_logger();
5468
5500
  RESPONSE_FORMAT_OK = /* @__PURE__ */ new Set(["openai", "inclusionai", "deepseek"]);
5469
5501
  RESPONSE_SCHEMA_OK = /* @__PURE__ */ new Set(["openai"]);
@@ -8378,6 +8410,7 @@ init_serverSentEvents_gen();
8378
8410
  init_clientConfig();
8379
8411
  init_embeddings();
8380
8412
  init_redactor();
8413
+ init_endpointOverride();
8381
8414
 
8382
8415
  // src/lib/chat/runHooks.ts
8383
8416
  function composeHooks(hooks) {
@@ -10557,22 +10590,6 @@ function linkAbortSignals(a, b) {
10557
10590
  }
10558
10591
  };
10559
10592
  }
10560
- function validateEndpointOverride(override) {
10561
- const trimmed = override.trim();
10562
- if (trimmed === "") {
10563
- return {
10564
- valid: false,
10565
- message: 'endpointOverride must be a non-empty, root-relative path (e.g. "/api/v1/utility/responses"); received an empty or whitespace-only string'
10566
- };
10567
- }
10568
- if (trimmed.startsWith("//") || trimmed.includes("://")) {
10569
- return {
10570
- valid: false,
10571
- message: `endpointOverride must be a root-relative path (e.g. "/api/v1/utility/responses"), not a protocol-relative or absolute URL; received "${trimmed}"`
10572
- };
10573
- }
10574
- return { valid: true, endpoint: trimmed.startsWith("/") ? trimmed : `/${trimmed}` };
10575
- }
10576
10593
  async function runToolLoop(options) {
10577
10594
  const {
10578
10595
  model,
@@ -17281,6 +17298,9 @@ When a memory refers to one of these, reuse the EXACT existing name (same spelli
17281
17298
  ...options.apiKey !== void 0 && { apiKey: options.apiKey },
17282
17299
  ...options.getToken !== void 0 && { getToken: options.getToken },
17283
17300
  ...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
17301
+ ...options.endpointOverride !== void 0 && {
17302
+ endpointOverride: options.endpointOverride
17303
+ },
17284
17304
  model: options.model ?? DEFAULT_EXTRACTION_MODEL,
17285
17305
  systemPrompt: SYSTEM_PROMPT6,
17286
17306
  userMessage: `${vocabularyNote}Memories:
@@ -8607,6 +8607,15 @@ interface TopicExtractionInput {
8607
8607
  */
8608
8608
  interface TopicExtractOptions extends PortalLlmAuth {
8609
8609
  baseUrl?: string;
8610
+ /**
8611
+ * Optional per-call request path override, forwarded to
8612
+ * {@link callPortalJsonCompletion}. When set, topic extraction POSTs to
8613
+ * `baseUrl + endpointOverride` instead of the default
8614
+ * `/api/v1/chat/completions` — path only, body unchanged. Lets callers route
8615
+ * this internal-utility pass to a dedicated endpoint. Invalid values throw at
8616
+ * call time (see {@link validateEndpointOverride}).
8617
+ */
8618
+ endpointOverride?: string;
8610
8619
  /** Defaults to {@link DEFAULT_EXTRACTION_MODEL} — the sanctioned extraction
8611
8620
  * model. Don't point this at a second model without an eval. */
8612
8621
  model?: string;
@@ -8607,6 +8607,15 @@ interface TopicExtractionInput {
8607
8607
  */
8608
8608
  interface TopicExtractOptions extends PortalLlmAuth {
8609
8609
  baseUrl?: string;
8610
+ /**
8611
+ * Optional per-call request path override, forwarded to
8612
+ * {@link callPortalJsonCompletion}. When set, topic extraction POSTs to
8613
+ * `baseUrl + endpointOverride` instead of the default
8614
+ * `/api/v1/chat/completions` — path only, body unchanged. Lets callers route
8615
+ * this internal-utility pass to a dedicated endpoint. Invalid values throw at
8616
+ * call time (see {@link validateEndpointOverride}).
8617
+ */
8618
+ endpointOverride?: string;
8610
8619
  /** Defaults to {@link DEFAULT_EXTRACTION_MODEL} — the sanctioned extraction
8611
8620
  * model. Don't point this at a second model without an eval. */
8612
8621
  model?: string;
@@ -149,7 +149,7 @@ import {
149
149
  updateVaultMemoryOp,
150
150
  useEncryption,
151
151
  vaultMemoryToStored
152
- } from "./chunk-ZGMHRWOR.mjs";
152
+ } from "./chunk-3VPEZDYL.mjs";
153
153
  import {
154
154
  PiiRedactor,
155
155
  createStreamingDeAnonymizer,
@@ -164,8 +164,9 @@ import {
164
164
  noopLogger,
165
165
  resolvePortalAuthHeaders,
166
166
  setLogger,
167
- supportsResponseFormat
168
- } from "./chunk-DFVCS3QQ.mjs";
167
+ supportsResponseFormat,
168
+ validateEndpointOverride
169
+ } from "./chunk-BOY27A2C.mjs";
169
170
  import {
170
171
  BASE_URL,
171
172
  MCP_R2_DOMAIN,
@@ -2346,22 +2347,6 @@ function linkAbortSignals(a, b) {
2346
2347
  }
2347
2348
  };
2348
2349
  }
2349
- function validateEndpointOverride(override) {
2350
- const trimmed = override.trim();
2351
- if (trimmed === "") {
2352
- return {
2353
- valid: false,
2354
- message: 'endpointOverride must be a non-empty, root-relative path (e.g. "/api/v1/utility/responses"); received an empty or whitespace-only string'
2355
- };
2356
- }
2357
- if (trimmed.startsWith("//") || trimmed.includes("://")) {
2358
- return {
2359
- valid: false,
2360
- message: `endpointOverride must be a root-relative path (e.g. "/api/v1/utility/responses"), not a protocol-relative or absolute URL; received "${trimmed}"`
2361
- };
2362
- }
2363
- return { valid: true, endpoint: trimmed.startsWith("/") ? trimmed : `/${trimmed}` };
2364
- }
2365
2350
  async function runToolLoop(options) {
2366
2351
  const {
2367
2352
  model,
@@ -7243,7 +7228,7 @@ async function tryConsolidate(trimmed, ctx, options) {
7243
7228
  content: m.content,
7244
7229
  similarity: m.similarity
7245
7230
  }));
7246
- const { consolidateMemory: doConsolidate } = await import("./consolidate-3MXZV3G7.mjs");
7231
+ const { consolidateMemory: doConsolidate } = await import("./consolidate-PWJCAPZA.mjs");
7247
7232
  const decision = await doConsolidate(trimmed, candidates, consolidateOptions);
7248
7233
  if (decision.action === "create") return null;
7249
7234
  if (decision.action === "supersede" && decision.targetId && decision.content) {
@@ -8986,6 +8971,9 @@ When a memory refers to one of these, reuse the EXACT existing name (same spelli
8986
8971
  ...options.apiKey !== void 0 && { apiKey: options.apiKey },
8987
8972
  ...options.getToken !== void 0 && { getToken: options.getToken },
8988
8973
  ...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
8974
+ ...options.endpointOverride !== void 0 && {
8975
+ endpointOverride: options.endpointOverride
8976
+ },
8989
8977
  model: options.model ?? DEFAULT_EXTRACTION_MODEL,
8990
8978
  systemPrompt: SYSTEM_PROMPT4,
8991
8979
  userMessage: `${vocabularyNote}Memories:
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  recall
3
- } from "./chunk-FKACNV6X.mjs";
4
- import "./chunk-DFVCS3QQ.mjs";
3
+ } from "./chunk-3VPEZDYL.mjs";
4
+ import "./chunk-BOY27A2C.mjs";
5
5
  import "./chunk-GYKJOWEO.mjs";
6
6
  export {
7
7
  recall
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  callPortalJsonCompletion,
3
3
  getLogger
4
- } from "./chunk-AHJT66EO.mjs";
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-UTVH2XPK.mjs");
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}/api/v1/chat/completions`, {
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-AHJT66EO.mjs";
7
+ } from "./chunk-MIXEASUP.mjs";
8
8
  import "./chunk-3RPGXXPZ.mjs";
9
9
 
10
10
  // src/lib/memory/consolidate.ts
@@ -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}/api/v1/chat/completions`, {
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"]);
@@ -29132,6 +29164,9 @@ When a memory refers to one of these, reuse the EXACT existing name (same spelli
29132
29164
  ...options.apiKey !== void 0 && { apiKey: options.apiKey },
29133
29165
  ...options.getToken !== void 0 && { getToken: options.getToken },
29134
29166
  ...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
29167
+ ...options.endpointOverride !== void 0 && {
29168
+ endpointOverride: options.endpointOverride
29169
+ },
29135
29170
  model: options.model ?? DEFAULT_EXTRACTION_MODEL,
29136
29171
  systemPrompt: SYSTEM_PROMPT6,
29137
29172
  userMessage: `${vocabularyNote}Memories:
@@ -31283,6 +31318,7 @@ init_serverSentEvents_gen();
31283
31318
  init_clientConfig();
31284
31319
  init_embeddings();
31285
31320
  init_redactor();
31321
+ init_endpointOverride();
31286
31322
 
31287
31323
  // src/lib/chat/runHooks.ts
31288
31324
  function composeHooks(hooks) {
@@ -33433,22 +33469,6 @@ function linkAbortSignals(a, b) {
33433
33469
  }
33434
33470
  };
33435
33471
  }
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
33472
  async function runToolLoop(options) {
33453
33473
  const {
33454
33474
  model,
@@ -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;
@@ -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;
@@ -125,7 +125,7 @@ import {
125
125
  updateVaultMemoryOp,
126
126
  upsertMessageOp,
127
127
  vaultMemoryToStored
128
- } from "./chunk-66UWDXS3.mjs";
128
+ } from "./chunk-LSKFJNLF.mjs";
129
129
  import {
130
130
  createStreamingDeAnonymizer,
131
131
  resolvePiiRedactor
@@ -135,8 +135,9 @@ import {
135
135
  extractJsonCandidate,
136
136
  getLogger,
137
137
  resolvePortalAuthHeaders,
138
- supportsResponseFormat
139
- } from "./chunk-AHJT66EO.mjs";
138
+ supportsResponseFormat,
139
+ validateEndpointOverride
140
+ } from "./chunk-MIXEASUP.mjs";
140
141
  import {
141
142
  BASE_URL,
142
143
  __commonJS,
@@ -5315,7 +5316,7 @@ async function tryConsolidate(trimmed, ctx, options) {
5315
5316
  content: m.content,
5316
5317
  similarity: m.similarity
5317
5318
  }));
5318
- const { consolidateMemory: doConsolidate } = await import("./consolidate-CN2GQV4D.mjs");
5319
+ const { consolidateMemory: doConsolidate } = await import("./consolidate-PCHO3D3G.mjs");
5319
5320
  const decision = await doConsolidate(trimmed, candidates, consolidateOptions);
5320
5321
  if (decision.action === "create") return null;
5321
5322
  if (decision.action === "supersede" && decision.targetId && decision.content) {
@@ -7058,6 +7059,9 @@ When a memory refers to one of these, reuse the EXACT existing name (same spelli
7058
7059
  ...options.apiKey !== void 0 && { apiKey: options.apiKey },
7059
7060
  ...options.getToken !== void 0 && { getToken: options.getToken },
7060
7061
  ...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
7062
+ ...options.endpointOverride !== void 0 && {
7063
+ endpointOverride: options.endpointOverride
7064
+ },
7061
7065
  model: options.model ?? DEFAULT_EXTRACTION_MODEL,
7062
7066
  systemPrompt: SYSTEM_PROMPT4,
7063
7067
  userMessage: `${vocabularyNote}Memories:
@@ -11326,22 +11330,6 @@ function linkAbortSignals(a, b) {
11326
11330
  }
11327
11331
  };
11328
11332
  }
11329
- function validateEndpointOverride(override) {
11330
- const trimmed = override.trim();
11331
- if (trimmed === "") {
11332
- return {
11333
- valid: false,
11334
- message: 'endpointOverride must be a non-empty, root-relative path (e.g. "/api/v1/utility/responses"); received an empty or whitespace-only string'
11335
- };
11336
- }
11337
- if (trimmed.startsWith("//") || trimmed.includes("://")) {
11338
- return {
11339
- valid: false,
11340
- message: `endpointOverride must be a root-relative path (e.g. "/api/v1/utility/responses"), not a protocol-relative or absolute URL; received "${trimmed}"`
11341
- };
11342
- }
11343
- return { valid: true, endpoint: trimmed.startsWith("/") ? trimmed : `/${trimmed}` };
11344
- }
11345
11333
  async function runToolLoop(options) {
11346
11334
  const {
11347
11335
  model,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  recall
3
- } from "./chunk-66UWDXS3.mjs";
4
- import "./chunk-AHJT66EO.mjs";
3
+ } from "./chunk-LSKFJNLF.mjs";
4
+ import "./chunk-MIXEASUP.mjs";
5
5
  import "./chunk-3RPGXXPZ.mjs";
6
6
  export {
7
7
  recall
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anuma/sdk",
3
- "version": "3.6.3",
3
+ "version": "3.7.0",
4
4
  "description": "",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",