@anuma/sdk 6.15.0 → 6.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/expo/{chunk-3V3BBJLH.mjs → chunk-4Z2X4UYQ.mjs} +7 -1
- package/dist/expo/{chunk-DIUQLXEH.mjs → chunk-A2G6TRUK.mjs} +1 -1
- package/dist/expo/{chunk-LUSKQQDD.mjs → chunk-JXN7LD6B.mjs} +41 -17
- package/dist/{react/consolidate-Y2XWEZRQ.mjs → expo/consolidate-ZM5JNULQ.mjs} +2 -2
- package/dist/expo/index.cjs +179 -104
- package/dist/expo/index.mjs +143 -92
- package/dist/expo/{recall-GKYVPD2B.mjs → recall-TGRI5MN4.mjs} +2 -2
- package/dist/react/{chunk-3V3BBJLH.mjs → chunk-4Z2X4UYQ.mjs} +7 -1
- package/dist/react/{chunk-2GNOTRG4.mjs → chunk-7X7BNMGS.mjs} +1 -1
- package/dist/react/{chunk-PDKKPAXP.mjs → chunk-TVPCH7ZZ.mjs} +45 -21
- package/dist/{expo/consolidate-GTMXZZ4C.mjs → react/consolidate-7NMKF7UC.mjs} +2 -2
- package/dist/react/index.cjs +183 -108
- package/dist/react/index.mjs +143 -92
- package/dist/react/{recall-5HNAFHLL.mjs → recall-OKNLU335.mjs} +2 -2
- package/dist/server/{chunk-JPLFOSB2.mjs → chunk-4LPSEROP.mjs} +1 -1
- package/dist/server/{chunk-H4G3DLDJ.mjs → chunk-BSCEZOIW.mjs} +7 -1
- package/dist/server/{chunk-2QFK4L7Y.mjs → chunk-K7H7ICPK.mjs} +21 -21
- package/dist/server/{consolidate-CMMDTZ37.mjs → consolidate-MSAXASHL.mjs} +2 -2
- package/dist/server/index.cjs +136 -93
- package/dist/server/index.mjs +118 -77
- package/dist/server/{recall-EODNEKIA.mjs → recall-YXJATOSD.mjs} +2 -2
- package/package.json +1 -1
package/dist/react/index.cjs
CHANGED
|
@@ -2220,6 +2220,29 @@ async function getMessageSkeletonsOp(ctx, convId) {
|
|
|
2220
2220
|
}
|
|
2221
2221
|
return skeletons;
|
|
2222
2222
|
}
|
|
2223
|
+
async function getToolCallEventIdsOp(ctx, convId) {
|
|
2224
|
+
const results = await ctx.messagesCollection.query(import_watermelondb.Q.where("conversation_id", convId)).unsafeFetchRaw();
|
|
2225
|
+
const ids = /* @__PURE__ */ new Set();
|
|
2226
|
+
for (const raw of results) {
|
|
2227
|
+
const value = raw.tool_call_events;
|
|
2228
|
+
if (!value) continue;
|
|
2229
|
+
let events;
|
|
2230
|
+
if (typeof value === "string") {
|
|
2231
|
+
try {
|
|
2232
|
+
events = JSON.parse(value);
|
|
2233
|
+
} catch {
|
|
2234
|
+
continue;
|
|
2235
|
+
}
|
|
2236
|
+
} else if (Array.isArray(value)) {
|
|
2237
|
+
events = value;
|
|
2238
|
+
}
|
|
2239
|
+
if (!Array.isArray(events)) continue;
|
|
2240
|
+
for (const evt of events) {
|
|
2241
|
+
if (evt && evt.id) ids.add(evt.id);
|
|
2242
|
+
}
|
|
2243
|
+
}
|
|
2244
|
+
return ids;
|
|
2245
|
+
}
|
|
2223
2246
|
async function clearMessagesOp(ctx, convId) {
|
|
2224
2247
|
const messages = await ctx.messagesCollection.query(import_watermelondb.Q.where("conversation_id", convId)).fetch();
|
|
2225
2248
|
await ctx.database.write(async () => {
|
|
@@ -2449,14 +2472,14 @@ function resolveChunkText(content, chunk, chunksInRow) {
|
|
|
2449
2472
|
if (covered !== content.length) return content;
|
|
2450
2473
|
return content.slice(start, end);
|
|
2451
2474
|
}
|
|
2452
|
-
async function
|
|
2453
|
-
const
|
|
2454
|
-
if (!
|
|
2455
|
-
if (walletAddress && isEncrypted(
|
|
2456
|
-
return await decryptJsonField(
|
|
2475
|
+
async function readRawJsonField(raw, column, walletAddress) {
|
|
2476
|
+
const value = raw[column];
|
|
2477
|
+
if (!value) return void 0;
|
|
2478
|
+
if (walletAddress && isEncrypted(value)) {
|
|
2479
|
+
return await decryptJsonField(value, walletAddress);
|
|
2457
2480
|
}
|
|
2458
2481
|
try {
|
|
2459
|
-
return JSON.parse(
|
|
2482
|
+
return JSON.parse(value);
|
|
2460
2483
|
} catch {
|
|
2461
2484
|
return void 0;
|
|
2462
2485
|
}
|
|
@@ -2469,12 +2492,12 @@ async function searchMessagesOp(ctx, queryVector, options) {
|
|
|
2469
2492
|
activeConversations.map((c) => String(c._getRaw("conversation_id")))
|
|
2470
2493
|
);
|
|
2471
2494
|
const queryConditions = conversationId ? [import_watermelondb.Q.where("conversation_id", conversationId)] : [];
|
|
2472
|
-
const messages = await ctx.messagesCollection.query(...queryConditions).
|
|
2495
|
+
const messages = await ctx.messagesCollection.query(...queryConditions).unsafeFetchRaw();
|
|
2473
2496
|
const candidates = [];
|
|
2474
2497
|
for (const message of messages) {
|
|
2475
|
-
const msgConvId = String(message.
|
|
2498
|
+
const msgConvId = String(message.conversation_id);
|
|
2476
2499
|
if (!activeConversationIds.has(msgConvId)) continue;
|
|
2477
|
-
const messageVector = await
|
|
2500
|
+
const messageVector = await readRawJsonField(message, "vector", ctx.walletAddress);
|
|
2478
2501
|
if (!messageVector || messageVector.length === 0) continue;
|
|
2479
2502
|
const similarity = cosineSimilarity(queryVector, messageVector);
|
|
2480
2503
|
if (similarity >= minSimilarity) {
|
|
@@ -2484,7 +2507,7 @@ async function searchMessagesOp(ctx, queryVector, options) {
|
|
|
2484
2507
|
const topK = candidates.sort((a, b) => b.similarity - a.similarity).slice(0, limit);
|
|
2485
2508
|
return Promise.all(
|
|
2486
2509
|
topK.map(async ({ message, similarity }) => {
|
|
2487
|
-
const stored = await
|
|
2510
|
+
const stored = await messageRawToStored(
|
|
2488
2511
|
message,
|
|
2489
2512
|
ctx.walletAddress,
|
|
2490
2513
|
ctx.signMessage,
|
|
@@ -2508,21 +2531,21 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
2508
2531
|
activeConversations.map((c) => String(c._getRaw("conversation_id")))
|
|
2509
2532
|
);
|
|
2510
2533
|
const queryConditions = conversationId ? [import_watermelondb.Q.where("conversation_id", conversationId)] : [];
|
|
2511
|
-
const messages = await ctx.messagesCollection.query(...queryConditions).
|
|
2534
|
+
const messages = await ctx.messagesCollection.query(...queryConditions).unsafeFetchRaw();
|
|
2512
2535
|
const candidates = [];
|
|
2513
2536
|
let staleSkipped = 0;
|
|
2514
2537
|
let unreadableVectors = 0;
|
|
2515
2538
|
for (const message of messages) {
|
|
2516
|
-
const msgConvId = String(message.
|
|
2539
|
+
const msgConvId = String(message.conversation_id);
|
|
2517
2540
|
if (!activeConversationIds.has(msgConvId)) continue;
|
|
2518
2541
|
if (embeddingModel) {
|
|
2519
|
-
const storedModel = message.
|
|
2542
|
+
const storedModel = message.embedding_model;
|
|
2520
2543
|
if (storedModel !== null && storedModel !== void 0 && storedModel !== embeddingModel) {
|
|
2521
2544
|
staleSkipped++;
|
|
2522
2545
|
continue;
|
|
2523
2546
|
}
|
|
2524
2547
|
}
|
|
2525
|
-
const version = Number(message.
|
|
2548
|
+
const version = Number(message.updated_at) || 0;
|
|
2526
2549
|
const cached = chunkCache?.get(message.id);
|
|
2527
2550
|
if (cached && cached.version === version) {
|
|
2528
2551
|
if (cached.chunks.length > 0) {
|
|
@@ -2546,7 +2569,7 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
2546
2569
|
}
|
|
2547
2570
|
continue;
|
|
2548
2571
|
}
|
|
2549
|
-
const chunks = await
|
|
2572
|
+
const chunks = await readRawJsonField(message, "chunks", ctx.walletAddress);
|
|
2550
2573
|
if (chunks && chunks.length > 0) {
|
|
2551
2574
|
const vectors = chunks.map(
|
|
2552
2575
|
(chunk) => decodeChunkVector(chunk.vector, () => {
|
|
@@ -2567,7 +2590,7 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
2567
2590
|
}
|
|
2568
2591
|
}
|
|
2569
2592
|
} else {
|
|
2570
|
-
const messageVector = await
|
|
2593
|
+
const messageVector = await readRawJsonField(message, "vector", ctx.walletAddress);
|
|
2571
2594
|
if (!messageVector || messageVector.length === 0) continue;
|
|
2572
2595
|
const fallback = Float32Array.from(messageVector);
|
|
2573
2596
|
chunkCache?.set(message.id, { version, chunks: [], fallback });
|
|
@@ -2593,7 +2616,7 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
2593
2616
|
const storedById = new Map(
|
|
2594
2617
|
await Promise.all(
|
|
2595
2618
|
Array.from(uniqueMessages, async ([id, m]) => {
|
|
2596
|
-
const stored = await
|
|
2619
|
+
const stored = await messageRawToStored(
|
|
2597
2620
|
m,
|
|
2598
2621
|
ctx.walletAddress,
|
|
2599
2622
|
ctx.signMessage,
|
|
@@ -2611,8 +2634,8 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
2611
2634
|
await Promise.all(
|
|
2612
2635
|
Array.from(needsChunkText, async (id) => {
|
|
2613
2636
|
const m = uniqueMessages.get(id);
|
|
2614
|
-
const parsed = await
|
|
2615
|
-
const version = Number(m.
|
|
2637
|
+
const parsed = await readRawJsonField(m, "chunks", ctx.walletAddress);
|
|
2638
|
+
const version = Number(m.updated_at) || 0;
|
|
2616
2639
|
if (parsed) chunkStateByMsgId.set(id, { version, chunks: parsed });
|
|
2617
2640
|
})
|
|
2618
2641
|
);
|
|
@@ -6429,6 +6452,9 @@ function supportsResponseFormat(model, variant = "json_object") {
|
|
|
6429
6452
|
const allow = variant === "json_schema" ? RESPONSE_SCHEMA_OK : RESPONSE_FORMAT_OK;
|
|
6430
6453
|
return model.split("/").some((seg) => allow.has(seg));
|
|
6431
6454
|
}
|
|
6455
|
+
function requiresResponsesTransport(model) {
|
|
6456
|
+
return model.split("/").some((seg) => RESPONSES_ONLY_MODEL_PREFIXES.some((prefix) => seg.startsWith(prefix)));
|
|
6457
|
+
}
|
|
6432
6458
|
function responsesExtra(extra) {
|
|
6433
6459
|
if (!extra) return {};
|
|
6434
6460
|
const out = {};
|
|
@@ -6764,7 +6790,7 @@ function extractResponsesContent(body) {
|
|
|
6764
6790
|
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("");
|
|
6765
6791
|
return text12;
|
|
6766
6792
|
}
|
|
6767
|
-
var RESPONSE_FORMAT_OK, RESPONSE_SCHEMA_OK, JSON_CONTRACT_REMINDER, CHAT_TO_RESPONSES_FIELDS, FOREIGN_ENDPOINT_SUFFIX, RETRYABLE_HTTP;
|
|
6793
|
+
var RESPONSE_FORMAT_OK, RESPONSE_SCHEMA_OK, JSON_CONTRACT_REMINDER, RESPONSES_ONLY_MODEL_PREFIXES, CHAT_TO_RESPONSES_FIELDS, FOREIGN_ENDPOINT_SUFFIX, RETRYABLE_HTTP;
|
|
6768
6794
|
var init_portalLlm = __esm({
|
|
6769
6795
|
"src/lib/memory/portalLlm.ts"() {
|
|
6770
6796
|
"use strict";
|
|
@@ -6776,6 +6802,7 @@ var init_portalLlm = __esm({
|
|
|
6776
6802
|
RESPONSE_FORMAT_OK = /* @__PURE__ */ new Set(["openai", "inclusionai", "deepseek"]);
|
|
6777
6803
|
RESPONSE_SCHEMA_OK = /* @__PURE__ */ new Set(["openai"]);
|
|
6778
6804
|
JSON_CONTRACT_REMINDER = "Output ONLY the strict JSON object requested. No prose, no explanation, no markdown.";
|
|
6805
|
+
RESPONSES_ONLY_MODEL_PREFIXES = ["gpt-5.6"];
|
|
6779
6806
|
CHAT_TO_RESPONSES_FIELDS = {
|
|
6780
6807
|
max_completion_tokens: "max_output_tokens"
|
|
6781
6808
|
};
|
|
@@ -19115,6 +19142,9 @@ var DEFAULT_BASE_URL2 = BASE_URL;
|
|
|
19115
19142
|
var DEFAULT_MODEL4 = "anthropic/claude-sonnet-4-6";
|
|
19116
19143
|
var DEFAULT_MAX_TOKENS = 4096;
|
|
19117
19144
|
var REQUEST_TIMEOUT_MS = 6e4;
|
|
19145
|
+
var MIN_RETRY_BUDGET_MS = 2e3;
|
|
19146
|
+
var MIN_RESPONSES_OUTPUT_TOKENS = 2048;
|
|
19147
|
+
var SCHEMA_FALLBACK_SKIP_STATUSES = /* @__PURE__ */ new Set([401, 403, 404, 408, 409, 413, 425, 429]);
|
|
19118
19148
|
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.
|
|
19119
19149
|
|
|
19120
19150
|
Rules:
|
|
@@ -19146,14 +19176,9 @@ ${m.content}`).join("\n\n");
|
|
|
19146
19176
|
const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL2;
|
|
19147
19177
|
const model = options.llmModel ?? DEFAULT_MODEL4;
|
|
19148
19178
|
const wantsStructured = !!options.responseSchema;
|
|
19149
|
-
const
|
|
19179
|
+
const useResponsesTransport = requiresResponsesTransport(model);
|
|
19180
|
+
const sendResponseFormat = wantsStructured && !useResponsesTransport && supportsResponseFormat(model, "json_schema");
|
|
19150
19181
|
const basePrompt = options.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;
|
|
19151
|
-
const systemPrompt = wantsStructured && !sendResponseFormat ? `${basePrompt}
|
|
19152
|
-
|
|
19153
|
-
Respond with ONLY a single JSON object conforming to this JSON Schema, with no prose, comments, or code fences:
|
|
19154
|
-
${JSON.stringify(
|
|
19155
|
-
options.responseSchema
|
|
19156
|
-
)}` : basePrompt;
|
|
19157
19182
|
const userMessage = [
|
|
19158
19183
|
`Question:
|
|
19159
19184
|
${trimmed}`,
|
|
@@ -19163,85 +19188,121 @@ ${evidence}`
|
|
|
19163
19188
|
].join("\n\n");
|
|
19164
19189
|
const maxTokens = options.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
19165
19190
|
const fetchImpl = options.fetchFn ?? fetch;
|
|
19191
|
+
const buildBody = (useResponseFormat) => {
|
|
19192
|
+
const systemPrompt = wantsStructured && !useResponseFormat ? `${basePrompt}
|
|
19193
|
+
|
|
19194
|
+
Respond with ONLY a single JSON object conforming to this JSON Schema, with no prose, comments, or code fences:
|
|
19195
|
+
${JSON.stringify(
|
|
19196
|
+
options.responseSchema
|
|
19197
|
+
)}` : basePrompt;
|
|
19198
|
+
const messages = [
|
|
19199
|
+
{ role: "system", content: systemPrompt },
|
|
19200
|
+
{ role: "user", content: userMessage }
|
|
19201
|
+
];
|
|
19202
|
+
if (useResponsesTransport) {
|
|
19203
|
+
return JSON.stringify({
|
|
19204
|
+
model,
|
|
19205
|
+
// Same system+user pair under the Responses-API field names: `input`
|
|
19206
|
+
// for the turns, `max_output_tokens` for the cap. Sending the
|
|
19207
|
+
// chat-completions spelling here is silently ignored, which caps the
|
|
19208
|
+
// answer at the portal default.
|
|
19209
|
+
input: messages,
|
|
19210
|
+
max_output_tokens: Math.max(maxTokens, MIN_RESPONSES_OUTPUT_TOKENS)
|
|
19211
|
+
});
|
|
19212
|
+
}
|
|
19213
|
+
return JSON.stringify({
|
|
19214
|
+
model,
|
|
19215
|
+
// Modern OpenAI field; the portal reads only `max_completion_tokens`
|
|
19216
|
+
// (the deprecated `max_tokens` is silently ignored → falls back to the
|
|
19217
|
+
// portal's default output cap and truncates the answer).
|
|
19218
|
+
max_completion_tokens: maxTokens,
|
|
19219
|
+
messages,
|
|
19220
|
+
...useResponseFormat && {
|
|
19221
|
+
response_format: {
|
|
19222
|
+
type: "json_schema",
|
|
19223
|
+
json_schema: { name: "reflect_output", schema: options.responseSchema }
|
|
19224
|
+
}
|
|
19225
|
+
}
|
|
19226
|
+
});
|
|
19227
|
+
};
|
|
19166
19228
|
const log = getLogger();
|
|
19167
19229
|
const authHeaders = await resolvePortalAuthHeaders(options, "memory/reflect");
|
|
19168
19230
|
if (authHeaders === null) return baseResult;
|
|
19169
|
-
const controller = new AbortController();
|
|
19170
19231
|
const deadline = Date.now() + REQUEST_TIMEOUT_MS;
|
|
19171
19232
|
const remaining = () => Math.max(0, deadline - Date.now());
|
|
19172
|
-
const
|
|
19173
|
-
|
|
19174
|
-
|
|
19175
|
-
|
|
19176
|
-
|
|
19177
|
-
|
|
19178
|
-
|
|
19179
|
-
|
|
19180
|
-
|
|
19181
|
-
|
|
19182
|
-
|
|
19183
|
-
|
|
19184
|
-
|
|
19185
|
-
|
|
19186
|
-
|
|
19187
|
-
|
|
19188
|
-
|
|
19189
|
-
|
|
19190
|
-
|
|
19191
|
-
|
|
19192
|
-
|
|
19193
|
-
|
|
19194
|
-
|
|
19195
|
-
|
|
19196
|
-
|
|
19197
|
-
|
|
19198
|
-
}
|
|
19199
|
-
}
|
|
19200
|
-
}),
|
|
19201
|
-
signal: controller.signal
|
|
19202
|
-
});
|
|
19203
|
-
} catch (err) {
|
|
19233
|
+
const endpoint = useResponsesTransport ? "/api/v1/responses" : "/api/v1/chat/completions";
|
|
19234
|
+
const sendOnce = async (useResponseFormat) => {
|
|
19235
|
+
const controller = new AbortController();
|
|
19236
|
+
const timer = setTimeout(() => controller.abort(), remaining());
|
|
19237
|
+
let response;
|
|
19238
|
+
try {
|
|
19239
|
+
response = await fetchImpl(`${baseUrl}${endpoint}`, {
|
|
19240
|
+
method: "POST",
|
|
19241
|
+
// No task type unless the caller named one — an undeclared task adds no
|
|
19242
|
+
// header at all, which is what keeps user-facing reflect() unlabelled.
|
|
19243
|
+
headers: {
|
|
19244
|
+
...authHeaders,
|
|
19245
|
+
...taskTypeHeader(options.taskType),
|
|
19246
|
+
"Content-Type": "application/json"
|
|
19247
|
+
},
|
|
19248
|
+
body: buildBody(useResponseFormat),
|
|
19249
|
+
signal: controller.signal
|
|
19250
|
+
});
|
|
19251
|
+
} catch (err) {
|
|
19252
|
+
clearTimeout(timer);
|
|
19253
|
+
log.warn("[memory/reflect] portal request failed", {
|
|
19254
|
+
err: err instanceof Error ? err.message : String(err),
|
|
19255
|
+
baseUrl
|
|
19256
|
+
});
|
|
19257
|
+
return { kind: "error" };
|
|
19258
|
+
}
|
|
19204
19259
|
clearTimeout(timer);
|
|
19205
|
-
|
|
19206
|
-
|
|
19207
|
-
|
|
19260
|
+
if (!response.ok) {
|
|
19261
|
+
return { kind: "http", status: response.status, statusText: response.statusText };
|
|
19262
|
+
}
|
|
19263
|
+
const bodyTimer = setTimeout(() => controller.abort(), remaining());
|
|
19264
|
+
try {
|
|
19265
|
+
const body = await response.json();
|
|
19266
|
+
clearTimeout(bodyTimer);
|
|
19267
|
+
return { kind: "ok", body };
|
|
19268
|
+
} catch (err) {
|
|
19269
|
+
clearTimeout(bodyTimer);
|
|
19270
|
+
log.warn("[memory/reflect] failed to parse portal response body", {
|
|
19271
|
+
err: err instanceof Error ? err.message : String(err)
|
|
19272
|
+
});
|
|
19273
|
+
return { kind: "error" };
|
|
19274
|
+
}
|
|
19275
|
+
};
|
|
19276
|
+
let attempt = await sendOnce(sendResponseFormat);
|
|
19277
|
+
let schemaFallbackUsed = false;
|
|
19278
|
+
const budgetLeftMs = remaining();
|
|
19279
|
+
if (attempt.kind === "http" && sendResponseFormat && !SCHEMA_FALLBACK_SKIP_STATUSES.has(attempt.status) && budgetLeftMs >= MIN_RETRY_BUDGET_MS) {
|
|
19280
|
+
log.warn("[memory/reflect] response_format json_schema rejected; retrying schema-in-prompt", {
|
|
19281
|
+
status: attempt.status,
|
|
19282
|
+
statusText: attempt.statusText,
|
|
19283
|
+
model,
|
|
19284
|
+
taskType: options.taskType,
|
|
19285
|
+
budgetLeftMs
|
|
19208
19286
|
});
|
|
19209
|
-
|
|
19287
|
+
schemaFallbackUsed = true;
|
|
19288
|
+
attempt = await sendOnce(false);
|
|
19210
19289
|
}
|
|
19211
|
-
|
|
19212
|
-
if (
|
|
19290
|
+
if (attempt.kind === "error") return baseResult;
|
|
19291
|
+
if (attempt.kind === "http") {
|
|
19213
19292
|
log.warn("[memory/reflect] portal returned non-OK", {
|
|
19214
|
-
status:
|
|
19215
|
-
statusText:
|
|
19293
|
+
status: attempt.status,
|
|
19294
|
+
statusText: attempt.statusText,
|
|
19295
|
+
// Distinguishes "the fallback ran and still failed" from "never tried".
|
|
19296
|
+
schemaFallbackUsed
|
|
19216
19297
|
});
|
|
19217
19298
|
return baseResult;
|
|
19218
19299
|
}
|
|
19219
|
-
|
|
19220
|
-
let body;
|
|
19221
|
-
try {
|
|
19222
|
-
body = await response.json();
|
|
19223
|
-
} catch (err) {
|
|
19224
|
-
clearTimeout(bodyTimer);
|
|
19225
|
-
log.warn("[memory/reflect] failed to parse portal response body", {
|
|
19226
|
-
err: err instanceof Error ? err.message : String(err)
|
|
19227
|
-
});
|
|
19228
|
-
return baseResult;
|
|
19229
|
-
}
|
|
19230
|
-
clearTimeout(bodyTimer);
|
|
19231
|
-
return parseAnswer(body, baseResult, !!options.responseSchema);
|
|
19300
|
+
return parseAnswer(attempt.body, baseResult, !!options.responseSchema);
|
|
19232
19301
|
}
|
|
19233
19302
|
function parseAnswer(body, base, parseSchema) {
|
|
19234
19303
|
if (typeof body !== "object" || body === null) return base;
|
|
19235
19304
|
const obj = body;
|
|
19236
|
-
const
|
|
19237
|
-
let text12 = "";
|
|
19238
|
-
if (Array.isArray(choices) && choices.length > 0) {
|
|
19239
|
-
const message = choices[0].message;
|
|
19240
|
-
if (typeof message === "object" && message !== null) {
|
|
19241
|
-
const content = message.content;
|
|
19242
|
-
if (typeof content === "string") text12 = content;
|
|
19243
|
-
}
|
|
19244
|
-
}
|
|
19305
|
+
const text12 = extractCompletionContent(obj) ?? "";
|
|
19245
19306
|
const usage = obj.usage;
|
|
19246
19307
|
let structuredOutput;
|
|
19247
19308
|
if (parseSchema && text12) {
|
|
@@ -19253,14 +19314,19 @@ function parseAnswer(body, base, parseSchema) {
|
|
|
19253
19314
|
});
|
|
19254
19315
|
}
|
|
19255
19316
|
}
|
|
19317
|
+
const promptTokens = usage?.prompt_tokens ?? usage?.input_tokens ?? 0;
|
|
19318
|
+
const completionTokens = usage?.completion_tokens ?? usage?.output_tokens ?? 0;
|
|
19256
19319
|
return {
|
|
19257
19320
|
text: text12,
|
|
19258
19321
|
...structuredOutput !== void 0 && { structuredOutput },
|
|
19259
19322
|
basedOn: base.basedOn,
|
|
19260
19323
|
usage: {
|
|
19261
|
-
promptTokens
|
|
19262
|
-
completionTokens
|
|
19263
|
-
|
|
19324
|
+
promptTokens,
|
|
19325
|
+
completionTokens,
|
|
19326
|
+
// Derived when absent: the Responses API reports the two component counts
|
|
19327
|
+
// and does not always send a total, which would otherwise report zero
|
|
19328
|
+
// spend for a call that plainly cost something.
|
|
19329
|
+
totalTokens: usage?.total_tokens ?? promptTokens + completionTokens
|
|
19264
19330
|
}
|
|
19265
19331
|
};
|
|
19266
19332
|
}
|
|
@@ -23922,22 +23988,31 @@ function useChatStorage(options) {
|
|
|
23922
23988
|
}
|
|
23923
23989
|
})() : null;
|
|
23924
23990
|
let messagesToSend;
|
|
23925
|
-
const
|
|
23926
|
-
const knownToolCallEventIds = /* @__PURE__ */ new Set();
|
|
23927
|
-
for (const msg of storedMessages) {
|
|
23928
|
-
if (msg.toolCallEvents) {
|
|
23929
|
-
for (const evt of msg.toolCallEvents) {
|
|
23930
|
-
if (evt.id) knownToolCallEventIds.add(evt.id);
|
|
23931
|
-
}
|
|
23932
|
-
}
|
|
23933
|
-
}
|
|
23991
|
+
const knownToolCallEventIds = await getToolCallEventIdsOp(storageCtx, convId);
|
|
23934
23992
|
if (includeHistory) {
|
|
23935
|
-
|
|
23936
|
-
|
|
23937
|
-
|
|
23938
|
-
|
|
23939
|
-
|
|
23940
|
-
|
|
23993
|
+
let tail = [];
|
|
23994
|
+
let replayableMessages = [];
|
|
23995
|
+
let beforeMessageId;
|
|
23996
|
+
let boundaryExcludeUniqueIds;
|
|
23997
|
+
for (; ; ) {
|
|
23998
|
+
const page = await getMessagesPageOp(storageCtx, convId, {
|
|
23999
|
+
limit: maxHistoryMessages,
|
|
24000
|
+
beforeMessageId,
|
|
24001
|
+
boundaryExcludeUniqueIds
|
|
24002
|
+
});
|
|
24003
|
+
if (page.length === 0) break;
|
|
24004
|
+
tail = [...page, ...tail];
|
|
24005
|
+
const validMessages = tail.filter((msg) => !msg.error);
|
|
24006
|
+
replayableMessages = prepareToolResultsForReplay(validMessages, {
|
|
24007
|
+
fold: foldToolResultsInHistoryRef.current === true,
|
|
24008
|
+
exclude: toolResultsHistoryExcludeRef.current,
|
|
24009
|
+
placeholder: DISPLAY_CARD_PLACEHOLDER
|
|
24010
|
+
});
|
|
24011
|
+
if (replayableMessages.length >= maxHistoryMessages) break;
|
|
24012
|
+
if (page.length < maxHistoryMessages) break;
|
|
24013
|
+
beforeMessageId = page[0].messageId;
|
|
24014
|
+
boundaryExcludeUniqueIds = tail.filter((msg) => msg.messageId === beforeMessageId).map((msg) => msg.uniqueId);
|
|
24015
|
+
}
|
|
23941
24016
|
const limitedMessages = replayableMessages.slice(-maxHistoryMessages);
|
|
23942
24017
|
if (!fileContextForRequest) {
|
|
23943
24018
|
for (let i = limitedMessages.length - 1; i >= 0; i--) {
|