@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
|
@@ -70,6 +70,34 @@ function supportsResponseFormat(model, variant = "json_object") {
|
|
|
70
70
|
const allow = variant === "json_schema" ? RESPONSE_SCHEMA_OK : RESPONSE_FORMAT_OK;
|
|
71
71
|
return model.split("/").some((seg) => allow.has(seg));
|
|
72
72
|
}
|
|
73
|
+
var RESPONSES_ONLY_MODEL_PREFIXES = ["gpt-5.6"];
|
|
74
|
+
function requiresResponsesTransport(model) {
|
|
75
|
+
return model.split("/").some((seg) => RESPONSES_ONLY_MODEL_PREFIXES.some((prefix) => seg.startsWith(prefix)));
|
|
76
|
+
}
|
|
77
|
+
var CHAT_TO_RESPONSES_FIELDS = {
|
|
78
|
+
max_completion_tokens: "max_output_tokens"
|
|
79
|
+
};
|
|
80
|
+
function responsesExtra(extra) {
|
|
81
|
+
if (!extra) return {};
|
|
82
|
+
const out = {};
|
|
83
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
84
|
+
const target = CHAT_TO_RESPONSES_FIELDS[key] ?? key;
|
|
85
|
+
if (target !== key && target in extra) continue;
|
|
86
|
+
out[target] = value;
|
|
87
|
+
}
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
var FOREIGN_ENDPOINT_SUFFIX = {
|
|
91
|
+
chat: "/responses",
|
|
92
|
+
responses: "/chat/completions"
|
|
93
|
+
};
|
|
94
|
+
function assertTransportMatchesEndpoint(transport, endpoint) {
|
|
95
|
+
const foreign = FOREIGN_ENDPOINT_SUFFIX[transport];
|
|
96
|
+
if (!endpoint.endsWith(foreign)) return;
|
|
97
|
+
throw new Error(
|
|
98
|
+
`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.`
|
|
99
|
+
);
|
|
100
|
+
}
|
|
73
101
|
var RETRYABLE_HTTP = /* @__PURE__ */ new Set([408, 409, 425, 429]);
|
|
74
102
|
function isRetryableStatus(status) {
|
|
75
103
|
return status >= 500 || RETRYABLE_HTTP.has(status);
|
|
@@ -111,13 +139,14 @@ async function resolvePortalAuthHeaders(auth, tag) {
|
|
|
111
139
|
}
|
|
112
140
|
async function callPortalJsonCompletion(req) {
|
|
113
141
|
const log = getLogger();
|
|
114
|
-
let endpoint = "/api/v1/chat/completions";
|
|
142
|
+
let endpoint = req.transport === "responses" ? "/api/v1/responses" : "/api/v1/chat/completions";
|
|
115
143
|
if (req.endpointOverride !== void 0) {
|
|
116
144
|
const overrideValidation = validateEndpointOverride(req.endpointOverride);
|
|
117
145
|
if (!overrideValidation.valid) {
|
|
118
146
|
throw new Error(overrideValidation.message);
|
|
119
147
|
}
|
|
120
148
|
endpoint = overrideValidation.endpoint;
|
|
149
|
+
assertTransportMatchesEndpoint(req.transport ?? "chat", endpoint);
|
|
121
150
|
}
|
|
122
151
|
const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
|
|
123
152
|
const startedAt = Date.now();
|
|
@@ -179,8 +208,8 @@ async function attemptPortalJson(req, endpoint) {
|
|
|
179
208
|
const authHeaders = await resolvePortalAuthHeaders(req, req.tag);
|
|
180
209
|
if (authHeaders === null)
|
|
181
210
|
return { kind: "terminal", code: "auth-unavailable", reason: "auth unavailable (no token)" };
|
|
182
|
-
const
|
|
183
|
-
const prefill =
|
|
211
|
+
const usesPrefill = req.transport !== "responses" && req.model.startsWith("anthropic/");
|
|
212
|
+
const prefill = usesPrefill ? "{" : "";
|
|
184
213
|
const messages = [
|
|
185
214
|
// Every caller of this helper is a first-party BACKGROUND op (fact extraction,
|
|
186
215
|
// topic sweep, consolidation, classifiers, graph traversal, query
|
|
@@ -199,13 +228,34 @@ async function attemptPortalJson(req, endpoint) {
|
|
|
199
228
|
const supportsJsonObjectFormat = supportsResponseFormat(req.model);
|
|
200
229
|
const controller = new AbortController();
|
|
201
230
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
202
|
-
const requestBody = {
|
|
231
|
+
const requestBody = req.transport === "responses" ? {
|
|
232
|
+
model: req.model,
|
|
233
|
+
// Same system+user pair under the Responses-API field name. No prefill
|
|
234
|
+
// entry to strip: `usesPrefill` is false on this transport, so it was
|
|
235
|
+
// never pushed and the response-side restore is disarmed with it. An
|
|
236
|
+
// earlier version pushed it and sliced it back off here, which left
|
|
237
|
+
// `prefill` truthy and the restore still armed — the fix belonged at
|
|
238
|
+
// the decision, not at the two symptoms.
|
|
239
|
+
input: messages,
|
|
240
|
+
...req.reasoning && { reasoning: req.reasoning },
|
|
241
|
+
// NO response_format. The Responses API spells structured output
|
|
242
|
+
// differently (`text.format`), and it is unverified against this
|
|
243
|
+
// portal — so this transport relies on the same strict-JSON system
|
|
244
|
+
// prompt plus `extractJsonCandidate` that every response_format-
|
|
245
|
+
// rejecting model already relies on. Verified end to end on dev:
|
|
246
|
+
// luna returns clean parseable JSON here without it. Add the field
|
|
247
|
+
// only with a per-provider check, exactly as RESPONSE_FORMAT_OK was
|
|
248
|
+
// earned.
|
|
249
|
+
...responsesExtra(req.extra)
|
|
250
|
+
} : {
|
|
203
251
|
model: req.model,
|
|
204
252
|
messages,
|
|
205
253
|
...supportsJsonObjectFormat && { response_format: { type: "json_object" } },
|
|
206
254
|
...req.extra
|
|
207
255
|
};
|
|
208
|
-
if (!supportsJsonObjectFormat)
|
|
256
|
+
if (req.transport === "responses" || !supportsJsonObjectFormat) {
|
|
257
|
+
delete requestBody.response_format;
|
|
258
|
+
}
|
|
209
259
|
let response;
|
|
210
260
|
try {
|
|
211
261
|
response = await fetchImpl(`${baseUrl}${endpoint}`, {
|
|
@@ -335,13 +385,15 @@ function logPortalUsage(body, tag) {
|
|
|
335
385
|
const root = asRecord(body);
|
|
336
386
|
if (!root) return;
|
|
337
387
|
const usage = asRecord(root.usage);
|
|
338
|
-
const promptTokens = asCount(usage?.prompt_tokens);
|
|
339
|
-
const completionTokens = asCount(usage?.completion_tokens);
|
|
388
|
+
const promptTokens = asCount(usage?.prompt_tokens) ?? asCount(usage?.input_tokens);
|
|
389
|
+
const completionTokens = asCount(usage?.completion_tokens) ?? asCount(usage?.output_tokens);
|
|
340
390
|
if (promptTokens === void 0 && completionTokens === void 0) return;
|
|
341
|
-
const cachedTokens = asCount(asRecord(root.portal)?.cached_tokens) ?? asCount(asRecord(usage?.prompt_tokens_details)?.cached_tokens) ?? 0;
|
|
391
|
+
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;
|
|
392
|
+
const reasoningTokens = asCount(asRecord(usage?.output_tokens_details)?.reasoning_tokens) ?? asCount(asRecord(usage?.completion_tokens_details)?.reasoning_tokens);
|
|
342
393
|
const parts = [];
|
|
343
394
|
if (promptTokens !== void 0) parts.push(`prompt=${promptTokens}`);
|
|
344
395
|
if (completionTokens !== void 0) parts.push(`completion=${completionTokens}`);
|
|
396
|
+
if (reasoningTokens !== void 0) parts.push(`reasoning=${reasoningTokens}`);
|
|
345
397
|
parts.push(`cached=${cachedTokens}`);
|
|
346
398
|
getLogger().debug(`[${tag}] usage ${parts.join(" ")}`);
|
|
347
399
|
} catch {
|
|
@@ -349,12 +401,22 @@ function logPortalUsage(body, tag) {
|
|
|
349
401
|
}
|
|
350
402
|
function extractCompletionContent(body) {
|
|
351
403
|
if (typeof body !== "object" || body === null) return null;
|
|
404
|
+
const responsesText = extractResponsesContent(body);
|
|
405
|
+
if (responsesText !== null) return responsesText;
|
|
352
406
|
const choices = body.choices;
|
|
353
407
|
if (!Array.isArray(choices) || choices.length === 0) return null;
|
|
354
408
|
const first = choices[0];
|
|
355
409
|
const content = first?.message?.content;
|
|
356
410
|
return typeof content === "string" ? content : null;
|
|
357
411
|
}
|
|
412
|
+
function extractResponsesContent(body) {
|
|
413
|
+
const root = asRecord(body);
|
|
414
|
+
if (!root) return null;
|
|
415
|
+
if (typeof root.output_text === "string" && root.output_text !== "") return root.output_text;
|
|
416
|
+
if (!Array.isArray(root.output)) return null;
|
|
417
|
+
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("");
|
|
418
|
+
return text;
|
|
419
|
+
}
|
|
358
420
|
|
|
359
421
|
export {
|
|
360
422
|
consoleLogger,
|
|
@@ -366,7 +428,9 @@ export {
|
|
|
366
428
|
withInternalFlowMarker,
|
|
367
429
|
taskTypeHeader,
|
|
368
430
|
supportsResponseFormat,
|
|
431
|
+
requiresResponsesTransport,
|
|
369
432
|
resolvePortalAuthHeaders,
|
|
370
433
|
callPortalJsonCompletion,
|
|
371
|
-
extractJsonCandidate
|
|
434
|
+
extractJsonCandidate,
|
|
435
|
+
extractCompletionContent
|
|
372
436
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
callPortalJsonCompletion,
|
|
3
3
|
getLogger
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-4Z2X4UYQ.mjs";
|
|
5
5
|
import {
|
|
6
6
|
BASE_URL,
|
|
7
7
|
createClientConfig
|
|
@@ -6885,7 +6885,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
6885
6885
|
subQueries = decomp.subQueries;
|
|
6886
6886
|
}
|
|
6887
6887
|
}
|
|
6888
|
-
const { recall: recall2 } = await import("./recall-
|
|
6888
|
+
const { recall: recall2 } = await import("./recall-FJQTIMYT.mjs");
|
|
6889
6889
|
let recallDegraded = [];
|
|
6890
6890
|
const result = await recall2(
|
|
6891
6891
|
query,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
notifyConsolidationFallback,
|
|
3
3
|
resolvePiiRedactor
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-A2G6TRUK.mjs";
|
|
5
5
|
import {
|
|
6
6
|
callPortalJsonCompletion
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-4Z2X4UYQ.mjs";
|
|
8
8
|
import "./chunk-GYKJOWEO.mjs";
|
|
9
9
|
|
|
10
10
|
// src/lib/memory/consolidate.ts
|
package/dist/expo/index.cjs
CHANGED
|
@@ -6145,6 +6145,26 @@ function supportsResponseFormat(model, variant = "json_object") {
|
|
|
6145
6145
|
const allow = variant === "json_schema" ? RESPONSE_SCHEMA_OK : RESPONSE_FORMAT_OK;
|
|
6146
6146
|
return model.split("/").some((seg) => allow.has(seg));
|
|
6147
6147
|
}
|
|
6148
|
+
function requiresResponsesTransport(model) {
|
|
6149
|
+
return model.split("/").some((seg) => RESPONSES_ONLY_MODEL_PREFIXES.some((prefix) => seg.startsWith(prefix)));
|
|
6150
|
+
}
|
|
6151
|
+
function responsesExtra(extra) {
|
|
6152
|
+
if (!extra) return {};
|
|
6153
|
+
const out = {};
|
|
6154
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
6155
|
+
const target = CHAT_TO_RESPONSES_FIELDS[key] ?? key;
|
|
6156
|
+
if (target !== key && target in extra) continue;
|
|
6157
|
+
out[target] = value;
|
|
6158
|
+
}
|
|
6159
|
+
return out;
|
|
6160
|
+
}
|
|
6161
|
+
function assertTransportMatchesEndpoint(transport, endpoint) {
|
|
6162
|
+
const foreign = FOREIGN_ENDPOINT_SUFFIX[transport];
|
|
6163
|
+
if (!endpoint.endsWith(foreign)) return;
|
|
6164
|
+
throw new Error(
|
|
6165
|
+
`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.`
|
|
6166
|
+
);
|
|
6167
|
+
}
|
|
6148
6168
|
function isRetryableStatus(status) {
|
|
6149
6169
|
return status >= 500 || RETRYABLE_HTTP.has(status);
|
|
6150
6170
|
}
|
|
@@ -6185,13 +6205,14 @@ async function resolvePortalAuthHeaders(auth, tag) {
|
|
|
6185
6205
|
}
|
|
6186
6206
|
async function callPortalJsonCompletion(req) {
|
|
6187
6207
|
const log = getLogger();
|
|
6188
|
-
let endpoint = "/api/v1/chat/completions";
|
|
6208
|
+
let endpoint = req.transport === "responses" ? "/api/v1/responses" : "/api/v1/chat/completions";
|
|
6189
6209
|
if (req.endpointOverride !== void 0) {
|
|
6190
6210
|
const overrideValidation = validateEndpointOverride(req.endpointOverride);
|
|
6191
6211
|
if (!overrideValidation.valid) {
|
|
6192
6212
|
throw new Error(overrideValidation.message);
|
|
6193
6213
|
}
|
|
6194
6214
|
endpoint = overrideValidation.endpoint;
|
|
6215
|
+
assertTransportMatchesEndpoint(req.transport ?? "chat", endpoint);
|
|
6195
6216
|
}
|
|
6196
6217
|
const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
|
|
6197
6218
|
const startedAt = Date.now();
|
|
@@ -6253,8 +6274,8 @@ async function attemptPortalJson(req, endpoint) {
|
|
|
6253
6274
|
const authHeaders = await resolvePortalAuthHeaders(req, req.tag);
|
|
6254
6275
|
if (authHeaders === null)
|
|
6255
6276
|
return { kind: "terminal", code: "auth-unavailable", reason: "auth unavailable (no token)" };
|
|
6256
|
-
const
|
|
6257
|
-
const prefill =
|
|
6277
|
+
const usesPrefill = req.transport !== "responses" && req.model.startsWith("anthropic/");
|
|
6278
|
+
const prefill = usesPrefill ? "{" : "";
|
|
6258
6279
|
const messages = [
|
|
6259
6280
|
// Every caller of this helper is a first-party BACKGROUND op (fact extraction,
|
|
6260
6281
|
// topic sweep, consolidation, classifiers, graph traversal, query
|
|
@@ -6273,13 +6294,34 @@ async function attemptPortalJson(req, endpoint) {
|
|
|
6273
6294
|
const supportsJsonObjectFormat = supportsResponseFormat(req.model);
|
|
6274
6295
|
const controller = new AbortController();
|
|
6275
6296
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
6276
|
-
const requestBody = {
|
|
6297
|
+
const requestBody = req.transport === "responses" ? {
|
|
6298
|
+
model: req.model,
|
|
6299
|
+
// Same system+user pair under the Responses-API field name. No prefill
|
|
6300
|
+
// entry to strip: `usesPrefill` is false on this transport, so it was
|
|
6301
|
+
// never pushed and the response-side restore is disarmed with it. An
|
|
6302
|
+
// earlier version pushed it and sliced it back off here, which left
|
|
6303
|
+
// `prefill` truthy and the restore still armed — the fix belonged at
|
|
6304
|
+
// the decision, not at the two symptoms.
|
|
6305
|
+
input: messages,
|
|
6306
|
+
...req.reasoning && { reasoning: req.reasoning },
|
|
6307
|
+
// NO response_format. The Responses API spells structured output
|
|
6308
|
+
// differently (`text.format`), and it is unverified against this
|
|
6309
|
+
// portal — so this transport relies on the same strict-JSON system
|
|
6310
|
+
// prompt plus `extractJsonCandidate` that every response_format-
|
|
6311
|
+
// rejecting model already relies on. Verified end to end on dev:
|
|
6312
|
+
// luna returns clean parseable JSON here without it. Add the field
|
|
6313
|
+
// only with a per-provider check, exactly as RESPONSE_FORMAT_OK was
|
|
6314
|
+
// earned.
|
|
6315
|
+
...responsesExtra(req.extra)
|
|
6316
|
+
} : {
|
|
6277
6317
|
model: req.model,
|
|
6278
6318
|
messages,
|
|
6279
6319
|
...supportsJsonObjectFormat && { response_format: { type: "json_object" } },
|
|
6280
6320
|
...req.extra
|
|
6281
6321
|
};
|
|
6282
|
-
if (!supportsJsonObjectFormat)
|
|
6322
|
+
if (req.transport === "responses" || !supportsJsonObjectFormat) {
|
|
6323
|
+
delete requestBody.response_format;
|
|
6324
|
+
}
|
|
6283
6325
|
let response;
|
|
6284
6326
|
try {
|
|
6285
6327
|
response = await fetchImpl(`${baseUrl}${endpoint}`, {
|
|
@@ -6409,13 +6451,15 @@ function logPortalUsage(body, tag) {
|
|
|
6409
6451
|
const root = asRecord(body);
|
|
6410
6452
|
if (!root) return;
|
|
6411
6453
|
const usage = asRecord(root.usage);
|
|
6412
|
-
const promptTokens = asCount(usage?.prompt_tokens);
|
|
6413
|
-
const completionTokens = asCount(usage?.completion_tokens);
|
|
6454
|
+
const promptTokens = asCount(usage?.prompt_tokens) ?? asCount(usage?.input_tokens);
|
|
6455
|
+
const completionTokens = asCount(usage?.completion_tokens) ?? asCount(usage?.output_tokens);
|
|
6414
6456
|
if (promptTokens === void 0 && completionTokens === void 0) return;
|
|
6415
|
-
const cachedTokens = asCount(asRecord(root.portal)?.cached_tokens) ?? asCount(asRecord(usage?.prompt_tokens_details)?.cached_tokens) ?? 0;
|
|
6457
|
+
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;
|
|
6458
|
+
const reasoningTokens = asCount(asRecord(usage?.output_tokens_details)?.reasoning_tokens) ?? asCount(asRecord(usage?.completion_tokens_details)?.reasoning_tokens);
|
|
6416
6459
|
const parts = [];
|
|
6417
6460
|
if (promptTokens !== void 0) parts.push(`prompt=${promptTokens}`);
|
|
6418
6461
|
if (completionTokens !== void 0) parts.push(`completion=${completionTokens}`);
|
|
6462
|
+
if (reasoningTokens !== void 0) parts.push(`reasoning=${reasoningTokens}`);
|
|
6419
6463
|
parts.push(`cached=${cachedTokens}`);
|
|
6420
6464
|
getLogger().debug(`[${tag}] usage ${parts.join(" ")}`);
|
|
6421
6465
|
} catch {
|
|
@@ -6423,13 +6467,23 @@ function logPortalUsage(body, tag) {
|
|
|
6423
6467
|
}
|
|
6424
6468
|
function extractCompletionContent(body) {
|
|
6425
6469
|
if (typeof body !== "object" || body === null) return null;
|
|
6470
|
+
const responsesText = extractResponsesContent(body);
|
|
6471
|
+
if (responsesText !== null) return responsesText;
|
|
6426
6472
|
const choices = body.choices;
|
|
6427
6473
|
if (!Array.isArray(choices) || choices.length === 0) return null;
|
|
6428
6474
|
const first = choices[0];
|
|
6429
6475
|
const content = first?.message?.content;
|
|
6430
6476
|
return typeof content === "string" ? content : null;
|
|
6431
6477
|
}
|
|
6432
|
-
|
|
6478
|
+
function extractResponsesContent(body) {
|
|
6479
|
+
const root = asRecord(body);
|
|
6480
|
+
if (!root) return null;
|
|
6481
|
+
if (typeof root.output_text === "string" && root.output_text !== "") return root.output_text;
|
|
6482
|
+
if (!Array.isArray(root.output)) return null;
|
|
6483
|
+
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("");
|
|
6484
|
+
return text12;
|
|
6485
|
+
}
|
|
6486
|
+
var RESPONSE_FORMAT_OK, RESPONSE_SCHEMA_OK, JSON_CONTRACT_REMINDER, RESPONSES_ONLY_MODEL_PREFIXES, CHAT_TO_RESPONSES_FIELDS, FOREIGN_ENDPOINT_SUFFIX, RETRYABLE_HTTP;
|
|
6433
6487
|
var init_portalLlm = __esm({
|
|
6434
6488
|
"src/lib/memory/portalLlm.ts"() {
|
|
6435
6489
|
"use strict";
|
|
@@ -6441,6 +6495,14 @@ var init_portalLlm = __esm({
|
|
|
6441
6495
|
RESPONSE_FORMAT_OK = /* @__PURE__ */ new Set(["openai", "inclusionai", "deepseek"]);
|
|
6442
6496
|
RESPONSE_SCHEMA_OK = /* @__PURE__ */ new Set(["openai"]);
|
|
6443
6497
|
JSON_CONTRACT_REMINDER = "Output ONLY the strict JSON object requested. No prose, no explanation, no markdown.";
|
|
6498
|
+
RESPONSES_ONLY_MODEL_PREFIXES = ["gpt-5.6"];
|
|
6499
|
+
CHAT_TO_RESPONSES_FIELDS = {
|
|
6500
|
+
max_completion_tokens: "max_output_tokens"
|
|
6501
|
+
};
|
|
6502
|
+
FOREIGN_ENDPOINT_SUFFIX = {
|
|
6503
|
+
chat: "/responses",
|
|
6504
|
+
responses: "/chat/completions"
|
|
6505
|
+
};
|
|
6444
6506
|
RETRYABLE_HTTP = /* @__PURE__ */ new Set([408, 409, 425, 429]);
|
|
6445
6507
|
}
|
|
6446
6508
|
});
|
|
@@ -17759,6 +17821,9 @@ var DEFAULT_BASE_URL2 = BASE_URL;
|
|
|
17759
17821
|
var DEFAULT_MODEL4 = "anthropic/claude-sonnet-4-6";
|
|
17760
17822
|
var DEFAULT_MAX_TOKENS = 4096;
|
|
17761
17823
|
var REQUEST_TIMEOUT_MS = 6e4;
|
|
17824
|
+
var MIN_RETRY_BUDGET_MS = 2e3;
|
|
17825
|
+
var MIN_RESPONSES_OUTPUT_TOKENS = 2048;
|
|
17826
|
+
var SCHEMA_FALLBACK_SKIP_STATUSES = /* @__PURE__ */ new Set([401, 403, 404, 408, 409, 413, 425, 429]);
|
|
17762
17827
|
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.
|
|
17763
17828
|
|
|
17764
17829
|
Rules:
|
|
@@ -17790,14 +17855,9 @@ ${m.content}`).join("\n\n");
|
|
|
17790
17855
|
const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL2;
|
|
17791
17856
|
const model = options.llmModel ?? DEFAULT_MODEL4;
|
|
17792
17857
|
const wantsStructured = !!options.responseSchema;
|
|
17793
|
-
const
|
|
17858
|
+
const useResponsesTransport = requiresResponsesTransport(model);
|
|
17859
|
+
const sendResponseFormat = wantsStructured && !useResponsesTransport && supportsResponseFormat(model, "json_schema");
|
|
17794
17860
|
const basePrompt = options.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;
|
|
17795
|
-
const systemPrompt = wantsStructured && !sendResponseFormat ? `${basePrompt}
|
|
17796
|
-
|
|
17797
|
-
Respond with ONLY a single JSON object conforming to this JSON Schema, with no prose, comments, or code fences:
|
|
17798
|
-
${JSON.stringify(
|
|
17799
|
-
options.responseSchema
|
|
17800
|
-
)}` : basePrompt;
|
|
17801
17861
|
const userMessage = [
|
|
17802
17862
|
`Question:
|
|
17803
17863
|
${trimmed}`,
|
|
@@ -17807,85 +17867,121 @@ ${evidence}`
|
|
|
17807
17867
|
].join("\n\n");
|
|
17808
17868
|
const maxTokens = options.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
17809
17869
|
const fetchImpl = options.fetchFn ?? fetch;
|
|
17870
|
+
const buildBody = (useResponseFormat) => {
|
|
17871
|
+
const systemPrompt = wantsStructured && !useResponseFormat ? `${basePrompt}
|
|
17872
|
+
|
|
17873
|
+
Respond with ONLY a single JSON object conforming to this JSON Schema, with no prose, comments, or code fences:
|
|
17874
|
+
${JSON.stringify(
|
|
17875
|
+
options.responseSchema
|
|
17876
|
+
)}` : basePrompt;
|
|
17877
|
+
const messages = [
|
|
17878
|
+
{ role: "system", content: systemPrompt },
|
|
17879
|
+
{ role: "user", content: userMessage }
|
|
17880
|
+
];
|
|
17881
|
+
if (useResponsesTransport) {
|
|
17882
|
+
return JSON.stringify({
|
|
17883
|
+
model,
|
|
17884
|
+
// Same system+user pair under the Responses-API field names: `input`
|
|
17885
|
+
// for the turns, `max_output_tokens` for the cap. Sending the
|
|
17886
|
+
// chat-completions spelling here is silently ignored, which caps the
|
|
17887
|
+
// answer at the portal default.
|
|
17888
|
+
input: messages,
|
|
17889
|
+
max_output_tokens: Math.max(maxTokens, MIN_RESPONSES_OUTPUT_TOKENS)
|
|
17890
|
+
});
|
|
17891
|
+
}
|
|
17892
|
+
return JSON.stringify({
|
|
17893
|
+
model,
|
|
17894
|
+
// Modern OpenAI field; the portal reads only `max_completion_tokens`
|
|
17895
|
+
// (the deprecated `max_tokens` is silently ignored → falls back to the
|
|
17896
|
+
// portal's default output cap and truncates the answer).
|
|
17897
|
+
max_completion_tokens: maxTokens,
|
|
17898
|
+
messages,
|
|
17899
|
+
...useResponseFormat && {
|
|
17900
|
+
response_format: {
|
|
17901
|
+
type: "json_schema",
|
|
17902
|
+
json_schema: { name: "reflect_output", schema: options.responseSchema }
|
|
17903
|
+
}
|
|
17904
|
+
}
|
|
17905
|
+
});
|
|
17906
|
+
};
|
|
17810
17907
|
const log = getLogger();
|
|
17811
17908
|
const authHeaders = await resolvePortalAuthHeaders(options, "memory/reflect");
|
|
17812
17909
|
if (authHeaders === null) return baseResult;
|
|
17813
|
-
const controller = new AbortController();
|
|
17814
17910
|
const deadline = Date.now() + REQUEST_TIMEOUT_MS;
|
|
17815
17911
|
const remaining = () => Math.max(0, deadline - Date.now());
|
|
17816
|
-
const
|
|
17817
|
-
|
|
17818
|
-
|
|
17819
|
-
|
|
17820
|
-
|
|
17821
|
-
|
|
17822
|
-
|
|
17823
|
-
|
|
17824
|
-
|
|
17825
|
-
|
|
17826
|
-
|
|
17827
|
-
|
|
17828
|
-
|
|
17829
|
-
|
|
17830
|
-
|
|
17831
|
-
|
|
17832
|
-
|
|
17833
|
-
|
|
17834
|
-
|
|
17835
|
-
|
|
17836
|
-
|
|
17837
|
-
|
|
17838
|
-
|
|
17839
|
-
|
|
17840
|
-
|
|
17841
|
-
|
|
17842
|
-
}
|
|
17843
|
-
}
|
|
17844
|
-
}),
|
|
17845
|
-
signal: controller.signal
|
|
17846
|
-
});
|
|
17847
|
-
} catch (err) {
|
|
17912
|
+
const endpoint = useResponsesTransport ? "/api/v1/responses" : "/api/v1/chat/completions";
|
|
17913
|
+
const sendOnce = async (useResponseFormat) => {
|
|
17914
|
+
const controller = new AbortController();
|
|
17915
|
+
const timer = setTimeout(() => controller.abort(), remaining());
|
|
17916
|
+
let response;
|
|
17917
|
+
try {
|
|
17918
|
+
response = await fetchImpl(`${baseUrl}${endpoint}`, {
|
|
17919
|
+
method: "POST",
|
|
17920
|
+
// No task type unless the caller named one — an undeclared task adds no
|
|
17921
|
+
// header at all, which is what keeps user-facing reflect() unlabelled.
|
|
17922
|
+
headers: {
|
|
17923
|
+
...authHeaders,
|
|
17924
|
+
...taskTypeHeader(options.taskType),
|
|
17925
|
+
"Content-Type": "application/json"
|
|
17926
|
+
},
|
|
17927
|
+
body: buildBody(useResponseFormat),
|
|
17928
|
+
signal: controller.signal
|
|
17929
|
+
});
|
|
17930
|
+
} catch (err) {
|
|
17931
|
+
clearTimeout(timer);
|
|
17932
|
+
log.warn("[memory/reflect] portal request failed", {
|
|
17933
|
+
err: err instanceof Error ? err.message : String(err),
|
|
17934
|
+
baseUrl
|
|
17935
|
+
});
|
|
17936
|
+
return { kind: "error" };
|
|
17937
|
+
}
|
|
17848
17938
|
clearTimeout(timer);
|
|
17849
|
-
|
|
17850
|
-
|
|
17851
|
-
|
|
17939
|
+
if (!response.ok) {
|
|
17940
|
+
return { kind: "http", status: response.status, statusText: response.statusText };
|
|
17941
|
+
}
|
|
17942
|
+
const bodyTimer = setTimeout(() => controller.abort(), remaining());
|
|
17943
|
+
try {
|
|
17944
|
+
const body = await response.json();
|
|
17945
|
+
clearTimeout(bodyTimer);
|
|
17946
|
+
return { kind: "ok", body };
|
|
17947
|
+
} catch (err) {
|
|
17948
|
+
clearTimeout(bodyTimer);
|
|
17949
|
+
log.warn("[memory/reflect] failed to parse portal response body", {
|
|
17950
|
+
err: err instanceof Error ? err.message : String(err)
|
|
17951
|
+
});
|
|
17952
|
+
return { kind: "error" };
|
|
17953
|
+
}
|
|
17954
|
+
};
|
|
17955
|
+
let attempt = await sendOnce(sendResponseFormat);
|
|
17956
|
+
let schemaFallbackUsed = false;
|
|
17957
|
+
const budgetLeftMs = remaining();
|
|
17958
|
+
if (attempt.kind === "http" && sendResponseFormat && !SCHEMA_FALLBACK_SKIP_STATUSES.has(attempt.status) && budgetLeftMs >= MIN_RETRY_BUDGET_MS) {
|
|
17959
|
+
log.warn("[memory/reflect] response_format json_schema rejected; retrying schema-in-prompt", {
|
|
17960
|
+
status: attempt.status,
|
|
17961
|
+
statusText: attempt.statusText,
|
|
17962
|
+
model,
|
|
17963
|
+
taskType: options.taskType,
|
|
17964
|
+
budgetLeftMs
|
|
17852
17965
|
});
|
|
17853
|
-
|
|
17966
|
+
schemaFallbackUsed = true;
|
|
17967
|
+
attempt = await sendOnce(false);
|
|
17854
17968
|
}
|
|
17855
|
-
|
|
17856
|
-
if (
|
|
17969
|
+
if (attempt.kind === "error") return baseResult;
|
|
17970
|
+
if (attempt.kind === "http") {
|
|
17857
17971
|
log.warn("[memory/reflect] portal returned non-OK", {
|
|
17858
|
-
status:
|
|
17859
|
-
statusText:
|
|
17972
|
+
status: attempt.status,
|
|
17973
|
+
statusText: attempt.statusText,
|
|
17974
|
+
// Distinguishes "the fallback ran and still failed" from "never tried".
|
|
17975
|
+
schemaFallbackUsed
|
|
17860
17976
|
});
|
|
17861
17977
|
return baseResult;
|
|
17862
17978
|
}
|
|
17863
|
-
|
|
17864
|
-
let body;
|
|
17865
|
-
try {
|
|
17866
|
-
body = await response.json();
|
|
17867
|
-
} catch (err) {
|
|
17868
|
-
clearTimeout(bodyTimer);
|
|
17869
|
-
log.warn("[memory/reflect] failed to parse portal response body", {
|
|
17870
|
-
err: err instanceof Error ? err.message : String(err)
|
|
17871
|
-
});
|
|
17872
|
-
return baseResult;
|
|
17873
|
-
}
|
|
17874
|
-
clearTimeout(bodyTimer);
|
|
17875
|
-
return parseAnswer(body, baseResult, !!options.responseSchema);
|
|
17979
|
+
return parseAnswer(attempt.body, baseResult, !!options.responseSchema);
|
|
17876
17980
|
}
|
|
17877
17981
|
function parseAnswer(body, base, parseSchema) {
|
|
17878
17982
|
if (typeof body !== "object" || body === null) return base;
|
|
17879
17983
|
const obj = body;
|
|
17880
|
-
const
|
|
17881
|
-
let text12 = "";
|
|
17882
|
-
if (Array.isArray(choices) && choices.length > 0) {
|
|
17883
|
-
const message = choices[0].message;
|
|
17884
|
-
if (typeof message === "object" && message !== null) {
|
|
17885
|
-
const content = message.content;
|
|
17886
|
-
if (typeof content === "string") text12 = content;
|
|
17887
|
-
}
|
|
17888
|
-
}
|
|
17984
|
+
const text12 = extractCompletionContent(obj) ?? "";
|
|
17889
17985
|
const usage = obj.usage;
|
|
17890
17986
|
let structuredOutput;
|
|
17891
17987
|
if (parseSchema && text12) {
|
|
@@ -17897,14 +17993,19 @@ function parseAnswer(body, base, parseSchema) {
|
|
|
17897
17993
|
});
|
|
17898
17994
|
}
|
|
17899
17995
|
}
|
|
17996
|
+
const promptTokens = usage?.prompt_tokens ?? usage?.input_tokens ?? 0;
|
|
17997
|
+
const completionTokens = usage?.completion_tokens ?? usage?.output_tokens ?? 0;
|
|
17900
17998
|
return {
|
|
17901
17999
|
text: text12,
|
|
17902
18000
|
...structuredOutput !== void 0 && { structuredOutput },
|
|
17903
18001
|
basedOn: base.basedOn,
|
|
17904
18002
|
usage: {
|
|
17905
|
-
promptTokens
|
|
17906
|
-
completionTokens
|
|
17907
|
-
|
|
18003
|
+
promptTokens,
|
|
18004
|
+
completionTokens,
|
|
18005
|
+
// Derived when absent: the Responses API reports the two component counts
|
|
18006
|
+
// and does not always send a total, which would otherwise report zero
|
|
18007
|
+
// spend for a call that plainly cost something.
|
|
18008
|
+
totalTokens: usage?.total_tokens ?? promptTokens + completionTokens
|
|
17908
18009
|
}
|
|
17909
18010
|
};
|
|
17910
18011
|
}
|