@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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
callPortalJsonCompletion,
|
|
3
3
|
getLogger
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-BSCEZOIW.mjs";
|
|
5
5
|
import {
|
|
6
6
|
BASE_URL,
|
|
7
7
|
__commonJS,
|
|
@@ -20923,7 +20923,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
20923
20923
|
subQueries = decomp.subQueries;
|
|
20924
20924
|
}
|
|
20925
20925
|
}
|
|
20926
|
-
const { recall: recall2 } = await import("./recall-
|
|
20926
|
+
const { recall: recall2 } = await import("./recall-OVSSDRYU.mjs");
|
|
20927
20927
|
let recallDegraded = [];
|
|
20928
20928
|
const result = await recall2(
|
|
20929
20929
|
query,
|
|
@@ -57,6 +57,34 @@ function supportsResponseFormat(model, variant = "json_object") {
|
|
|
57
57
|
const allow = variant === "json_schema" ? RESPONSE_SCHEMA_OK : RESPONSE_FORMAT_OK;
|
|
58
58
|
return model.split("/").some((seg) => allow.has(seg));
|
|
59
59
|
}
|
|
60
|
+
var RESPONSES_ONLY_MODEL_PREFIXES = ["gpt-5.6"];
|
|
61
|
+
function requiresResponsesTransport(model) {
|
|
62
|
+
return model.split("/").some((seg) => RESPONSES_ONLY_MODEL_PREFIXES.some((prefix) => seg.startsWith(prefix)));
|
|
63
|
+
}
|
|
64
|
+
var CHAT_TO_RESPONSES_FIELDS = {
|
|
65
|
+
max_completion_tokens: "max_output_tokens"
|
|
66
|
+
};
|
|
67
|
+
function responsesExtra(extra) {
|
|
68
|
+
if (!extra) return {};
|
|
69
|
+
const out = {};
|
|
70
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
71
|
+
const target = CHAT_TO_RESPONSES_FIELDS[key] ?? key;
|
|
72
|
+
if (target !== key && target in extra) continue;
|
|
73
|
+
out[target] = value;
|
|
74
|
+
}
|
|
75
|
+
return out;
|
|
76
|
+
}
|
|
77
|
+
var FOREIGN_ENDPOINT_SUFFIX = {
|
|
78
|
+
chat: "/responses",
|
|
79
|
+
responses: "/chat/completions"
|
|
80
|
+
};
|
|
81
|
+
function assertTransportMatchesEndpoint(transport, endpoint) {
|
|
82
|
+
const foreign = FOREIGN_ENDPOINT_SUFFIX[transport];
|
|
83
|
+
if (!endpoint.endsWith(foreign)) return;
|
|
84
|
+
throw new Error(
|
|
85
|
+
`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.`
|
|
86
|
+
);
|
|
87
|
+
}
|
|
60
88
|
var RETRYABLE_HTTP = /* @__PURE__ */ new Set([408, 409, 425, 429]);
|
|
61
89
|
function isRetryableStatus(status) {
|
|
62
90
|
return status >= 500 || RETRYABLE_HTTP.has(status);
|
|
@@ -98,13 +126,14 @@ async function resolvePortalAuthHeaders(auth, tag) {
|
|
|
98
126
|
}
|
|
99
127
|
async function callPortalJsonCompletion(req) {
|
|
100
128
|
const log = getLogger();
|
|
101
|
-
let endpoint = "/api/v1/chat/completions";
|
|
129
|
+
let endpoint = req.transport === "responses" ? "/api/v1/responses" : "/api/v1/chat/completions";
|
|
102
130
|
if (req.endpointOverride !== void 0) {
|
|
103
131
|
const overrideValidation = validateEndpointOverride(req.endpointOverride);
|
|
104
132
|
if (!overrideValidation.valid) {
|
|
105
133
|
throw new Error(overrideValidation.message);
|
|
106
134
|
}
|
|
107
135
|
endpoint = overrideValidation.endpoint;
|
|
136
|
+
assertTransportMatchesEndpoint(req.transport ?? "chat", endpoint);
|
|
108
137
|
}
|
|
109
138
|
const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
|
|
110
139
|
const startedAt = Date.now();
|
|
@@ -166,8 +195,8 @@ async function attemptPortalJson(req, endpoint) {
|
|
|
166
195
|
const authHeaders = await resolvePortalAuthHeaders(req, req.tag);
|
|
167
196
|
if (authHeaders === null)
|
|
168
197
|
return { kind: "terminal", code: "auth-unavailable", reason: "auth unavailable (no token)" };
|
|
169
|
-
const
|
|
170
|
-
const prefill =
|
|
198
|
+
const usesPrefill = req.transport !== "responses" && req.model.startsWith("anthropic/");
|
|
199
|
+
const prefill = usesPrefill ? "{" : "";
|
|
171
200
|
const messages = [
|
|
172
201
|
// Every caller of this helper is a first-party BACKGROUND op (fact extraction,
|
|
173
202
|
// topic sweep, consolidation, classifiers, graph traversal, query
|
|
@@ -186,13 +215,34 @@ async function attemptPortalJson(req, endpoint) {
|
|
|
186
215
|
const supportsJsonObjectFormat = supportsResponseFormat(req.model);
|
|
187
216
|
const controller = new AbortController();
|
|
188
217
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
189
|
-
const requestBody = {
|
|
218
|
+
const requestBody = req.transport === "responses" ? {
|
|
219
|
+
model: req.model,
|
|
220
|
+
// Same system+user pair under the Responses-API field name. No prefill
|
|
221
|
+
// entry to strip: `usesPrefill` is false on this transport, so it was
|
|
222
|
+
// never pushed and the response-side restore is disarmed with it. An
|
|
223
|
+
// earlier version pushed it and sliced it back off here, which left
|
|
224
|
+
// `prefill` truthy and the restore still armed — the fix belonged at
|
|
225
|
+
// the decision, not at the two symptoms.
|
|
226
|
+
input: messages,
|
|
227
|
+
...req.reasoning && { reasoning: req.reasoning },
|
|
228
|
+
// NO response_format. The Responses API spells structured output
|
|
229
|
+
// differently (`text.format`), and it is unverified against this
|
|
230
|
+
// portal — so this transport relies on the same strict-JSON system
|
|
231
|
+
// prompt plus `extractJsonCandidate` that every response_format-
|
|
232
|
+
// rejecting model already relies on. Verified end to end on dev:
|
|
233
|
+
// luna returns clean parseable JSON here without it. Add the field
|
|
234
|
+
// only with a per-provider check, exactly as RESPONSE_FORMAT_OK was
|
|
235
|
+
// earned.
|
|
236
|
+
...responsesExtra(req.extra)
|
|
237
|
+
} : {
|
|
190
238
|
model: req.model,
|
|
191
239
|
messages,
|
|
192
240
|
...supportsJsonObjectFormat && { response_format: { type: "json_object" } },
|
|
193
241
|
...req.extra
|
|
194
242
|
};
|
|
195
|
-
if (!supportsJsonObjectFormat)
|
|
243
|
+
if (req.transport === "responses" || !supportsJsonObjectFormat) {
|
|
244
|
+
delete requestBody.response_format;
|
|
245
|
+
}
|
|
196
246
|
let response;
|
|
197
247
|
try {
|
|
198
248
|
response = await fetchImpl(`${baseUrl}${endpoint}`, {
|
|
@@ -322,13 +372,15 @@ function logPortalUsage(body, tag) {
|
|
|
322
372
|
const root = asRecord(body);
|
|
323
373
|
if (!root) return;
|
|
324
374
|
const usage = asRecord(root.usage);
|
|
325
|
-
const promptTokens = asCount(usage?.prompt_tokens);
|
|
326
|
-
const completionTokens = asCount(usage?.completion_tokens);
|
|
375
|
+
const promptTokens = asCount(usage?.prompt_tokens) ?? asCount(usage?.input_tokens);
|
|
376
|
+
const completionTokens = asCount(usage?.completion_tokens) ?? asCount(usage?.output_tokens);
|
|
327
377
|
if (promptTokens === void 0 && completionTokens === void 0) return;
|
|
328
|
-
const cachedTokens = asCount(asRecord(root.portal)?.cached_tokens) ?? asCount(asRecord(usage?.prompt_tokens_details)?.cached_tokens) ?? 0;
|
|
378
|
+
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;
|
|
379
|
+
const reasoningTokens = asCount(asRecord(usage?.output_tokens_details)?.reasoning_tokens) ?? asCount(asRecord(usage?.completion_tokens_details)?.reasoning_tokens);
|
|
329
380
|
const parts = [];
|
|
330
381
|
if (promptTokens !== void 0) parts.push(`prompt=${promptTokens}`);
|
|
331
382
|
if (completionTokens !== void 0) parts.push(`completion=${completionTokens}`);
|
|
383
|
+
if (reasoningTokens !== void 0) parts.push(`reasoning=${reasoningTokens}`);
|
|
332
384
|
parts.push(`cached=${cachedTokens}`);
|
|
333
385
|
getLogger().debug(`[${tag}] usage ${parts.join(" ")}`);
|
|
334
386
|
} catch {
|
|
@@ -336,12 +388,22 @@ function logPortalUsage(body, tag) {
|
|
|
336
388
|
}
|
|
337
389
|
function extractCompletionContent(body) {
|
|
338
390
|
if (typeof body !== "object" || body === null) return null;
|
|
391
|
+
const responsesText = extractResponsesContent(body);
|
|
392
|
+
if (responsesText !== null) return responsesText;
|
|
339
393
|
const choices = body.choices;
|
|
340
394
|
if (!Array.isArray(choices) || choices.length === 0) return null;
|
|
341
395
|
const first = choices[0];
|
|
342
396
|
const content = first?.message?.content;
|
|
343
397
|
return typeof content === "string" ? content : null;
|
|
344
398
|
}
|
|
399
|
+
function extractResponsesContent(body) {
|
|
400
|
+
const root = asRecord(body);
|
|
401
|
+
if (!root) return null;
|
|
402
|
+
if (typeof root.output_text === "string" && root.output_text !== "") return root.output_text;
|
|
403
|
+
if (!Array.isArray(root.output)) return null;
|
|
404
|
+
const text = 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("");
|
|
405
|
+
return text;
|
|
406
|
+
}
|
|
345
407
|
|
|
346
408
|
export {
|
|
347
409
|
getLogger,
|
|
@@ -350,7 +412,9 @@ export {
|
|
|
350
412
|
taskTypeHeader,
|
|
351
413
|
validateEndpointOverride,
|
|
352
414
|
supportsResponseFormat,
|
|
415
|
+
requiresResponsesTransport,
|
|
353
416
|
resolvePortalAuthHeaders,
|
|
354
417
|
callPortalJsonCompletion,
|
|
355
|
-
extractJsonCandidate
|
|
418
|
+
extractJsonCandidate,
|
|
419
|
+
extractCompletionContent
|
|
356
420
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
notifyConsolidationFallback,
|
|
3
3
|
resolvePiiRedactor
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-4LPSEROP.mjs";
|
|
5
5
|
import {
|
|
6
6
|
callPortalJsonCompletion
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-BSCEZOIW.mjs";
|
|
8
8
|
import "./chunk-3RPGXXPZ.mjs";
|
|
9
9
|
|
|
10
10
|
// src/lib/memory/consolidate.ts
|
package/dist/server/index.cjs
CHANGED
|
@@ -20611,6 +20611,26 @@ function supportsResponseFormat(model, variant = "json_object") {
|
|
|
20611
20611
|
const allow = variant === "json_schema" ? RESPONSE_SCHEMA_OK : RESPONSE_FORMAT_OK;
|
|
20612
20612
|
return model.split("/").some((seg) => allow.has(seg));
|
|
20613
20613
|
}
|
|
20614
|
+
function requiresResponsesTransport(model) {
|
|
20615
|
+
return model.split("/").some((seg) => RESPONSES_ONLY_MODEL_PREFIXES.some((prefix) => seg.startsWith(prefix)));
|
|
20616
|
+
}
|
|
20617
|
+
function responsesExtra(extra) {
|
|
20618
|
+
if (!extra) return {};
|
|
20619
|
+
const out = {};
|
|
20620
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
20621
|
+
const target = CHAT_TO_RESPONSES_FIELDS[key] ?? key;
|
|
20622
|
+
if (target !== key && target in extra) continue;
|
|
20623
|
+
out[target] = value;
|
|
20624
|
+
}
|
|
20625
|
+
return out;
|
|
20626
|
+
}
|
|
20627
|
+
function assertTransportMatchesEndpoint(transport, endpoint) {
|
|
20628
|
+
const foreign = FOREIGN_ENDPOINT_SUFFIX[transport];
|
|
20629
|
+
if (!endpoint.endsWith(foreign)) return;
|
|
20630
|
+
throw new Error(
|
|
20631
|
+
`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.`
|
|
20632
|
+
);
|
|
20633
|
+
}
|
|
20614
20634
|
function isRetryableStatus(status) {
|
|
20615
20635
|
return status >= 500 || RETRYABLE_HTTP.has(status);
|
|
20616
20636
|
}
|
|
@@ -20651,13 +20671,14 @@ async function resolvePortalAuthHeaders(auth, tag) {
|
|
|
20651
20671
|
}
|
|
20652
20672
|
async function callPortalJsonCompletion(req) {
|
|
20653
20673
|
const log = getLogger();
|
|
20654
|
-
let endpoint = "/api/v1/chat/completions";
|
|
20674
|
+
let endpoint = req.transport === "responses" ? "/api/v1/responses" : "/api/v1/chat/completions";
|
|
20655
20675
|
if (req.endpointOverride !== void 0) {
|
|
20656
20676
|
const overrideValidation = validateEndpointOverride(req.endpointOverride);
|
|
20657
20677
|
if (!overrideValidation.valid) {
|
|
20658
20678
|
throw new Error(overrideValidation.message);
|
|
20659
20679
|
}
|
|
20660
20680
|
endpoint = overrideValidation.endpoint;
|
|
20681
|
+
assertTransportMatchesEndpoint(req.transport ?? "chat", endpoint);
|
|
20661
20682
|
}
|
|
20662
20683
|
const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
|
|
20663
20684
|
const startedAt = Date.now();
|
|
@@ -20719,8 +20740,8 @@ async function attemptPortalJson(req, endpoint) {
|
|
|
20719
20740
|
const authHeaders = await resolvePortalAuthHeaders(req, req.tag);
|
|
20720
20741
|
if (authHeaders === null)
|
|
20721
20742
|
return { kind: "terminal", code: "auth-unavailable", reason: "auth unavailable (no token)" };
|
|
20722
|
-
const
|
|
20723
|
-
const prefill =
|
|
20743
|
+
const usesPrefill = req.transport !== "responses" && req.model.startsWith("anthropic/");
|
|
20744
|
+
const prefill = usesPrefill ? "{" : "";
|
|
20724
20745
|
const messages = [
|
|
20725
20746
|
// Every caller of this helper is a first-party BACKGROUND op (fact extraction,
|
|
20726
20747
|
// topic sweep, consolidation, classifiers, graph traversal, query
|
|
@@ -20739,13 +20760,34 @@ async function attemptPortalJson(req, endpoint) {
|
|
|
20739
20760
|
const supportsJsonObjectFormat = supportsResponseFormat(req.model);
|
|
20740
20761
|
const controller = new AbortController();
|
|
20741
20762
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
20742
|
-
const requestBody = {
|
|
20763
|
+
const requestBody = req.transport === "responses" ? {
|
|
20764
|
+
model: req.model,
|
|
20765
|
+
// Same system+user pair under the Responses-API field name. No prefill
|
|
20766
|
+
// entry to strip: `usesPrefill` is false on this transport, so it was
|
|
20767
|
+
// never pushed and the response-side restore is disarmed with it. An
|
|
20768
|
+
// earlier version pushed it and sliced it back off here, which left
|
|
20769
|
+
// `prefill` truthy and the restore still armed — the fix belonged at
|
|
20770
|
+
// the decision, not at the two symptoms.
|
|
20771
|
+
input: messages,
|
|
20772
|
+
...req.reasoning && { reasoning: req.reasoning },
|
|
20773
|
+
// NO response_format. The Responses API spells structured output
|
|
20774
|
+
// differently (`text.format`), and it is unverified against this
|
|
20775
|
+
// portal — so this transport relies on the same strict-JSON system
|
|
20776
|
+
// prompt plus `extractJsonCandidate` that every response_format-
|
|
20777
|
+
// rejecting model already relies on. Verified end to end on dev:
|
|
20778
|
+
// luna returns clean parseable JSON here without it. Add the field
|
|
20779
|
+
// only with a per-provider check, exactly as RESPONSE_FORMAT_OK was
|
|
20780
|
+
// earned.
|
|
20781
|
+
...responsesExtra(req.extra)
|
|
20782
|
+
} : {
|
|
20743
20783
|
model: req.model,
|
|
20744
20784
|
messages,
|
|
20745
20785
|
...supportsJsonObjectFormat && { response_format: { type: "json_object" } },
|
|
20746
20786
|
...req.extra
|
|
20747
20787
|
};
|
|
20748
|
-
if (!supportsJsonObjectFormat)
|
|
20788
|
+
if (req.transport === "responses" || !supportsJsonObjectFormat) {
|
|
20789
|
+
delete requestBody.response_format;
|
|
20790
|
+
}
|
|
20749
20791
|
let response;
|
|
20750
20792
|
try {
|
|
20751
20793
|
response = await fetchImpl(`${baseUrl}${endpoint}`, {
|
|
@@ -20875,13 +20917,15 @@ function logPortalUsage(body, tag) {
|
|
|
20875
20917
|
const root = asRecord(body);
|
|
20876
20918
|
if (!root) return;
|
|
20877
20919
|
const usage = asRecord(root.usage);
|
|
20878
|
-
const promptTokens = asCount(usage?.prompt_tokens);
|
|
20879
|
-
const completionTokens = asCount(usage?.completion_tokens);
|
|
20920
|
+
const promptTokens = asCount(usage?.prompt_tokens) ?? asCount(usage?.input_tokens);
|
|
20921
|
+
const completionTokens = asCount(usage?.completion_tokens) ?? asCount(usage?.output_tokens);
|
|
20880
20922
|
if (promptTokens === void 0 && completionTokens === void 0) return;
|
|
20881
|
-
const cachedTokens = asCount(asRecord(root.portal)?.cached_tokens) ?? asCount(asRecord(usage?.prompt_tokens_details)?.cached_tokens) ?? 0;
|
|
20923
|
+
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;
|
|
20924
|
+
const reasoningTokens = asCount(asRecord(usage?.output_tokens_details)?.reasoning_tokens) ?? asCount(asRecord(usage?.completion_tokens_details)?.reasoning_tokens);
|
|
20882
20925
|
const parts = [];
|
|
20883
20926
|
if (promptTokens !== void 0) parts.push(`prompt=${promptTokens}`);
|
|
20884
20927
|
if (completionTokens !== void 0) parts.push(`completion=${completionTokens}`);
|
|
20928
|
+
if (reasoningTokens !== void 0) parts.push(`reasoning=${reasoningTokens}`);
|
|
20885
20929
|
parts.push(`cached=${cachedTokens}`);
|
|
20886
20930
|
getLogger().debug(`[${tag}] usage ${parts.join(" ")}`);
|
|
20887
20931
|
} catch {
|
|
@@ -20889,13 +20933,23 @@ function logPortalUsage(body, tag) {
|
|
|
20889
20933
|
}
|
|
20890
20934
|
function extractCompletionContent(body) {
|
|
20891
20935
|
if (typeof body !== "object" || body === null) return null;
|
|
20936
|
+
const responsesText = extractResponsesContent(body);
|
|
20937
|
+
if (responsesText !== null) return responsesText;
|
|
20892
20938
|
const choices = body.choices;
|
|
20893
20939
|
if (!Array.isArray(choices) || choices.length === 0) return null;
|
|
20894
20940
|
const first = choices[0];
|
|
20895
20941
|
const content = first?.message?.content;
|
|
20896
20942
|
return typeof content === "string" ? content : null;
|
|
20897
20943
|
}
|
|
20898
|
-
|
|
20944
|
+
function extractResponsesContent(body) {
|
|
20945
|
+
const root = asRecord(body);
|
|
20946
|
+
if (!root) return null;
|
|
20947
|
+
if (typeof root.output_text === "string" && root.output_text !== "") return root.output_text;
|
|
20948
|
+
if (!Array.isArray(root.output)) return null;
|
|
20949
|
+
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("");
|
|
20950
|
+
return text12;
|
|
20951
|
+
}
|
|
20952
|
+
var RESPONSE_FORMAT_OK, RESPONSE_SCHEMA_OK, JSON_CONTRACT_REMINDER, RESPONSES_ONLY_MODEL_PREFIXES, CHAT_TO_RESPONSES_FIELDS, FOREIGN_ENDPOINT_SUFFIX, RETRYABLE_HTTP;
|
|
20899
20953
|
var init_portalLlm = __esm({
|
|
20900
20954
|
"src/lib/memory/portalLlm.ts"() {
|
|
20901
20955
|
"use strict";
|
|
@@ -20907,6 +20961,14 @@ var init_portalLlm = __esm({
|
|
|
20907
20961
|
RESPONSE_FORMAT_OK = /* @__PURE__ */ new Set(["openai", "inclusionai", "deepseek"]);
|
|
20908
20962
|
RESPONSE_SCHEMA_OK = /* @__PURE__ */ new Set(["openai"]);
|
|
20909
20963
|
JSON_CONTRACT_REMINDER = "Output ONLY the strict JSON object requested. No prose, no explanation, no markdown.";
|
|
20964
|
+
RESPONSES_ONLY_MODEL_PREFIXES = ["gpt-5.6"];
|
|
20965
|
+
CHAT_TO_RESPONSES_FIELDS = {
|
|
20966
|
+
max_completion_tokens: "max_output_tokens"
|
|
20967
|
+
};
|
|
20968
|
+
FOREIGN_ENDPOINT_SUFFIX = {
|
|
20969
|
+
chat: "/responses",
|
|
20970
|
+
responses: "/chat/completions"
|
|
20971
|
+
};
|
|
20910
20972
|
RETRYABLE_HTTP = /* @__PURE__ */ new Set([408, 409, 425, 429]);
|
|
20911
20973
|
}
|
|
20912
20974
|
});
|
|
@@ -30675,6 +30737,9 @@ var DEFAULT_BASE_URL2 = BASE_URL;
|
|
|
30675
30737
|
var DEFAULT_MODEL4 = "anthropic/claude-sonnet-4-6";
|
|
30676
30738
|
var DEFAULT_MAX_TOKENS = 4096;
|
|
30677
30739
|
var REQUEST_TIMEOUT_MS = 6e4;
|
|
30740
|
+
var MIN_RETRY_BUDGET_MS = 2e3;
|
|
30741
|
+
var MIN_RESPONSES_OUTPUT_TOKENS = 2048;
|
|
30742
|
+
var SCHEMA_FALLBACK_SKIP_STATUSES = /* @__PURE__ */ new Set([401, 403, 404, 408, 409, 413, 425, 429]);
|
|
30678
30743
|
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.
|
|
30679
30744
|
|
|
30680
30745
|
Rules:
|
|
@@ -30706,14 +30771,9 @@ ${m.content}`).join("\n\n");
|
|
|
30706
30771
|
const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL2;
|
|
30707
30772
|
const model = options.llmModel ?? DEFAULT_MODEL4;
|
|
30708
30773
|
const wantsStructured = !!options.responseSchema;
|
|
30709
|
-
const
|
|
30774
|
+
const useResponsesTransport = requiresResponsesTransport(model);
|
|
30775
|
+
const sendResponseFormat = wantsStructured && !useResponsesTransport && supportsResponseFormat(model, "json_schema");
|
|
30710
30776
|
const basePrompt = options.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;
|
|
30711
|
-
const systemPrompt = wantsStructured && !sendResponseFormat ? `${basePrompt}
|
|
30712
|
-
|
|
30713
|
-
Respond with ONLY a single JSON object conforming to this JSON Schema, with no prose, comments, or code fences:
|
|
30714
|
-
${JSON.stringify(
|
|
30715
|
-
options.responseSchema
|
|
30716
|
-
)}` : basePrompt;
|
|
30717
30777
|
const userMessage = [
|
|
30718
30778
|
`Question:
|
|
30719
30779
|
${trimmed}`,
|
|
@@ -30723,85 +30783,121 @@ ${evidence}`
|
|
|
30723
30783
|
].join("\n\n");
|
|
30724
30784
|
const maxTokens = options.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
30725
30785
|
const fetchImpl = options.fetchFn ?? fetch;
|
|
30786
|
+
const buildBody = (useResponseFormat) => {
|
|
30787
|
+
const systemPrompt = wantsStructured && !useResponseFormat ? `${basePrompt}
|
|
30788
|
+
|
|
30789
|
+
Respond with ONLY a single JSON object conforming to this JSON Schema, with no prose, comments, or code fences:
|
|
30790
|
+
${JSON.stringify(
|
|
30791
|
+
options.responseSchema
|
|
30792
|
+
)}` : basePrompt;
|
|
30793
|
+
const messages = [
|
|
30794
|
+
{ role: "system", content: systemPrompt },
|
|
30795
|
+
{ role: "user", content: userMessage }
|
|
30796
|
+
];
|
|
30797
|
+
if (useResponsesTransport) {
|
|
30798
|
+
return JSON.stringify({
|
|
30799
|
+
model,
|
|
30800
|
+
// Same system+user pair under the Responses-API field names: `input`
|
|
30801
|
+
// for the turns, `max_output_tokens` for the cap. Sending the
|
|
30802
|
+
// chat-completions spelling here is silently ignored, which caps the
|
|
30803
|
+
// answer at the portal default.
|
|
30804
|
+
input: messages,
|
|
30805
|
+
max_output_tokens: Math.max(maxTokens, MIN_RESPONSES_OUTPUT_TOKENS)
|
|
30806
|
+
});
|
|
30807
|
+
}
|
|
30808
|
+
return JSON.stringify({
|
|
30809
|
+
model,
|
|
30810
|
+
// Modern OpenAI field; the portal reads only `max_completion_tokens`
|
|
30811
|
+
// (the deprecated `max_tokens` is silently ignored → falls back to the
|
|
30812
|
+
// portal's default output cap and truncates the answer).
|
|
30813
|
+
max_completion_tokens: maxTokens,
|
|
30814
|
+
messages,
|
|
30815
|
+
...useResponseFormat && {
|
|
30816
|
+
response_format: {
|
|
30817
|
+
type: "json_schema",
|
|
30818
|
+
json_schema: { name: "reflect_output", schema: options.responseSchema }
|
|
30819
|
+
}
|
|
30820
|
+
}
|
|
30821
|
+
});
|
|
30822
|
+
};
|
|
30726
30823
|
const log = getLogger();
|
|
30727
30824
|
const authHeaders = await resolvePortalAuthHeaders(options, "memory/reflect");
|
|
30728
30825
|
if (authHeaders === null) return baseResult;
|
|
30729
|
-
const controller = new AbortController();
|
|
30730
30826
|
const deadline = Date.now() + REQUEST_TIMEOUT_MS;
|
|
30731
30827
|
const remaining = () => Math.max(0, deadline - Date.now());
|
|
30732
|
-
const
|
|
30733
|
-
|
|
30734
|
-
|
|
30735
|
-
|
|
30736
|
-
|
|
30737
|
-
|
|
30738
|
-
|
|
30739
|
-
|
|
30740
|
-
|
|
30741
|
-
|
|
30742
|
-
|
|
30743
|
-
|
|
30744
|
-
|
|
30745
|
-
|
|
30746
|
-
|
|
30747
|
-
|
|
30748
|
-
|
|
30749
|
-
|
|
30750
|
-
|
|
30751
|
-
|
|
30752
|
-
|
|
30753
|
-
|
|
30754
|
-
|
|
30755
|
-
|
|
30756
|
-
|
|
30757
|
-
|
|
30758
|
-
}
|
|
30759
|
-
}
|
|
30760
|
-
}),
|
|
30761
|
-
signal: controller.signal
|
|
30762
|
-
});
|
|
30763
|
-
} catch (err) {
|
|
30828
|
+
const endpoint = useResponsesTransport ? "/api/v1/responses" : "/api/v1/chat/completions";
|
|
30829
|
+
const sendOnce = async (useResponseFormat) => {
|
|
30830
|
+
const controller = new AbortController();
|
|
30831
|
+
const timer = setTimeout(() => controller.abort(), remaining());
|
|
30832
|
+
let response;
|
|
30833
|
+
try {
|
|
30834
|
+
response = await fetchImpl(`${baseUrl}${endpoint}`, {
|
|
30835
|
+
method: "POST",
|
|
30836
|
+
// No task type unless the caller named one — an undeclared task adds no
|
|
30837
|
+
// header at all, which is what keeps user-facing reflect() unlabelled.
|
|
30838
|
+
headers: {
|
|
30839
|
+
...authHeaders,
|
|
30840
|
+
...taskTypeHeader(options.taskType),
|
|
30841
|
+
"Content-Type": "application/json"
|
|
30842
|
+
},
|
|
30843
|
+
body: buildBody(useResponseFormat),
|
|
30844
|
+
signal: controller.signal
|
|
30845
|
+
});
|
|
30846
|
+
} catch (err) {
|
|
30847
|
+
clearTimeout(timer);
|
|
30848
|
+
log.warn("[memory/reflect] portal request failed", {
|
|
30849
|
+
err: err instanceof Error ? err.message : String(err),
|
|
30850
|
+
baseUrl
|
|
30851
|
+
});
|
|
30852
|
+
return { kind: "error" };
|
|
30853
|
+
}
|
|
30764
30854
|
clearTimeout(timer);
|
|
30765
|
-
|
|
30766
|
-
|
|
30767
|
-
|
|
30855
|
+
if (!response.ok) {
|
|
30856
|
+
return { kind: "http", status: response.status, statusText: response.statusText };
|
|
30857
|
+
}
|
|
30858
|
+
const bodyTimer = setTimeout(() => controller.abort(), remaining());
|
|
30859
|
+
try {
|
|
30860
|
+
const body = await response.json();
|
|
30861
|
+
clearTimeout(bodyTimer);
|
|
30862
|
+
return { kind: "ok", body };
|
|
30863
|
+
} catch (err) {
|
|
30864
|
+
clearTimeout(bodyTimer);
|
|
30865
|
+
log.warn("[memory/reflect] failed to parse portal response body", {
|
|
30866
|
+
err: err instanceof Error ? err.message : String(err)
|
|
30867
|
+
});
|
|
30868
|
+
return { kind: "error" };
|
|
30869
|
+
}
|
|
30870
|
+
};
|
|
30871
|
+
let attempt = await sendOnce(sendResponseFormat);
|
|
30872
|
+
let schemaFallbackUsed = false;
|
|
30873
|
+
const budgetLeftMs = remaining();
|
|
30874
|
+
if (attempt.kind === "http" && sendResponseFormat && !SCHEMA_FALLBACK_SKIP_STATUSES.has(attempt.status) && budgetLeftMs >= MIN_RETRY_BUDGET_MS) {
|
|
30875
|
+
log.warn("[memory/reflect] response_format json_schema rejected; retrying schema-in-prompt", {
|
|
30876
|
+
status: attempt.status,
|
|
30877
|
+
statusText: attempt.statusText,
|
|
30878
|
+
model,
|
|
30879
|
+
taskType: options.taskType,
|
|
30880
|
+
budgetLeftMs
|
|
30768
30881
|
});
|
|
30769
|
-
|
|
30882
|
+
schemaFallbackUsed = true;
|
|
30883
|
+
attempt = await sendOnce(false);
|
|
30770
30884
|
}
|
|
30771
|
-
|
|
30772
|
-
if (
|
|
30885
|
+
if (attempt.kind === "error") return baseResult;
|
|
30886
|
+
if (attempt.kind === "http") {
|
|
30773
30887
|
log.warn("[memory/reflect] portal returned non-OK", {
|
|
30774
|
-
status:
|
|
30775
|
-
statusText:
|
|
30888
|
+
status: attempt.status,
|
|
30889
|
+
statusText: attempt.statusText,
|
|
30890
|
+
// Distinguishes "the fallback ran and still failed" from "never tried".
|
|
30891
|
+
schemaFallbackUsed
|
|
30776
30892
|
});
|
|
30777
30893
|
return baseResult;
|
|
30778
30894
|
}
|
|
30779
|
-
|
|
30780
|
-
let body;
|
|
30781
|
-
try {
|
|
30782
|
-
body = await response.json();
|
|
30783
|
-
} catch (err) {
|
|
30784
|
-
clearTimeout(bodyTimer);
|
|
30785
|
-
log.warn("[memory/reflect] failed to parse portal response body", {
|
|
30786
|
-
err: err instanceof Error ? err.message : String(err)
|
|
30787
|
-
});
|
|
30788
|
-
return baseResult;
|
|
30789
|
-
}
|
|
30790
|
-
clearTimeout(bodyTimer);
|
|
30791
|
-
return parseAnswer(body, baseResult, !!options.responseSchema);
|
|
30895
|
+
return parseAnswer(attempt.body, baseResult, !!options.responseSchema);
|
|
30792
30896
|
}
|
|
30793
30897
|
function parseAnswer(body, base, parseSchema) {
|
|
30794
30898
|
if (typeof body !== "object" || body === null) return base;
|
|
30795
30899
|
const obj = body;
|
|
30796
|
-
const
|
|
30797
|
-
let text12 = "";
|
|
30798
|
-
if (Array.isArray(choices) && choices.length > 0) {
|
|
30799
|
-
const message = choices[0].message;
|
|
30800
|
-
if (typeof message === "object" && message !== null) {
|
|
30801
|
-
const content = message.content;
|
|
30802
|
-
if (typeof content === "string") text12 = content;
|
|
30803
|
-
}
|
|
30804
|
-
}
|
|
30900
|
+
const text12 = extractCompletionContent(obj) ?? "";
|
|
30805
30901
|
const usage = obj.usage;
|
|
30806
30902
|
let structuredOutput;
|
|
30807
30903
|
if (parseSchema && text12) {
|
|
@@ -30813,14 +30909,19 @@ function parseAnswer(body, base, parseSchema) {
|
|
|
30813
30909
|
});
|
|
30814
30910
|
}
|
|
30815
30911
|
}
|
|
30912
|
+
const promptTokens = usage?.prompt_tokens ?? usage?.input_tokens ?? 0;
|
|
30913
|
+
const completionTokens = usage?.completion_tokens ?? usage?.output_tokens ?? 0;
|
|
30816
30914
|
return {
|
|
30817
30915
|
text: text12,
|
|
30818
30916
|
...structuredOutput !== void 0 && { structuredOutput },
|
|
30819
30917
|
basedOn: base.basedOn,
|
|
30820
30918
|
usage: {
|
|
30821
|
-
promptTokens
|
|
30822
|
-
completionTokens
|
|
30823
|
-
|
|
30919
|
+
promptTokens,
|
|
30920
|
+
completionTokens,
|
|
30921
|
+
// Derived when absent: the Responses API reports the two component counts
|
|
30922
|
+
// and does not always send a total, which would otherwise report zero
|
|
30923
|
+
// spend for a call that plainly cost something.
|
|
30924
|
+
totalTokens: usage?.total_tokens ?? promptTokens + completionTokens
|
|
30824
30925
|
}
|
|
30825
30926
|
};
|
|
30826
30927
|
}
|