@anuma/sdk 6.14.2 → 6.15.1
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/client/index.cjs +13 -0
- package/dist/client/index.d.mts +187 -1
- package/dist/client/index.d.ts +187 -1
- package/dist/client/index.mjs +11 -0
- package/dist/expo/{chunk-O25LUKBK.mjs → chunk-4Z2X4UYQ.mjs} +73 -9
- package/dist/expo/{chunk-M4JSLFTQ.mjs → chunk-A2G6TRUK.mjs} +1 -1
- package/dist/expo/{chunk-JA7CDJCA.mjs → chunk-TNMPAE3V.mjs} +2 -2
- package/dist/{react/consolidate-LSDBMQDW.mjs → expo/consolidate-ZM5JNULQ.mjs} +2 -2
- package/dist/expo/index.cjs +183 -82
- package/dist/expo/index.mjs +118 -77
- package/dist/expo/{recall-JYVHWU6N.mjs → recall-FJQTIMYT.mjs} +2 -2
- package/dist/react/{chunk-O25LUKBK.mjs → chunk-4Z2X4UYQ.mjs} +73 -9
- package/dist/react/{chunk-2XLHV2XW.mjs → chunk-7X7BNMGS.mjs} +1 -1
- package/dist/react/{chunk-DNSPMVBY.mjs → chunk-YSL3J4K4.mjs} +2 -2
- package/dist/{expo/consolidate-S3KFA2WT.mjs → react/consolidate-7NMKF7UC.mjs} +2 -2
- package/dist/react/index.cjs +183 -82
- package/dist/react/index.mjs +118 -77
- package/dist/react/{recall-2BWBJWGG.mjs → recall-UVVZGRVF.mjs} +2 -2
- package/dist/server/{chunk-GP6YY6H5.mjs → chunk-4LPSEROP.mjs} +1 -1
- package/dist/server/{chunk-O7TB36P3.mjs → chunk-ARYSRI4Z.mjs} +2 -2
- package/dist/server/{chunk-7D3RI25K.mjs → chunk-BSCEZOIW.mjs} +73 -9
- package/dist/server/{consolidate-Z2JJP7LW.mjs → consolidate-MSAXASHL.mjs} +2 -2
- package/dist/server/index.cjs +183 -82
- package/dist/server/index.mjs +118 -77
- package/dist/server/{recall-VHU372MK.mjs → recall-OVSSDRYU.mjs} +2 -2
- package/package.json +2 -2
package/dist/react/index.cjs
CHANGED
|
@@ -6429,6 +6429,26 @@ function supportsResponseFormat(model, variant = "json_object") {
|
|
|
6429
6429
|
const allow = variant === "json_schema" ? RESPONSE_SCHEMA_OK : RESPONSE_FORMAT_OK;
|
|
6430
6430
|
return model.split("/").some((seg) => allow.has(seg));
|
|
6431
6431
|
}
|
|
6432
|
+
function requiresResponsesTransport(model) {
|
|
6433
|
+
return model.split("/").some((seg) => RESPONSES_ONLY_MODEL_PREFIXES.some((prefix) => seg.startsWith(prefix)));
|
|
6434
|
+
}
|
|
6435
|
+
function responsesExtra(extra) {
|
|
6436
|
+
if (!extra) return {};
|
|
6437
|
+
const out = {};
|
|
6438
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
6439
|
+
const target = CHAT_TO_RESPONSES_FIELDS[key] ?? key;
|
|
6440
|
+
if (target !== key && target in extra) continue;
|
|
6441
|
+
out[target] = value;
|
|
6442
|
+
}
|
|
6443
|
+
return out;
|
|
6444
|
+
}
|
|
6445
|
+
function assertTransportMatchesEndpoint(transport, endpoint) {
|
|
6446
|
+
const foreign = FOREIGN_ENDPOINT_SUFFIX[transport];
|
|
6447
|
+
if (!endpoint.endsWith(foreign)) return;
|
|
6448
|
+
throw new Error(
|
|
6449
|
+
`endpointOverride "${endpoint}" is the other transport's endpoint, but transport is "${transport}". The request body is built for the transport, so this sends the wrong shape and 400s without retry.`
|
|
6450
|
+
);
|
|
6451
|
+
}
|
|
6432
6452
|
function isRetryableStatus(status) {
|
|
6433
6453
|
return status >= 500 || RETRYABLE_HTTP.has(status);
|
|
6434
6454
|
}
|
|
@@ -6469,13 +6489,14 @@ async function resolvePortalAuthHeaders(auth, tag) {
|
|
|
6469
6489
|
}
|
|
6470
6490
|
async function callPortalJsonCompletion(req) {
|
|
6471
6491
|
const log = getLogger();
|
|
6472
|
-
let endpoint = "/api/v1/chat/completions";
|
|
6492
|
+
let endpoint = req.transport === "responses" ? "/api/v1/responses" : "/api/v1/chat/completions";
|
|
6473
6493
|
if (req.endpointOverride !== void 0) {
|
|
6474
6494
|
const overrideValidation = validateEndpointOverride(req.endpointOverride);
|
|
6475
6495
|
if (!overrideValidation.valid) {
|
|
6476
6496
|
throw new Error(overrideValidation.message);
|
|
6477
6497
|
}
|
|
6478
6498
|
endpoint = overrideValidation.endpoint;
|
|
6499
|
+
assertTransportMatchesEndpoint(req.transport ?? "chat", endpoint);
|
|
6479
6500
|
}
|
|
6480
6501
|
const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
|
|
6481
6502
|
const startedAt = Date.now();
|
|
@@ -6537,8 +6558,8 @@ async function attemptPortalJson(req, endpoint) {
|
|
|
6537
6558
|
const authHeaders = await resolvePortalAuthHeaders(req, req.tag);
|
|
6538
6559
|
if (authHeaders === null)
|
|
6539
6560
|
return { kind: "terminal", code: "auth-unavailable", reason: "auth unavailable (no token)" };
|
|
6540
|
-
const
|
|
6541
|
-
const prefill =
|
|
6561
|
+
const usesPrefill = req.transport !== "responses" && req.model.startsWith("anthropic/");
|
|
6562
|
+
const prefill = usesPrefill ? "{" : "";
|
|
6542
6563
|
const messages = [
|
|
6543
6564
|
// Every caller of this helper is a first-party BACKGROUND op (fact extraction,
|
|
6544
6565
|
// topic sweep, consolidation, classifiers, graph traversal, query
|
|
@@ -6557,13 +6578,34 @@ async function attemptPortalJson(req, endpoint) {
|
|
|
6557
6578
|
const supportsJsonObjectFormat = supportsResponseFormat(req.model);
|
|
6558
6579
|
const controller = new AbortController();
|
|
6559
6580
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
6560
|
-
const requestBody = {
|
|
6581
|
+
const requestBody = req.transport === "responses" ? {
|
|
6582
|
+
model: req.model,
|
|
6583
|
+
// Same system+user pair under the Responses-API field name. No prefill
|
|
6584
|
+
// entry to strip: `usesPrefill` is false on this transport, so it was
|
|
6585
|
+
// never pushed and the response-side restore is disarmed with it. An
|
|
6586
|
+
// earlier version pushed it and sliced it back off here, which left
|
|
6587
|
+
// `prefill` truthy and the restore still armed — the fix belonged at
|
|
6588
|
+
// the decision, not at the two symptoms.
|
|
6589
|
+
input: messages,
|
|
6590
|
+
...req.reasoning && { reasoning: req.reasoning },
|
|
6591
|
+
// NO response_format. The Responses API spells structured output
|
|
6592
|
+
// differently (`text.format`), and it is unverified against this
|
|
6593
|
+
// portal — so this transport relies on the same strict-JSON system
|
|
6594
|
+
// prompt plus `extractJsonCandidate` that every response_format-
|
|
6595
|
+
// rejecting model already relies on. Verified end to end on dev:
|
|
6596
|
+
// luna returns clean parseable JSON here without it. Add the field
|
|
6597
|
+
// only with a per-provider check, exactly as RESPONSE_FORMAT_OK was
|
|
6598
|
+
// earned.
|
|
6599
|
+
...responsesExtra(req.extra)
|
|
6600
|
+
} : {
|
|
6561
6601
|
model: req.model,
|
|
6562
6602
|
messages,
|
|
6563
6603
|
...supportsJsonObjectFormat && { response_format: { type: "json_object" } },
|
|
6564
6604
|
...req.extra
|
|
6565
6605
|
};
|
|
6566
|
-
if (!supportsJsonObjectFormat)
|
|
6606
|
+
if (req.transport === "responses" || !supportsJsonObjectFormat) {
|
|
6607
|
+
delete requestBody.response_format;
|
|
6608
|
+
}
|
|
6567
6609
|
let response;
|
|
6568
6610
|
try {
|
|
6569
6611
|
response = await fetchImpl(`${baseUrl}${endpoint}`, {
|
|
@@ -6693,13 +6735,15 @@ function logPortalUsage(body, tag) {
|
|
|
6693
6735
|
const root = asRecord(body);
|
|
6694
6736
|
if (!root) return;
|
|
6695
6737
|
const usage = asRecord(root.usage);
|
|
6696
|
-
const promptTokens = asCount(usage?.prompt_tokens);
|
|
6697
|
-
const completionTokens = asCount(usage?.completion_tokens);
|
|
6738
|
+
const promptTokens = asCount(usage?.prompt_tokens) ?? asCount(usage?.input_tokens);
|
|
6739
|
+
const completionTokens = asCount(usage?.completion_tokens) ?? asCount(usage?.output_tokens);
|
|
6698
6740
|
if (promptTokens === void 0 && completionTokens === void 0) return;
|
|
6699
|
-
const cachedTokens = asCount(asRecord(root.portal)?.cached_tokens) ?? asCount(asRecord(usage?.prompt_tokens_details)?.cached_tokens) ?? 0;
|
|
6741
|
+
const cachedTokens = asCount(asRecord(root.portal)?.cached_tokens) ?? asCount(asRecord(usage?.prompt_tokens_details)?.cached_tokens) ?? asCount(asRecord(usage?.input_tokens_details)?.cached_tokens) ?? 0;
|
|
6742
|
+
const reasoningTokens = asCount(asRecord(usage?.output_tokens_details)?.reasoning_tokens) ?? asCount(asRecord(usage?.completion_tokens_details)?.reasoning_tokens);
|
|
6700
6743
|
const parts = [];
|
|
6701
6744
|
if (promptTokens !== void 0) parts.push(`prompt=${promptTokens}`);
|
|
6702
6745
|
if (completionTokens !== void 0) parts.push(`completion=${completionTokens}`);
|
|
6746
|
+
if (reasoningTokens !== void 0) parts.push(`reasoning=${reasoningTokens}`);
|
|
6703
6747
|
parts.push(`cached=${cachedTokens}`);
|
|
6704
6748
|
getLogger().debug(`[${tag}] usage ${parts.join(" ")}`);
|
|
6705
6749
|
} catch {
|
|
@@ -6707,13 +6751,23 @@ function logPortalUsage(body, tag) {
|
|
|
6707
6751
|
}
|
|
6708
6752
|
function extractCompletionContent(body) {
|
|
6709
6753
|
if (typeof body !== "object" || body === null) return null;
|
|
6754
|
+
const responsesText = extractResponsesContent(body);
|
|
6755
|
+
if (responsesText !== null) return responsesText;
|
|
6710
6756
|
const choices = body.choices;
|
|
6711
6757
|
if (!Array.isArray(choices) || choices.length === 0) return null;
|
|
6712
6758
|
const first = choices[0];
|
|
6713
6759
|
const content = first?.message?.content;
|
|
6714
6760
|
return typeof content === "string" ? content : null;
|
|
6715
6761
|
}
|
|
6716
|
-
|
|
6762
|
+
function extractResponsesContent(body) {
|
|
6763
|
+
const root = asRecord(body);
|
|
6764
|
+
if (!root) return null;
|
|
6765
|
+
if (typeof root.output_text === "string" && root.output_text !== "") return root.output_text;
|
|
6766
|
+
if (!Array.isArray(root.output)) return null;
|
|
6767
|
+
const text12 = root.output.filter((item) => asRecord(item)?.type === "message").flatMap((item) => Array.isArray(item.content) ? item.content : []).map((part) => asRecord(part)?.text).filter((t) => typeof t === "string").join("");
|
|
6768
|
+
return text12;
|
|
6769
|
+
}
|
|
6770
|
+
var RESPONSE_FORMAT_OK, RESPONSE_SCHEMA_OK, JSON_CONTRACT_REMINDER, RESPONSES_ONLY_MODEL_PREFIXES, CHAT_TO_RESPONSES_FIELDS, FOREIGN_ENDPOINT_SUFFIX, RETRYABLE_HTTP;
|
|
6717
6771
|
var init_portalLlm = __esm({
|
|
6718
6772
|
"src/lib/memory/portalLlm.ts"() {
|
|
6719
6773
|
"use strict";
|
|
@@ -6725,6 +6779,14 @@ var init_portalLlm = __esm({
|
|
|
6725
6779
|
RESPONSE_FORMAT_OK = /* @__PURE__ */ new Set(["openai", "inclusionai", "deepseek"]);
|
|
6726
6780
|
RESPONSE_SCHEMA_OK = /* @__PURE__ */ new Set(["openai"]);
|
|
6727
6781
|
JSON_CONTRACT_REMINDER = "Output ONLY the strict JSON object requested. No prose, no explanation, no markdown.";
|
|
6782
|
+
RESPONSES_ONLY_MODEL_PREFIXES = ["gpt-5.6"];
|
|
6783
|
+
CHAT_TO_RESPONSES_FIELDS = {
|
|
6784
|
+
max_completion_tokens: "max_output_tokens"
|
|
6785
|
+
};
|
|
6786
|
+
FOREIGN_ENDPOINT_SUFFIX = {
|
|
6787
|
+
chat: "/responses",
|
|
6788
|
+
responses: "/chat/completions"
|
|
6789
|
+
};
|
|
6728
6790
|
RETRYABLE_HTTP = /* @__PURE__ */ new Set([408, 409, 425, 429]);
|
|
6729
6791
|
}
|
|
6730
6792
|
});
|
|
@@ -19057,6 +19119,9 @@ var DEFAULT_BASE_URL2 = BASE_URL;
|
|
|
19057
19119
|
var DEFAULT_MODEL4 = "anthropic/claude-sonnet-4-6";
|
|
19058
19120
|
var DEFAULT_MAX_TOKENS = 4096;
|
|
19059
19121
|
var REQUEST_TIMEOUT_MS = 6e4;
|
|
19122
|
+
var MIN_RETRY_BUDGET_MS = 2e3;
|
|
19123
|
+
var MIN_RESPONSES_OUTPUT_TOKENS = 2048;
|
|
19124
|
+
var SCHEMA_FALLBACK_SKIP_STATUSES = /* @__PURE__ */ new Set([401, 403, 404, 408, 409, 413, 425, 429]);
|
|
19060
19125
|
var DEFAULT_SYSTEM_PROMPT = `You are a personal assistant with access to the user's memory. Answer the user's question using the supplied memories as evidence.
|
|
19061
19126
|
|
|
19062
19127
|
Rules:
|
|
@@ -19088,14 +19153,9 @@ ${m.content}`).join("\n\n");
|
|
|
19088
19153
|
const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL2;
|
|
19089
19154
|
const model = options.llmModel ?? DEFAULT_MODEL4;
|
|
19090
19155
|
const wantsStructured = !!options.responseSchema;
|
|
19091
|
-
const
|
|
19156
|
+
const useResponsesTransport = requiresResponsesTransport(model);
|
|
19157
|
+
const sendResponseFormat = wantsStructured && !useResponsesTransport && supportsResponseFormat(model, "json_schema");
|
|
19092
19158
|
const basePrompt = options.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;
|
|
19093
|
-
const systemPrompt = wantsStructured && !sendResponseFormat ? `${basePrompt}
|
|
19094
|
-
|
|
19095
|
-
Respond with ONLY a single JSON object conforming to this JSON Schema, with no prose, comments, or code fences:
|
|
19096
|
-
${JSON.stringify(
|
|
19097
|
-
options.responseSchema
|
|
19098
|
-
)}` : basePrompt;
|
|
19099
19159
|
const userMessage = [
|
|
19100
19160
|
`Question:
|
|
19101
19161
|
${trimmed}`,
|
|
@@ -19105,85 +19165,121 @@ ${evidence}`
|
|
|
19105
19165
|
].join("\n\n");
|
|
19106
19166
|
const maxTokens = options.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
19107
19167
|
const fetchImpl = options.fetchFn ?? fetch;
|
|
19168
|
+
const buildBody = (useResponseFormat) => {
|
|
19169
|
+
const systemPrompt = wantsStructured && !useResponseFormat ? `${basePrompt}
|
|
19170
|
+
|
|
19171
|
+
Respond with ONLY a single JSON object conforming to this JSON Schema, with no prose, comments, or code fences:
|
|
19172
|
+
${JSON.stringify(
|
|
19173
|
+
options.responseSchema
|
|
19174
|
+
)}` : basePrompt;
|
|
19175
|
+
const messages = [
|
|
19176
|
+
{ role: "system", content: systemPrompt },
|
|
19177
|
+
{ role: "user", content: userMessage }
|
|
19178
|
+
];
|
|
19179
|
+
if (useResponsesTransport) {
|
|
19180
|
+
return JSON.stringify({
|
|
19181
|
+
model,
|
|
19182
|
+
// Same system+user pair under the Responses-API field names: `input`
|
|
19183
|
+
// for the turns, `max_output_tokens` for the cap. Sending the
|
|
19184
|
+
// chat-completions spelling here is silently ignored, which caps the
|
|
19185
|
+
// answer at the portal default.
|
|
19186
|
+
input: messages,
|
|
19187
|
+
max_output_tokens: Math.max(maxTokens, MIN_RESPONSES_OUTPUT_TOKENS)
|
|
19188
|
+
});
|
|
19189
|
+
}
|
|
19190
|
+
return JSON.stringify({
|
|
19191
|
+
model,
|
|
19192
|
+
// Modern OpenAI field; the portal reads only `max_completion_tokens`
|
|
19193
|
+
// (the deprecated `max_tokens` is silently ignored → falls back to the
|
|
19194
|
+
// portal's default output cap and truncates the answer).
|
|
19195
|
+
max_completion_tokens: maxTokens,
|
|
19196
|
+
messages,
|
|
19197
|
+
...useResponseFormat && {
|
|
19198
|
+
response_format: {
|
|
19199
|
+
type: "json_schema",
|
|
19200
|
+
json_schema: { name: "reflect_output", schema: options.responseSchema }
|
|
19201
|
+
}
|
|
19202
|
+
}
|
|
19203
|
+
});
|
|
19204
|
+
};
|
|
19108
19205
|
const log = getLogger();
|
|
19109
19206
|
const authHeaders = await resolvePortalAuthHeaders(options, "memory/reflect");
|
|
19110
19207
|
if (authHeaders === null) return baseResult;
|
|
19111
|
-
const controller = new AbortController();
|
|
19112
19208
|
const deadline = Date.now() + REQUEST_TIMEOUT_MS;
|
|
19113
19209
|
const remaining = () => Math.max(0, deadline - Date.now());
|
|
19114
|
-
const
|
|
19115
|
-
|
|
19116
|
-
|
|
19117
|
-
|
|
19118
|
-
|
|
19119
|
-
|
|
19120
|
-
|
|
19121
|
-
|
|
19122
|
-
|
|
19123
|
-
|
|
19124
|
-
|
|
19125
|
-
|
|
19126
|
-
|
|
19127
|
-
|
|
19128
|
-
|
|
19129
|
-
|
|
19130
|
-
|
|
19131
|
-
|
|
19132
|
-
|
|
19133
|
-
|
|
19134
|
-
|
|
19135
|
-
|
|
19136
|
-
|
|
19137
|
-
|
|
19138
|
-
|
|
19139
|
-
|
|
19140
|
-
}
|
|
19141
|
-
}
|
|
19142
|
-
}),
|
|
19143
|
-
signal: controller.signal
|
|
19144
|
-
});
|
|
19145
|
-
} catch (err) {
|
|
19210
|
+
const endpoint = useResponsesTransport ? "/api/v1/responses" : "/api/v1/chat/completions";
|
|
19211
|
+
const sendOnce = async (useResponseFormat) => {
|
|
19212
|
+
const controller = new AbortController();
|
|
19213
|
+
const timer = setTimeout(() => controller.abort(), remaining());
|
|
19214
|
+
let response;
|
|
19215
|
+
try {
|
|
19216
|
+
response = await fetchImpl(`${baseUrl}${endpoint}`, {
|
|
19217
|
+
method: "POST",
|
|
19218
|
+
// No task type unless the caller named one — an undeclared task adds no
|
|
19219
|
+
// header at all, which is what keeps user-facing reflect() unlabelled.
|
|
19220
|
+
headers: {
|
|
19221
|
+
...authHeaders,
|
|
19222
|
+
...taskTypeHeader(options.taskType),
|
|
19223
|
+
"Content-Type": "application/json"
|
|
19224
|
+
},
|
|
19225
|
+
body: buildBody(useResponseFormat),
|
|
19226
|
+
signal: controller.signal
|
|
19227
|
+
});
|
|
19228
|
+
} catch (err) {
|
|
19229
|
+
clearTimeout(timer);
|
|
19230
|
+
log.warn("[memory/reflect] portal request failed", {
|
|
19231
|
+
err: err instanceof Error ? err.message : String(err),
|
|
19232
|
+
baseUrl
|
|
19233
|
+
});
|
|
19234
|
+
return { kind: "error" };
|
|
19235
|
+
}
|
|
19146
19236
|
clearTimeout(timer);
|
|
19147
|
-
|
|
19148
|
-
|
|
19149
|
-
|
|
19237
|
+
if (!response.ok) {
|
|
19238
|
+
return { kind: "http", status: response.status, statusText: response.statusText };
|
|
19239
|
+
}
|
|
19240
|
+
const bodyTimer = setTimeout(() => controller.abort(), remaining());
|
|
19241
|
+
try {
|
|
19242
|
+
const body = await response.json();
|
|
19243
|
+
clearTimeout(bodyTimer);
|
|
19244
|
+
return { kind: "ok", body };
|
|
19245
|
+
} catch (err) {
|
|
19246
|
+
clearTimeout(bodyTimer);
|
|
19247
|
+
log.warn("[memory/reflect] failed to parse portal response body", {
|
|
19248
|
+
err: err instanceof Error ? err.message : String(err)
|
|
19249
|
+
});
|
|
19250
|
+
return { kind: "error" };
|
|
19251
|
+
}
|
|
19252
|
+
};
|
|
19253
|
+
let attempt = await sendOnce(sendResponseFormat);
|
|
19254
|
+
let schemaFallbackUsed = false;
|
|
19255
|
+
const budgetLeftMs = remaining();
|
|
19256
|
+
if (attempt.kind === "http" && sendResponseFormat && !SCHEMA_FALLBACK_SKIP_STATUSES.has(attempt.status) && budgetLeftMs >= MIN_RETRY_BUDGET_MS) {
|
|
19257
|
+
log.warn("[memory/reflect] response_format json_schema rejected; retrying schema-in-prompt", {
|
|
19258
|
+
status: attempt.status,
|
|
19259
|
+
statusText: attempt.statusText,
|
|
19260
|
+
model,
|
|
19261
|
+
taskType: options.taskType,
|
|
19262
|
+
budgetLeftMs
|
|
19150
19263
|
});
|
|
19151
|
-
|
|
19264
|
+
schemaFallbackUsed = true;
|
|
19265
|
+
attempt = await sendOnce(false);
|
|
19152
19266
|
}
|
|
19153
|
-
|
|
19154
|
-
if (
|
|
19267
|
+
if (attempt.kind === "error") return baseResult;
|
|
19268
|
+
if (attempt.kind === "http") {
|
|
19155
19269
|
log.warn("[memory/reflect] portal returned non-OK", {
|
|
19156
|
-
status:
|
|
19157
|
-
statusText:
|
|
19270
|
+
status: attempt.status,
|
|
19271
|
+
statusText: attempt.statusText,
|
|
19272
|
+
// Distinguishes "the fallback ran and still failed" from "never tried".
|
|
19273
|
+
schemaFallbackUsed
|
|
19158
19274
|
});
|
|
19159
19275
|
return baseResult;
|
|
19160
19276
|
}
|
|
19161
|
-
|
|
19162
|
-
let body;
|
|
19163
|
-
try {
|
|
19164
|
-
body = await response.json();
|
|
19165
|
-
} catch (err) {
|
|
19166
|
-
clearTimeout(bodyTimer);
|
|
19167
|
-
log.warn("[memory/reflect] failed to parse portal response body", {
|
|
19168
|
-
err: err instanceof Error ? err.message : String(err)
|
|
19169
|
-
});
|
|
19170
|
-
return baseResult;
|
|
19171
|
-
}
|
|
19172
|
-
clearTimeout(bodyTimer);
|
|
19173
|
-
return parseAnswer(body, baseResult, !!options.responseSchema);
|
|
19277
|
+
return parseAnswer(attempt.body, baseResult, !!options.responseSchema);
|
|
19174
19278
|
}
|
|
19175
19279
|
function parseAnswer(body, base, parseSchema) {
|
|
19176
19280
|
if (typeof body !== "object" || body === null) return base;
|
|
19177
19281
|
const obj = body;
|
|
19178
|
-
const
|
|
19179
|
-
let text12 = "";
|
|
19180
|
-
if (Array.isArray(choices) && choices.length > 0) {
|
|
19181
|
-
const message = choices[0].message;
|
|
19182
|
-
if (typeof message === "object" && message !== null) {
|
|
19183
|
-
const content = message.content;
|
|
19184
|
-
if (typeof content === "string") text12 = content;
|
|
19185
|
-
}
|
|
19186
|
-
}
|
|
19282
|
+
const text12 = extractCompletionContent(obj) ?? "";
|
|
19187
19283
|
const usage = obj.usage;
|
|
19188
19284
|
let structuredOutput;
|
|
19189
19285
|
if (parseSchema && text12) {
|
|
@@ -19195,14 +19291,19 @@ function parseAnswer(body, base, parseSchema) {
|
|
|
19195
19291
|
});
|
|
19196
19292
|
}
|
|
19197
19293
|
}
|
|
19294
|
+
const promptTokens = usage?.prompt_tokens ?? usage?.input_tokens ?? 0;
|
|
19295
|
+
const completionTokens = usage?.completion_tokens ?? usage?.output_tokens ?? 0;
|
|
19198
19296
|
return {
|
|
19199
19297
|
text: text12,
|
|
19200
19298
|
...structuredOutput !== void 0 && { structuredOutput },
|
|
19201
19299
|
basedOn: base.basedOn,
|
|
19202
19300
|
usage: {
|
|
19203
|
-
promptTokens
|
|
19204
|
-
completionTokens
|
|
19205
|
-
|
|
19301
|
+
promptTokens,
|
|
19302
|
+
completionTokens,
|
|
19303
|
+
// Derived when absent: the Responses API reports the two component counts
|
|
19304
|
+
// and does not always send a total, which would otherwise report zero
|
|
19305
|
+
// spend for a call that plainly cost something.
|
|
19306
|
+
totalTokens: usage?.total_tokens ?? promptTokens + completionTokens
|
|
19206
19307
|
}
|
|
19207
19308
|
};
|
|
19208
19309
|
}
|
package/dist/react/index.mjs
CHANGED
|
@@ -178,28 +178,30 @@ import {
|
|
|
178
178
|
updateVaultMemoryOp,
|
|
179
179
|
useEncryption,
|
|
180
180
|
vaultMemoryToStored
|
|
181
|
-
} from "./chunk-
|
|
181
|
+
} from "./chunk-YSL3J4K4.mjs";
|
|
182
182
|
import {
|
|
183
183
|
PiiRedactor,
|
|
184
184
|
createStreamingDeAnonymizer,
|
|
185
185
|
isPiiRedactor,
|
|
186
186
|
notifyConsolidationFallback,
|
|
187
187
|
resolvePiiRedactor
|
|
188
|
-
} from "./chunk-
|
|
188
|
+
} from "./chunk-7X7BNMGS.mjs";
|
|
189
189
|
import {
|
|
190
190
|
INTERNAL_FLOW_MARKER,
|
|
191
191
|
callPortalJsonCompletion,
|
|
192
192
|
consoleLogger,
|
|
193
|
+
extractCompletionContent,
|
|
193
194
|
extractJsonCandidate,
|
|
194
195
|
getLogger,
|
|
195
196
|
noopLogger,
|
|
197
|
+
requiresResponsesTransport,
|
|
196
198
|
resolvePortalAuthHeaders,
|
|
197
199
|
setLogger,
|
|
198
200
|
supportsResponseFormat,
|
|
199
201
|
taskTypeHeader,
|
|
200
202
|
validateEndpointOverride,
|
|
201
203
|
withInternalFlowMarker
|
|
202
|
-
} from "./chunk-
|
|
204
|
+
} from "./chunk-4Z2X4UYQ.mjs";
|
|
203
205
|
import {
|
|
204
206
|
BASE_URL,
|
|
205
207
|
MCP_R2_DOMAIN,
|
|
@@ -7686,7 +7688,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
7686
7688
|
content: m.content,
|
|
7687
7689
|
similarity: m.similarity
|
|
7688
7690
|
}));
|
|
7689
|
-
const { consolidateMemory: doConsolidate } = await import("./consolidate-
|
|
7691
|
+
const { consolidateMemory: doConsolidate } = await import("./consolidate-7NMKF7UC.mjs");
|
|
7690
7692
|
const decision = await doConsolidate(trimmed, candidates, consolidateOptions);
|
|
7691
7693
|
if (decision.action === "create") return null;
|
|
7692
7694
|
if (decision.action === "supersede" && decision.content) {
|
|
@@ -8910,6 +8912,9 @@ var DEFAULT_BASE_URL = BASE_URL;
|
|
|
8910
8912
|
var DEFAULT_MODEL3 = "anthropic/claude-sonnet-4-6";
|
|
8911
8913
|
var DEFAULT_MAX_TOKENS = 4096;
|
|
8912
8914
|
var REQUEST_TIMEOUT_MS = 6e4;
|
|
8915
|
+
var MIN_RETRY_BUDGET_MS = 2e3;
|
|
8916
|
+
var MIN_RESPONSES_OUTPUT_TOKENS = 2048;
|
|
8917
|
+
var SCHEMA_FALLBACK_SKIP_STATUSES = /* @__PURE__ */ new Set([401, 403, 404, 408, 409, 413, 425, 429]);
|
|
8913
8918
|
var DEFAULT_SYSTEM_PROMPT = `You are a personal assistant with access to the user's memory. Answer the user's question using the supplied memories as evidence.
|
|
8914
8919
|
|
|
8915
8920
|
Rules:
|
|
@@ -8941,14 +8946,9 @@ ${m.content}`).join("\n\n");
|
|
|
8941
8946
|
const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
|
|
8942
8947
|
const model = options.llmModel ?? DEFAULT_MODEL3;
|
|
8943
8948
|
const wantsStructured = !!options.responseSchema;
|
|
8944
|
-
const
|
|
8949
|
+
const useResponsesTransport = requiresResponsesTransport(model);
|
|
8950
|
+
const sendResponseFormat = wantsStructured && !useResponsesTransport && supportsResponseFormat(model, "json_schema");
|
|
8945
8951
|
const basePrompt = options.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;
|
|
8946
|
-
const systemPrompt = wantsStructured && !sendResponseFormat ? `${basePrompt}
|
|
8947
|
-
|
|
8948
|
-
Respond with ONLY a single JSON object conforming to this JSON Schema, with no prose, comments, or code fences:
|
|
8949
|
-
${JSON.stringify(
|
|
8950
|
-
options.responseSchema
|
|
8951
|
-
)}` : basePrompt;
|
|
8952
8952
|
const userMessage = [
|
|
8953
8953
|
`Question:
|
|
8954
8954
|
${trimmed}`,
|
|
@@ -8958,85 +8958,121 @@ ${evidence}`
|
|
|
8958
8958
|
].join("\n\n");
|
|
8959
8959
|
const maxTokens = options.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
8960
8960
|
const fetchImpl = options.fetchFn ?? fetch;
|
|
8961
|
+
const buildBody = (useResponseFormat) => {
|
|
8962
|
+
const systemPrompt = wantsStructured && !useResponseFormat ? `${basePrompt}
|
|
8963
|
+
|
|
8964
|
+
Respond with ONLY a single JSON object conforming to this JSON Schema, with no prose, comments, or code fences:
|
|
8965
|
+
${JSON.stringify(
|
|
8966
|
+
options.responseSchema
|
|
8967
|
+
)}` : basePrompt;
|
|
8968
|
+
const messages = [
|
|
8969
|
+
{ role: "system", content: systemPrompt },
|
|
8970
|
+
{ role: "user", content: userMessage }
|
|
8971
|
+
];
|
|
8972
|
+
if (useResponsesTransport) {
|
|
8973
|
+
return JSON.stringify({
|
|
8974
|
+
model,
|
|
8975
|
+
// Same system+user pair under the Responses-API field names: `input`
|
|
8976
|
+
// for the turns, `max_output_tokens` for the cap. Sending the
|
|
8977
|
+
// chat-completions spelling here is silently ignored, which caps the
|
|
8978
|
+
// answer at the portal default.
|
|
8979
|
+
input: messages,
|
|
8980
|
+
max_output_tokens: Math.max(maxTokens, MIN_RESPONSES_OUTPUT_TOKENS)
|
|
8981
|
+
});
|
|
8982
|
+
}
|
|
8983
|
+
return JSON.stringify({
|
|
8984
|
+
model,
|
|
8985
|
+
// Modern OpenAI field; the portal reads only `max_completion_tokens`
|
|
8986
|
+
// (the deprecated `max_tokens` is silently ignored → falls back to the
|
|
8987
|
+
// portal's default output cap and truncates the answer).
|
|
8988
|
+
max_completion_tokens: maxTokens,
|
|
8989
|
+
messages,
|
|
8990
|
+
...useResponseFormat && {
|
|
8991
|
+
response_format: {
|
|
8992
|
+
type: "json_schema",
|
|
8993
|
+
json_schema: { name: "reflect_output", schema: options.responseSchema }
|
|
8994
|
+
}
|
|
8995
|
+
}
|
|
8996
|
+
});
|
|
8997
|
+
};
|
|
8961
8998
|
const log = getLogger();
|
|
8962
8999
|
const authHeaders = await resolvePortalAuthHeaders(options, "memory/reflect");
|
|
8963
9000
|
if (authHeaders === null) return baseResult;
|
|
8964
|
-
const controller = new AbortController();
|
|
8965
9001
|
const deadline = Date.now() + REQUEST_TIMEOUT_MS;
|
|
8966
9002
|
const remaining = () => Math.max(0, deadline - Date.now());
|
|
8967
|
-
const
|
|
8968
|
-
|
|
8969
|
-
|
|
8970
|
-
|
|
8971
|
-
|
|
8972
|
-
|
|
8973
|
-
|
|
8974
|
-
|
|
8975
|
-
|
|
8976
|
-
|
|
8977
|
-
|
|
8978
|
-
|
|
8979
|
-
|
|
8980
|
-
|
|
8981
|
-
|
|
8982
|
-
|
|
8983
|
-
|
|
8984
|
-
|
|
8985
|
-
|
|
8986
|
-
|
|
8987
|
-
|
|
8988
|
-
|
|
8989
|
-
|
|
8990
|
-
|
|
8991
|
-
|
|
8992
|
-
|
|
8993
|
-
}
|
|
8994
|
-
}
|
|
8995
|
-
}),
|
|
8996
|
-
signal: controller.signal
|
|
8997
|
-
});
|
|
8998
|
-
} catch (err) {
|
|
9003
|
+
const endpoint = useResponsesTransport ? "/api/v1/responses" : "/api/v1/chat/completions";
|
|
9004
|
+
const sendOnce = async (useResponseFormat) => {
|
|
9005
|
+
const controller = new AbortController();
|
|
9006
|
+
const timer = setTimeout(() => controller.abort(), remaining());
|
|
9007
|
+
let response;
|
|
9008
|
+
try {
|
|
9009
|
+
response = await fetchImpl(`${baseUrl}${endpoint}`, {
|
|
9010
|
+
method: "POST",
|
|
9011
|
+
// No task type unless the caller named one — an undeclared task adds no
|
|
9012
|
+
// header at all, which is what keeps user-facing reflect() unlabelled.
|
|
9013
|
+
headers: {
|
|
9014
|
+
...authHeaders,
|
|
9015
|
+
...taskTypeHeader(options.taskType),
|
|
9016
|
+
"Content-Type": "application/json"
|
|
9017
|
+
},
|
|
9018
|
+
body: buildBody(useResponseFormat),
|
|
9019
|
+
signal: controller.signal
|
|
9020
|
+
});
|
|
9021
|
+
} catch (err) {
|
|
9022
|
+
clearTimeout(timer);
|
|
9023
|
+
log.warn("[memory/reflect] portal request failed", {
|
|
9024
|
+
err: err instanceof Error ? err.message : String(err),
|
|
9025
|
+
baseUrl
|
|
9026
|
+
});
|
|
9027
|
+
return { kind: "error" };
|
|
9028
|
+
}
|
|
8999
9029
|
clearTimeout(timer);
|
|
9000
|
-
|
|
9001
|
-
|
|
9002
|
-
|
|
9030
|
+
if (!response.ok) {
|
|
9031
|
+
return { kind: "http", status: response.status, statusText: response.statusText };
|
|
9032
|
+
}
|
|
9033
|
+
const bodyTimer = setTimeout(() => controller.abort(), remaining());
|
|
9034
|
+
try {
|
|
9035
|
+
const body = await response.json();
|
|
9036
|
+
clearTimeout(bodyTimer);
|
|
9037
|
+
return { kind: "ok", body };
|
|
9038
|
+
} catch (err) {
|
|
9039
|
+
clearTimeout(bodyTimer);
|
|
9040
|
+
log.warn("[memory/reflect] failed to parse portal response body", {
|
|
9041
|
+
err: err instanceof Error ? err.message : String(err)
|
|
9042
|
+
});
|
|
9043
|
+
return { kind: "error" };
|
|
9044
|
+
}
|
|
9045
|
+
};
|
|
9046
|
+
let attempt = await sendOnce(sendResponseFormat);
|
|
9047
|
+
let schemaFallbackUsed = false;
|
|
9048
|
+
const budgetLeftMs = remaining();
|
|
9049
|
+
if (attempt.kind === "http" && sendResponseFormat && !SCHEMA_FALLBACK_SKIP_STATUSES.has(attempt.status) && budgetLeftMs >= MIN_RETRY_BUDGET_MS) {
|
|
9050
|
+
log.warn("[memory/reflect] response_format json_schema rejected; retrying schema-in-prompt", {
|
|
9051
|
+
status: attempt.status,
|
|
9052
|
+
statusText: attempt.statusText,
|
|
9053
|
+
model,
|
|
9054
|
+
taskType: options.taskType,
|
|
9055
|
+
budgetLeftMs
|
|
9003
9056
|
});
|
|
9004
|
-
|
|
9057
|
+
schemaFallbackUsed = true;
|
|
9058
|
+
attempt = await sendOnce(false);
|
|
9005
9059
|
}
|
|
9006
|
-
|
|
9007
|
-
if (
|
|
9060
|
+
if (attempt.kind === "error") return baseResult;
|
|
9061
|
+
if (attempt.kind === "http") {
|
|
9008
9062
|
log.warn("[memory/reflect] portal returned non-OK", {
|
|
9009
|
-
status:
|
|
9010
|
-
statusText:
|
|
9063
|
+
status: attempt.status,
|
|
9064
|
+
statusText: attempt.statusText,
|
|
9065
|
+
// Distinguishes "the fallback ran and still failed" from "never tried".
|
|
9066
|
+
schemaFallbackUsed
|
|
9011
9067
|
});
|
|
9012
9068
|
return baseResult;
|
|
9013
9069
|
}
|
|
9014
|
-
|
|
9015
|
-
let body;
|
|
9016
|
-
try {
|
|
9017
|
-
body = await response.json();
|
|
9018
|
-
} catch (err) {
|
|
9019
|
-
clearTimeout(bodyTimer);
|
|
9020
|
-
log.warn("[memory/reflect] failed to parse portal response body", {
|
|
9021
|
-
err: err instanceof Error ? err.message : String(err)
|
|
9022
|
-
});
|
|
9023
|
-
return baseResult;
|
|
9024
|
-
}
|
|
9025
|
-
clearTimeout(bodyTimer);
|
|
9026
|
-
return parseAnswer(body, baseResult, !!options.responseSchema);
|
|
9070
|
+
return parseAnswer(attempt.body, baseResult, !!options.responseSchema);
|
|
9027
9071
|
}
|
|
9028
9072
|
function parseAnswer(body, base, parseSchema) {
|
|
9029
9073
|
if (typeof body !== "object" || body === null) return base;
|
|
9030
9074
|
const obj = body;
|
|
9031
|
-
const
|
|
9032
|
-
let text12 = "";
|
|
9033
|
-
if (Array.isArray(choices) && choices.length > 0) {
|
|
9034
|
-
const message = choices[0].message;
|
|
9035
|
-
if (typeof message === "object" && message !== null) {
|
|
9036
|
-
const content = message.content;
|
|
9037
|
-
if (typeof content === "string") text12 = content;
|
|
9038
|
-
}
|
|
9039
|
-
}
|
|
9075
|
+
const text12 = extractCompletionContent(obj) ?? "";
|
|
9040
9076
|
const usage = obj.usage;
|
|
9041
9077
|
let structuredOutput;
|
|
9042
9078
|
if (parseSchema && text12) {
|
|
@@ -9048,14 +9084,19 @@ function parseAnswer(body, base, parseSchema) {
|
|
|
9048
9084
|
});
|
|
9049
9085
|
}
|
|
9050
9086
|
}
|
|
9087
|
+
const promptTokens = usage?.prompt_tokens ?? usage?.input_tokens ?? 0;
|
|
9088
|
+
const completionTokens = usage?.completion_tokens ?? usage?.output_tokens ?? 0;
|
|
9051
9089
|
return {
|
|
9052
9090
|
text: text12,
|
|
9053
9091
|
...structuredOutput !== void 0 && { structuredOutput },
|
|
9054
9092
|
basedOn: base.basedOn,
|
|
9055
9093
|
usage: {
|
|
9056
|
-
promptTokens
|
|
9057
|
-
completionTokens
|
|
9058
|
-
|
|
9094
|
+
promptTokens,
|
|
9095
|
+
completionTokens,
|
|
9096
|
+
// Derived when absent: the Responses API reports the two component counts
|
|
9097
|
+
// and does not always send a total, which would otherwise report zero
|
|
9098
|
+
// spend for a call that plainly cost something.
|
|
9099
|
+
totalTokens: usage?.total_tokens ?? promptTokens + completionTokens
|
|
9059
9100
|
}
|
|
9060
9101
|
};
|
|
9061
9102
|
}
|