@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.
Files changed (26) hide show
  1. package/dist/client/index.cjs +13 -0
  2. package/dist/client/index.d.mts +187 -1
  3. package/dist/client/index.d.ts +187 -1
  4. package/dist/client/index.mjs +11 -0
  5. package/dist/expo/{chunk-O25LUKBK.mjs → chunk-4Z2X4UYQ.mjs} +73 -9
  6. package/dist/expo/{chunk-M4JSLFTQ.mjs → chunk-A2G6TRUK.mjs} +1 -1
  7. package/dist/expo/{chunk-JA7CDJCA.mjs → chunk-TNMPAE3V.mjs} +2 -2
  8. package/dist/{react/consolidate-LSDBMQDW.mjs → expo/consolidate-ZM5JNULQ.mjs} +2 -2
  9. package/dist/expo/index.cjs +183 -82
  10. package/dist/expo/index.mjs +118 -77
  11. package/dist/expo/{recall-JYVHWU6N.mjs → recall-FJQTIMYT.mjs} +2 -2
  12. package/dist/react/{chunk-O25LUKBK.mjs → chunk-4Z2X4UYQ.mjs} +73 -9
  13. package/dist/react/{chunk-2XLHV2XW.mjs → chunk-7X7BNMGS.mjs} +1 -1
  14. package/dist/react/{chunk-DNSPMVBY.mjs → chunk-YSL3J4K4.mjs} +2 -2
  15. package/dist/{expo/consolidate-S3KFA2WT.mjs → react/consolidate-7NMKF7UC.mjs} +2 -2
  16. package/dist/react/index.cjs +183 -82
  17. package/dist/react/index.mjs +118 -77
  18. package/dist/react/{recall-2BWBJWGG.mjs → recall-UVVZGRVF.mjs} +2 -2
  19. package/dist/server/{chunk-GP6YY6H5.mjs → chunk-4LPSEROP.mjs} +1 -1
  20. package/dist/server/{chunk-O7TB36P3.mjs → chunk-ARYSRI4Z.mjs} +2 -2
  21. package/dist/server/{chunk-7D3RI25K.mjs → chunk-BSCEZOIW.mjs} +73 -9
  22. package/dist/server/{consolidate-Z2JJP7LW.mjs → consolidate-MSAXASHL.mjs} +2 -2
  23. package/dist/server/index.cjs +183 -82
  24. package/dist/server/index.mjs +118 -77
  25. package/dist/server/{recall-VHU372MK.mjs → recall-OVSSDRYU.mjs} +2 -2
  26. package/package.json +2 -2
@@ -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 isAnthropic = req.model.startsWith("anthropic/");
6541
- const prefill = isAnthropic ? "{" : "";
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) delete requestBody.response_format;
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
- var RESPONSE_FORMAT_OK, RESPONSE_SCHEMA_OK, JSON_CONTRACT_REMINDER, RETRYABLE_HTTP;
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 sendResponseFormat = wantsStructured && supportsResponseFormat(model, "json_schema");
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 timer = setTimeout(() => controller.abort(), remaining());
19115
- let response;
19116
- try {
19117
- response = await fetchImpl(`${baseUrl}/api/v1/chat/completions`, {
19118
- method: "POST",
19119
- // No task type unless the caller named one — an undeclared task adds no
19120
- // header at all, which is what keeps user-facing reflect() unlabelled.
19121
- headers: {
19122
- ...authHeaders,
19123
- ...taskTypeHeader(options.taskType),
19124
- "Content-Type": "application/json"
19125
- },
19126
- body: JSON.stringify({
19127
- model,
19128
- // Modern OpenAI field; the portal reads only `max_completion_tokens`
19129
- // (the deprecated `max_tokens` is silently ignored → falls back to the
19130
- // portal's default output cap and truncates the answer).
19131
- max_completion_tokens: maxTokens,
19132
- messages: [
19133
- { role: "system", content: systemPrompt },
19134
- { role: "user", content: userMessage }
19135
- ],
19136
- ...sendResponseFormat && {
19137
- response_format: {
19138
- type: "json_schema",
19139
- json_schema: { name: "reflect_output", schema: options.responseSchema }
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
- log.warn("[memory/reflect] portal request failed", {
19148
- err: err instanceof Error ? err.message : String(err),
19149
- baseUrl
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
- return baseResult;
19264
+ schemaFallbackUsed = true;
19265
+ attempt = await sendOnce(false);
19152
19266
  }
19153
- clearTimeout(timer);
19154
- if (!response.ok) {
19267
+ if (attempt.kind === "error") return baseResult;
19268
+ if (attempt.kind === "http") {
19155
19269
  log.warn("[memory/reflect] portal returned non-OK", {
19156
- status: response.status,
19157
- statusText: response.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
- const bodyTimer = setTimeout(() => controller.abort(), remaining());
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 choices = obj.choices;
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: usage?.prompt_tokens ?? 0,
19204
- completionTokens: usage?.completion_tokens ?? 0,
19205
- totalTokens: usage?.total_tokens ?? 0
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
  }
@@ -178,28 +178,30 @@ import {
178
178
  updateVaultMemoryOp,
179
179
  useEncryption,
180
180
  vaultMemoryToStored
181
- } from "./chunk-DNSPMVBY.mjs";
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-2XLHV2XW.mjs";
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-O25LUKBK.mjs";
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-LSDBMQDW.mjs");
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 sendResponseFormat = wantsStructured && supportsResponseFormat(model, "json_schema");
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 timer = setTimeout(() => controller.abort(), remaining());
8968
- let response;
8969
- try {
8970
- response = await fetchImpl(`${baseUrl}/api/v1/chat/completions`, {
8971
- method: "POST",
8972
- // No task type unless the caller named one — an undeclared task adds no
8973
- // header at all, which is what keeps user-facing reflect() unlabelled.
8974
- headers: {
8975
- ...authHeaders,
8976
- ...taskTypeHeader(options.taskType),
8977
- "Content-Type": "application/json"
8978
- },
8979
- body: JSON.stringify({
8980
- model,
8981
- // Modern OpenAI field; the portal reads only `max_completion_tokens`
8982
- // (the deprecated `max_tokens` is silently ignored → falls back to the
8983
- // portal's default output cap and truncates the answer).
8984
- max_completion_tokens: maxTokens,
8985
- messages: [
8986
- { role: "system", content: systemPrompt },
8987
- { role: "user", content: userMessage }
8988
- ],
8989
- ...sendResponseFormat && {
8990
- response_format: {
8991
- type: "json_schema",
8992
- json_schema: { name: "reflect_output", schema: options.responseSchema }
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
- log.warn("[memory/reflect] portal request failed", {
9001
- err: err instanceof Error ? err.message : String(err),
9002
- baseUrl
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
- return baseResult;
9057
+ schemaFallbackUsed = true;
9058
+ attempt = await sendOnce(false);
9005
9059
  }
9006
- clearTimeout(timer);
9007
- if (!response.ok) {
9060
+ if (attempt.kind === "error") return baseResult;
9061
+ if (attempt.kind === "http") {
9008
9062
  log.warn("[memory/reflect] portal returned non-OK", {
9009
- status: response.status,
9010
- statusText: response.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
- const bodyTimer = setTimeout(() => controller.abort(), remaining());
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 choices = obj.choices;
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: usage?.prompt_tokens ?? 0,
9057
- completionTokens: usage?.completion_tokens ?? 0,
9058
- totalTokens: usage?.total_tokens ?? 0
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
  }
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  recall
3
- } from "./chunk-DNSPMVBY.mjs";
4
- import "./chunk-O25LUKBK.mjs";
3
+ } from "./chunk-YSL3J4K4.mjs";
4
+ import "./chunk-4Z2X4UYQ.mjs";
5
5
  import "./chunk-GYKJOWEO.mjs";
6
6
  export {
7
7
  recall