@anuma/sdk 5.0.2 → 5.0.4
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.d.mts +27 -3
- package/dist/client/index.d.ts +27 -3
- package/dist/expo/index.cjs +40 -4
- package/dist/expo/index.d.mts +48 -8
- package/dist/expo/index.d.ts +48 -8
- package/dist/expo/index.mjs +40 -4
- package/dist/index.d.mts +26 -2
- package/dist/index.d.ts +26 -2
- package/dist/react/index.cjs +40 -4
- package/dist/react/index.d.mts +40 -1
- package/dist/react/index.d.ts +40 -1
- package/dist/react/index.mjs +40 -4
- package/dist/server/index.cjs +40 -4
- package/dist/server/index.d.mts +48 -8
- package/dist/server/index.d.ts +48 -8
- package/dist/server/index.mjs +40 -4
- package/package.json +1 -1
package/dist/client/index.d.mts
CHANGED
|
@@ -1137,7 +1137,7 @@ type LlmapiResponseRequest = {
|
|
|
1137
1137
|
*/
|
|
1138
1138
|
tools?: Array<LlmapiResponseTool>;
|
|
1139
1139
|
};
|
|
1140
|
-
type LlmapiResponseResponse = {
|
|
1140
|
+
type LlmapiResponseResponse$1 = {
|
|
1141
1141
|
/**
|
|
1142
1142
|
* ClientInjectedTools are tool names the client provided in the original request.
|
|
1143
1143
|
*/
|
|
@@ -8562,7 +8562,7 @@ type PostApiV1ResponsesResponses = {
|
|
|
8562
8562
|
/**
|
|
8563
8563
|
* OK
|
|
8564
8564
|
*/
|
|
8565
|
-
200: LlmapiResponseResponse | string;
|
|
8565
|
+
200: LlmapiResponseResponse$1 | string;
|
|
8566
8566
|
};
|
|
8567
8567
|
type PostApiV1ResponsesResponse = PostApiV1ResponsesResponses[keyof PostApiV1ResponsesResponses];
|
|
8568
8568
|
type GetApiV1SharesData = {
|
|
@@ -9563,7 +9563,7 @@ type PostApiV1UtilityResponsesResponses = {
|
|
|
9563
9563
|
/**
|
|
9564
9564
|
* OK
|
|
9565
9565
|
*/
|
|
9566
|
-
200: LlmapiResponseResponse | string;
|
|
9566
|
+
200: LlmapiResponseResponse$1 | string;
|
|
9567
9567
|
};
|
|
9568
9568
|
type PostApiV1UtilityResponsesResponse = PostApiV1UtilityResponsesResponses[keyof PostApiV1UtilityResponsesResponses];
|
|
9569
9569
|
type GetApiV1WalletsBindingData = {
|
|
@@ -11237,6 +11237,30 @@ type LlmapiChatCompletionUsage = OpenaiCompletionUsage & {
|
|
|
11237
11237
|
* strategies/completions.ts `buildFinalResponse`. See that TODO for the full
|
|
11238
11238
|
* deprecation plan.
|
|
11239
11239
|
*/
|
|
11240
|
+
/**
|
|
11241
|
+
* Add the Responses API's terminal-state fields, which the portal's generated
|
|
11242
|
+
* schema does not declare.
|
|
11243
|
+
*
|
|
11244
|
+
* Without them the two transports are asymmetric: a completions consumer reads
|
|
11245
|
+
* `choices[0].finish_reason` and can see a turn cut off at the output ceiling,
|
|
11246
|
+
* while a Responses consumer has no field to read at all — the truncation the
|
|
11247
|
+
* SDK *did* detect (see the normalization in `strategies/responses.ts`) died at
|
|
11248
|
+
* the stream boundary. `runToolLoop` works around this with `terminalState` on
|
|
11249
|
+
* its own result, but a caller holding only a response object cannot (#805).
|
|
11250
|
+
*
|
|
11251
|
+
* These are standard OpenAI Responses fields, so this widens the type toward
|
|
11252
|
+
* the wire rather than inventing shape: they are optional because a
|
|
11253
|
+
* non-streaming direct call returns only what the portal serializes today.
|
|
11254
|
+
* Drop the override once the portal declares them upstream.
|
|
11255
|
+
*/
|
|
11256
|
+
type LlmapiResponseResponse = LlmapiResponseResponse$1 & {
|
|
11257
|
+
/** `"completed"` | `"incomplete"` — the turn's own status, not an output item's. */
|
|
11258
|
+
status?: string;
|
|
11259
|
+
/** Present when `status` is `"incomplete"`; `"max_output_tokens"` is a truncation. */
|
|
11260
|
+
incomplete_details?: {
|
|
11261
|
+
reason?: string;
|
|
11262
|
+
};
|
|
11263
|
+
};
|
|
11240
11264
|
type LlmapiChatCompletionResponse = Omit<LlmapiChatCompletionResponse$1, "usage"> & {
|
|
11241
11265
|
usage?: LlmapiChatCompletionUsage;
|
|
11242
11266
|
inference_id?: string;
|
package/dist/client/index.d.ts
CHANGED
|
@@ -1137,7 +1137,7 @@ type LlmapiResponseRequest = {
|
|
|
1137
1137
|
*/
|
|
1138
1138
|
tools?: Array<LlmapiResponseTool>;
|
|
1139
1139
|
};
|
|
1140
|
-
type LlmapiResponseResponse = {
|
|
1140
|
+
type LlmapiResponseResponse$1 = {
|
|
1141
1141
|
/**
|
|
1142
1142
|
* ClientInjectedTools are tool names the client provided in the original request.
|
|
1143
1143
|
*/
|
|
@@ -8562,7 +8562,7 @@ type PostApiV1ResponsesResponses = {
|
|
|
8562
8562
|
/**
|
|
8563
8563
|
* OK
|
|
8564
8564
|
*/
|
|
8565
|
-
200: LlmapiResponseResponse | string;
|
|
8565
|
+
200: LlmapiResponseResponse$1 | string;
|
|
8566
8566
|
};
|
|
8567
8567
|
type PostApiV1ResponsesResponse = PostApiV1ResponsesResponses[keyof PostApiV1ResponsesResponses];
|
|
8568
8568
|
type GetApiV1SharesData = {
|
|
@@ -9563,7 +9563,7 @@ type PostApiV1UtilityResponsesResponses = {
|
|
|
9563
9563
|
/**
|
|
9564
9564
|
* OK
|
|
9565
9565
|
*/
|
|
9566
|
-
200: LlmapiResponseResponse | string;
|
|
9566
|
+
200: LlmapiResponseResponse$1 | string;
|
|
9567
9567
|
};
|
|
9568
9568
|
type PostApiV1UtilityResponsesResponse = PostApiV1UtilityResponsesResponses[keyof PostApiV1UtilityResponsesResponses];
|
|
9569
9569
|
type GetApiV1WalletsBindingData = {
|
|
@@ -11237,6 +11237,30 @@ type LlmapiChatCompletionUsage = OpenaiCompletionUsage & {
|
|
|
11237
11237
|
* strategies/completions.ts `buildFinalResponse`. See that TODO for the full
|
|
11238
11238
|
* deprecation plan.
|
|
11239
11239
|
*/
|
|
11240
|
+
/**
|
|
11241
|
+
* Add the Responses API's terminal-state fields, which the portal's generated
|
|
11242
|
+
* schema does not declare.
|
|
11243
|
+
*
|
|
11244
|
+
* Without them the two transports are asymmetric: a completions consumer reads
|
|
11245
|
+
* `choices[0].finish_reason` and can see a turn cut off at the output ceiling,
|
|
11246
|
+
* while a Responses consumer has no field to read at all — the truncation the
|
|
11247
|
+
* SDK *did* detect (see the normalization in `strategies/responses.ts`) died at
|
|
11248
|
+
* the stream boundary. `runToolLoop` works around this with `terminalState` on
|
|
11249
|
+
* its own result, but a caller holding only a response object cannot (#805).
|
|
11250
|
+
*
|
|
11251
|
+
* These are standard OpenAI Responses fields, so this widens the type toward
|
|
11252
|
+
* the wire rather than inventing shape: they are optional because a
|
|
11253
|
+
* non-streaming direct call returns only what the portal serializes today.
|
|
11254
|
+
* Drop the override once the portal declares them upstream.
|
|
11255
|
+
*/
|
|
11256
|
+
type LlmapiResponseResponse = LlmapiResponseResponse$1 & {
|
|
11257
|
+
/** `"completed"` | `"incomplete"` — the turn's own status, not an output item's. */
|
|
11258
|
+
status?: string;
|
|
11259
|
+
/** Present when `status` is `"incomplete"`; `"max_output_tokens"` is a truncation. */
|
|
11260
|
+
incomplete_details?: {
|
|
11261
|
+
reason?: string;
|
|
11262
|
+
};
|
|
11263
|
+
};
|
|
11240
11264
|
type LlmapiChatCompletionResponse = Omit<LlmapiChatCompletionResponse$1, "usage"> & {
|
|
11241
11265
|
usage?: LlmapiChatCompletionUsage;
|
|
11242
11266
|
inference_id?: string;
|
package/dist/expo/index.cjs
CHANGED
|
@@ -10784,6 +10784,16 @@ var ResponsesStrategy = class {
|
|
|
10784
10784
|
}));
|
|
10785
10785
|
mergeToolCallEventsIntoAccumulator(accumulator, toolCallEvents);
|
|
10786
10786
|
}
|
|
10787
|
+
const fbStatus = typeof resp.status === "string" ? resp.status : void 0;
|
|
10788
|
+
const fbIncompleteReason = resp.incomplete_details?.reason;
|
|
10789
|
+
const fbFinishReason = typeof resp.finish_reason === "string" ? resp.finish_reason : void 0;
|
|
10790
|
+
if (fbStatus !== void 0) accumulator.responseStatus = fbStatus;
|
|
10791
|
+
if (fbIncompleteReason !== void 0) accumulator.incompleteReason = fbIncompleteReason;
|
|
10792
|
+
if (fbFinishReason !== void 0) {
|
|
10793
|
+
accumulator.finishReason = fbFinishReason;
|
|
10794
|
+
} else if (fbStatus === "incomplete" && fbIncompleteReason === "max_output_tokens") {
|
|
10795
|
+
accumulator.finishReason = "length";
|
|
10796
|
+
}
|
|
10787
10797
|
return result;
|
|
10788
10798
|
}
|
|
10789
10799
|
if (typedChunk.type === "response.created" && typedChunk.response) {
|
|
@@ -10819,6 +10829,8 @@ var ResponsesStrategy = class {
|
|
|
10819
10829
|
if (looksIncomplete && resp?.incomplete_details?.reason === "max_output_tokens") {
|
|
10820
10830
|
accumulator.finishReason = "length";
|
|
10821
10831
|
}
|
|
10832
|
+
accumulator.responseStatus = looksIncomplete ? "incomplete" : resp?.status;
|
|
10833
|
+
accumulator.incompleteReason = resp?.incomplete_details?.reason;
|
|
10822
10834
|
if (typedChunk.response?.tools_checksum && !accumulator.toolsChecksum) {
|
|
10823
10835
|
accumulator.toolsChecksum = typedChunk.response.tools_checksum;
|
|
10824
10836
|
}
|
|
@@ -11087,7 +11099,17 @@ var ResponsesStrategy = class {
|
|
|
11087
11099
|
output,
|
|
11088
11100
|
usage: Object.keys(accumulator.usage).length > 0 ? accumulator.usage : void 0,
|
|
11089
11101
|
tools_checksum: accumulator.toolsChecksum,
|
|
11090
|
-
tool_call_events: accumulator.toolCallEvents
|
|
11102
|
+
tool_call_events: accumulator.toolCallEvents,
|
|
11103
|
+
// Response-level terminal state (#805). Note the individual output items
|
|
11104
|
+
// above hardcode `status: "completed"` — that is the item's own status
|
|
11105
|
+
// and says nothing about the turn. Only these two fields can tell a
|
|
11106
|
+
// caller the turn was cut off, and until now neither survived the stream.
|
|
11107
|
+
// Omitted rather than emitted as `undefined` so a clean turn's response
|
|
11108
|
+
// shape is unchanged.
|
|
11109
|
+
...accumulator.responseStatus !== void 0 && { status: accumulator.responseStatus },
|
|
11110
|
+
...accumulator.incompleteReason !== void 0 && {
|
|
11111
|
+
incomplete_details: { reason: accumulator.incompleteReason }
|
|
11112
|
+
}
|
|
11091
11113
|
};
|
|
11092
11114
|
}
|
|
11093
11115
|
};
|
|
@@ -12106,6 +12128,9 @@ Executing tool: ${toolInfo}
|
|
|
12106
12128
|
usage: {
|
|
12107
12129
|
inputTokens: currentAccumulator.usage.prompt_tokens,
|
|
12108
12130
|
outputTokens: currentAccumulator.usage.completion_tokens
|
|
12131
|
+
},
|
|
12132
|
+
...currentAccumulator.finishReason !== void 0 && {
|
|
12133
|
+
finishReason: currentAccumulator.finishReason
|
|
12109
12134
|
}
|
|
12110
12135
|
});
|
|
12111
12136
|
}
|
|
@@ -17281,7 +17306,14 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
17281
17306
|
observationTrends
|
|
17282
17307
|
};
|
|
17283
17308
|
}
|
|
17284
|
-
const staleKeys = await computeStaleFacetKeys(
|
|
17309
|
+
const staleKeys = await computeStaleFacetKeys(
|
|
17310
|
+
ctx,
|
|
17311
|
+
memories,
|
|
17312
|
+
facets,
|
|
17313
|
+
previous,
|
|
17314
|
+
watermark,
|
|
17315
|
+
options.reviewedMemoryIds
|
|
17316
|
+
);
|
|
17285
17317
|
const settled = await Promise.allSettled(
|
|
17286
17318
|
facets.map(async (facet) => {
|
|
17287
17319
|
const prior = previous?.sections.find((s) => s.key === facet.key);
|
|
@@ -17342,7 +17374,7 @@ function computeVaultWatermark(memories) {
|
|
|
17342
17374
|
}
|
|
17343
17375
|
return max;
|
|
17344
17376
|
}
|
|
17345
|
-
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark) {
|
|
17377
|
+
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark, reviewedMemoryIds) {
|
|
17346
17378
|
const allKeys = new Set(facets.map((f) => f.key));
|
|
17347
17379
|
if (previous && watermark < previous.vaultWatermark) return allKeys;
|
|
17348
17380
|
if (!previous) return allKeys;
|
|
@@ -17365,9 +17397,13 @@ async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark)
|
|
|
17365
17397
|
if (!previous.sections.some((s) => s.key === facet.key)) stale.add(facet.key);
|
|
17366
17398
|
}
|
|
17367
17399
|
const citedIds = new Set(previous.sections.flatMap((s) => s.sourceMemoryIds));
|
|
17368
|
-
|
|
17400
|
+
let toAttribute = changed.filter(
|
|
17369
17401
|
(m) => !m.isDeleted && !m.supersededBy && !citedIds.has(m.uniqueId)
|
|
17370
17402
|
);
|
|
17403
|
+
if (reviewedMemoryIds !== void 0) {
|
|
17404
|
+
const allowed = new Set(reviewedMemoryIds);
|
|
17405
|
+
toAttribute = toAttribute.filter((m) => allowed.has(m.uniqueId));
|
|
17406
|
+
}
|
|
17371
17407
|
if (toAttribute.length > 0) {
|
|
17372
17408
|
const attributed = await attributeFacts(ctx, toAttribute, facets);
|
|
17373
17409
|
if (attributed === null) return allKeys;
|
package/dist/expo/index.d.mts
CHANGED
|
@@ -407,7 +407,7 @@ type LlmapiResponseReasoning = {
|
|
|
407
407
|
*/
|
|
408
408
|
summary?: string;
|
|
409
409
|
};
|
|
410
|
-
type LlmapiResponseResponse = {
|
|
410
|
+
type LlmapiResponseResponse$1 = {
|
|
411
411
|
/**
|
|
412
412
|
* ClientInjectedTools are tool names the client provided in the original request.
|
|
413
413
|
*/
|
|
@@ -1234,6 +1234,30 @@ type LlmapiChatCompletionUsage = OpenaiCompletionUsage & {
|
|
|
1234
1234
|
* strategies/completions.ts `buildFinalResponse`. See that TODO for the full
|
|
1235
1235
|
* deprecation plan.
|
|
1236
1236
|
*/
|
|
1237
|
+
/**
|
|
1238
|
+
* Add the Responses API's terminal-state fields, which the portal's generated
|
|
1239
|
+
* schema does not declare.
|
|
1240
|
+
*
|
|
1241
|
+
* Without them the two transports are asymmetric: a completions consumer reads
|
|
1242
|
+
* `choices[0].finish_reason` and can see a turn cut off at the output ceiling,
|
|
1243
|
+
* while a Responses consumer has no field to read at all — the truncation the
|
|
1244
|
+
* SDK *did* detect (see the normalization in `strategies/responses.ts`) died at
|
|
1245
|
+
* the stream boundary. `runToolLoop` works around this with `terminalState` on
|
|
1246
|
+
* its own result, but a caller holding only a response object cannot (#805).
|
|
1247
|
+
*
|
|
1248
|
+
* These are standard OpenAI Responses fields, so this widens the type toward
|
|
1249
|
+
* the wire rather than inventing shape: they are optional because a
|
|
1250
|
+
* non-streaming direct call returns only what the portal serializes today.
|
|
1251
|
+
* Drop the override once the portal declares them upstream.
|
|
1252
|
+
*/
|
|
1253
|
+
type LlmapiResponseResponse = LlmapiResponseResponse$1 & {
|
|
1254
|
+
/** `"completed"` | `"incomplete"` — the turn's own status, not an output item's. */
|
|
1255
|
+
status?: string;
|
|
1256
|
+
/** Present when `status` is `"incomplete"`; `"max_output_tokens"` is a truncation. */
|
|
1257
|
+
incomplete_details?: {
|
|
1258
|
+
reason?: string;
|
|
1259
|
+
};
|
|
1260
|
+
};
|
|
1237
1261
|
type LlmapiChatCompletionResponse = Omit<LlmapiChatCompletionResponse$1, "usage"> & {
|
|
1238
1262
|
usage?: LlmapiChatCompletionUsage;
|
|
1239
1263
|
inference_id?: string;
|
|
@@ -2428,6 +2452,21 @@ type StepFinishEvent = {
|
|
|
2428
2452
|
inputTokens?: number;
|
|
2429
2453
|
outputTokens?: number;
|
|
2430
2454
|
};
|
|
2455
|
+
/**
|
|
2456
|
+
* The round's own finish reason, as the provider sent it — `"length"` means
|
|
2457
|
+
* this round hit the output ceiling.
|
|
2458
|
+
*
|
|
2459
|
+
* Per-round, not per-turn: a round can truncate and the loop still recover on
|
|
2460
|
+
* the next one, which is why the loop does not treat it as an error on its
|
|
2461
|
+
* own (see the truncation guard below). Without it a consumer watching steps
|
|
2462
|
+
* cannot tell a round that said everything it meant to from one that was cut
|
|
2463
|
+
* off mid-argument — they differ only in this field (#805).
|
|
2464
|
+
*
|
|
2465
|
+
* Absent when the provider sent no finish reason. Note that no step event
|
|
2466
|
+
* fires for the round that *ends* a turn, so use {@link RunTerminalState} on
|
|
2467
|
+
* the result for the final round.
|
|
2468
|
+
*/
|
|
2469
|
+
finishReason?: string;
|
|
2431
2470
|
};
|
|
2432
2471
|
/**
|
|
2433
2472
|
* Terminal state of the LAST model response in the turn, normalized to the
|
|
@@ -2435,13 +2474,14 @@ type StepFinishEvent = {
|
|
|
2435
2474
|
* specific values). `undefined` when the stream carried no finish reason at all.
|
|
2436
2475
|
*
|
|
2437
2476
|
* Exposed because neither response shape reliably carries it out to a caller.
|
|
2438
|
-
* The Responses
|
|
2439
|
-
*
|
|
2440
|
-
*
|
|
2441
|
-
*
|
|
2442
|
-
* `choices[0].finish_reason`, but omits `tool_calls` entirely when
|
|
2443
|
-
* none, so a caller sniffing the response cannot tell "no tool calls"
|
|
2444
|
-
* "field absent".
|
|
2477
|
+
* The Responses shape now carries `status` / `incomplete_details` — added in
|
|
2478
|
+
* `clientCompat` and emitted by `buildFinalResponse` — but only in the
|
|
2479
|
+
* Responses vocabulary, so a caller reading it has to translate
|
|
2480
|
+
* `incomplete_details.reason === "max_output_tokens"` itself. Completions
|
|
2481
|
+
* exposes `choices[0].finish_reason`, but omits `tool_calls` entirely when
|
|
2482
|
+
* there are none, so a caller sniffing the response cannot tell "no tool calls"
|
|
2483
|
+
* from "field absent". This field answers both questions in one vocabulary,
|
|
2484
|
+
* for either transport.
|
|
2445
2485
|
*
|
|
2446
2486
|
* The loop already knows both, unambiguously and identically for either API.
|
|
2447
2487
|
* Reporting them here means callers and test harnesses stop reverse-engineering
|
package/dist/expo/index.d.ts
CHANGED
|
@@ -407,7 +407,7 @@ type LlmapiResponseReasoning = {
|
|
|
407
407
|
*/
|
|
408
408
|
summary?: string;
|
|
409
409
|
};
|
|
410
|
-
type LlmapiResponseResponse = {
|
|
410
|
+
type LlmapiResponseResponse$1 = {
|
|
411
411
|
/**
|
|
412
412
|
* ClientInjectedTools are tool names the client provided in the original request.
|
|
413
413
|
*/
|
|
@@ -1234,6 +1234,30 @@ type LlmapiChatCompletionUsage = OpenaiCompletionUsage & {
|
|
|
1234
1234
|
* strategies/completions.ts `buildFinalResponse`. See that TODO for the full
|
|
1235
1235
|
* deprecation plan.
|
|
1236
1236
|
*/
|
|
1237
|
+
/**
|
|
1238
|
+
* Add the Responses API's terminal-state fields, which the portal's generated
|
|
1239
|
+
* schema does not declare.
|
|
1240
|
+
*
|
|
1241
|
+
* Without them the two transports are asymmetric: a completions consumer reads
|
|
1242
|
+
* `choices[0].finish_reason` and can see a turn cut off at the output ceiling,
|
|
1243
|
+
* while a Responses consumer has no field to read at all — the truncation the
|
|
1244
|
+
* SDK *did* detect (see the normalization in `strategies/responses.ts`) died at
|
|
1245
|
+
* the stream boundary. `runToolLoop` works around this with `terminalState` on
|
|
1246
|
+
* its own result, but a caller holding only a response object cannot (#805).
|
|
1247
|
+
*
|
|
1248
|
+
* These are standard OpenAI Responses fields, so this widens the type toward
|
|
1249
|
+
* the wire rather than inventing shape: they are optional because a
|
|
1250
|
+
* non-streaming direct call returns only what the portal serializes today.
|
|
1251
|
+
* Drop the override once the portal declares them upstream.
|
|
1252
|
+
*/
|
|
1253
|
+
type LlmapiResponseResponse = LlmapiResponseResponse$1 & {
|
|
1254
|
+
/** `"completed"` | `"incomplete"` — the turn's own status, not an output item's. */
|
|
1255
|
+
status?: string;
|
|
1256
|
+
/** Present when `status` is `"incomplete"`; `"max_output_tokens"` is a truncation. */
|
|
1257
|
+
incomplete_details?: {
|
|
1258
|
+
reason?: string;
|
|
1259
|
+
};
|
|
1260
|
+
};
|
|
1237
1261
|
type LlmapiChatCompletionResponse = Omit<LlmapiChatCompletionResponse$1, "usage"> & {
|
|
1238
1262
|
usage?: LlmapiChatCompletionUsage;
|
|
1239
1263
|
inference_id?: string;
|
|
@@ -2428,6 +2452,21 @@ type StepFinishEvent = {
|
|
|
2428
2452
|
inputTokens?: number;
|
|
2429
2453
|
outputTokens?: number;
|
|
2430
2454
|
};
|
|
2455
|
+
/**
|
|
2456
|
+
* The round's own finish reason, as the provider sent it — `"length"` means
|
|
2457
|
+
* this round hit the output ceiling.
|
|
2458
|
+
*
|
|
2459
|
+
* Per-round, not per-turn: a round can truncate and the loop still recover on
|
|
2460
|
+
* the next one, which is why the loop does not treat it as an error on its
|
|
2461
|
+
* own (see the truncation guard below). Without it a consumer watching steps
|
|
2462
|
+
* cannot tell a round that said everything it meant to from one that was cut
|
|
2463
|
+
* off mid-argument — they differ only in this field (#805).
|
|
2464
|
+
*
|
|
2465
|
+
* Absent when the provider sent no finish reason. Note that no step event
|
|
2466
|
+
* fires for the round that *ends* a turn, so use {@link RunTerminalState} on
|
|
2467
|
+
* the result for the final round.
|
|
2468
|
+
*/
|
|
2469
|
+
finishReason?: string;
|
|
2431
2470
|
};
|
|
2432
2471
|
/**
|
|
2433
2472
|
* Terminal state of the LAST model response in the turn, normalized to the
|
|
@@ -2435,13 +2474,14 @@ type StepFinishEvent = {
|
|
|
2435
2474
|
* specific values). `undefined` when the stream carried no finish reason at all.
|
|
2436
2475
|
*
|
|
2437
2476
|
* Exposed because neither response shape reliably carries it out to a caller.
|
|
2438
|
-
* The Responses
|
|
2439
|
-
*
|
|
2440
|
-
*
|
|
2441
|
-
*
|
|
2442
|
-
* `choices[0].finish_reason`, but omits `tool_calls` entirely when
|
|
2443
|
-
* none, so a caller sniffing the response cannot tell "no tool calls"
|
|
2444
|
-
* "field absent".
|
|
2477
|
+
* The Responses shape now carries `status` / `incomplete_details` — added in
|
|
2478
|
+
* `clientCompat` and emitted by `buildFinalResponse` — but only in the
|
|
2479
|
+
* Responses vocabulary, so a caller reading it has to translate
|
|
2480
|
+
* `incomplete_details.reason === "max_output_tokens"` itself. Completions
|
|
2481
|
+
* exposes `choices[0].finish_reason`, but omits `tool_calls` entirely when
|
|
2482
|
+
* there are none, so a caller sniffing the response cannot tell "no tool calls"
|
|
2483
|
+
* from "field absent". This field answers both questions in one vocabulary,
|
|
2484
|
+
* for either transport.
|
|
2445
2485
|
*
|
|
2446
2486
|
* The loop already knows both, unambiguously and identically for either API.
|
|
2447
2487
|
* Reporting them here means callers and test harnesses stop reverse-engineering
|
package/dist/expo/index.mjs
CHANGED
|
@@ -1823,6 +1823,16 @@ var ResponsesStrategy = class {
|
|
|
1823
1823
|
}));
|
|
1824
1824
|
mergeToolCallEventsIntoAccumulator(accumulator, toolCallEvents);
|
|
1825
1825
|
}
|
|
1826
|
+
const fbStatus = typeof resp.status === "string" ? resp.status : void 0;
|
|
1827
|
+
const fbIncompleteReason = resp.incomplete_details?.reason;
|
|
1828
|
+
const fbFinishReason = typeof resp.finish_reason === "string" ? resp.finish_reason : void 0;
|
|
1829
|
+
if (fbStatus !== void 0) accumulator.responseStatus = fbStatus;
|
|
1830
|
+
if (fbIncompleteReason !== void 0) accumulator.incompleteReason = fbIncompleteReason;
|
|
1831
|
+
if (fbFinishReason !== void 0) {
|
|
1832
|
+
accumulator.finishReason = fbFinishReason;
|
|
1833
|
+
} else if (fbStatus === "incomplete" && fbIncompleteReason === "max_output_tokens") {
|
|
1834
|
+
accumulator.finishReason = "length";
|
|
1835
|
+
}
|
|
1826
1836
|
return result;
|
|
1827
1837
|
}
|
|
1828
1838
|
if (typedChunk.type === "response.created" && typedChunk.response) {
|
|
@@ -1858,6 +1868,8 @@ var ResponsesStrategy = class {
|
|
|
1858
1868
|
if (looksIncomplete && resp?.incomplete_details?.reason === "max_output_tokens") {
|
|
1859
1869
|
accumulator.finishReason = "length";
|
|
1860
1870
|
}
|
|
1871
|
+
accumulator.responseStatus = looksIncomplete ? "incomplete" : resp?.status;
|
|
1872
|
+
accumulator.incompleteReason = resp?.incomplete_details?.reason;
|
|
1861
1873
|
if (typedChunk.response?.tools_checksum && !accumulator.toolsChecksum) {
|
|
1862
1874
|
accumulator.toolsChecksum = typedChunk.response.tools_checksum;
|
|
1863
1875
|
}
|
|
@@ -2126,7 +2138,17 @@ var ResponsesStrategy = class {
|
|
|
2126
2138
|
output,
|
|
2127
2139
|
usage: Object.keys(accumulator.usage).length > 0 ? accumulator.usage : void 0,
|
|
2128
2140
|
tools_checksum: accumulator.toolsChecksum,
|
|
2129
|
-
tool_call_events: accumulator.toolCallEvents
|
|
2141
|
+
tool_call_events: accumulator.toolCallEvents,
|
|
2142
|
+
// Response-level terminal state (#805). Note the individual output items
|
|
2143
|
+
// above hardcode `status: "completed"` — that is the item's own status
|
|
2144
|
+
// and says nothing about the turn. Only these two fields can tell a
|
|
2145
|
+
// caller the turn was cut off, and until now neither survived the stream.
|
|
2146
|
+
// Omitted rather than emitted as `undefined` so a clean turn's response
|
|
2147
|
+
// shape is unchanged.
|
|
2148
|
+
...accumulator.responseStatus !== void 0 && { status: accumulator.responseStatus },
|
|
2149
|
+
...accumulator.incompleteReason !== void 0 && {
|
|
2150
|
+
incomplete_details: { reason: accumulator.incompleteReason }
|
|
2151
|
+
}
|
|
2130
2152
|
};
|
|
2131
2153
|
}
|
|
2132
2154
|
};
|
|
@@ -3145,6 +3167,9 @@ Executing tool: ${toolInfo}
|
|
|
3145
3167
|
usage: {
|
|
3146
3168
|
inputTokens: currentAccumulator.usage.prompt_tokens,
|
|
3147
3169
|
outputTokens: currentAccumulator.usage.completion_tokens
|
|
3170
|
+
},
|
|
3171
|
+
...currentAccumulator.finishReason !== void 0 && {
|
|
3172
|
+
finishReason: currentAccumulator.finishReason
|
|
3148
3173
|
}
|
|
3149
3174
|
});
|
|
3150
3175
|
}
|
|
@@ -8237,7 +8262,14 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
8237
8262
|
observationTrends
|
|
8238
8263
|
};
|
|
8239
8264
|
}
|
|
8240
|
-
const staleKeys = await computeStaleFacetKeys(
|
|
8265
|
+
const staleKeys = await computeStaleFacetKeys(
|
|
8266
|
+
ctx,
|
|
8267
|
+
memories,
|
|
8268
|
+
facets,
|
|
8269
|
+
previous,
|
|
8270
|
+
watermark,
|
|
8271
|
+
options.reviewedMemoryIds
|
|
8272
|
+
);
|
|
8241
8273
|
const settled = await Promise.allSettled(
|
|
8242
8274
|
facets.map(async (facet) => {
|
|
8243
8275
|
const prior = previous?.sections.find((s) => s.key === facet.key);
|
|
@@ -8298,7 +8330,7 @@ function computeVaultWatermark(memories) {
|
|
|
8298
8330
|
}
|
|
8299
8331
|
return max;
|
|
8300
8332
|
}
|
|
8301
|
-
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark) {
|
|
8333
|
+
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark, reviewedMemoryIds) {
|
|
8302
8334
|
const allKeys = new Set(facets.map((f) => f.key));
|
|
8303
8335
|
if (previous && watermark < previous.vaultWatermark) return allKeys;
|
|
8304
8336
|
if (!previous) return allKeys;
|
|
@@ -8321,9 +8353,13 @@ async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark)
|
|
|
8321
8353
|
if (!previous.sections.some((s) => s.key === facet.key)) stale.add(facet.key);
|
|
8322
8354
|
}
|
|
8323
8355
|
const citedIds = new Set(previous.sections.flatMap((s) => s.sourceMemoryIds));
|
|
8324
|
-
|
|
8356
|
+
let toAttribute = changed.filter(
|
|
8325
8357
|
(m) => !m.isDeleted && !m.supersededBy && !citedIds.has(m.uniqueId)
|
|
8326
8358
|
);
|
|
8359
|
+
if (reviewedMemoryIds !== void 0) {
|
|
8360
|
+
const allowed = new Set(reviewedMemoryIds);
|
|
8361
|
+
toAttribute = toAttribute.filter((m) => allowed.has(m.uniqueId));
|
|
8362
|
+
}
|
|
8327
8363
|
if (toAttribute.length > 0) {
|
|
8328
8364
|
const attributed = await attributeFacts(ctx, toAttribute, facets);
|
|
8329
8365
|
if (attributed === null) return allKeys;
|
package/dist/index.d.mts
CHANGED
|
@@ -990,7 +990,7 @@ type LlmapiResponseRequest = {
|
|
|
990
990
|
*/
|
|
991
991
|
tools?: Array<LlmapiResponseTool>;
|
|
992
992
|
};
|
|
993
|
-
type LlmapiResponseResponse = {
|
|
993
|
+
type LlmapiResponseResponse$1 = {
|
|
994
994
|
/**
|
|
995
995
|
* ClientInjectedTools are tool names the client provided in the original request.
|
|
996
996
|
*/
|
|
@@ -5840,7 +5840,7 @@ type PostApiV1ResponsesResponses = {
|
|
|
5840
5840
|
/**
|
|
5841
5841
|
* OK
|
|
5842
5842
|
*/
|
|
5843
|
-
200: LlmapiResponseResponse | string;
|
|
5843
|
+
200: LlmapiResponseResponse$1 | string;
|
|
5844
5844
|
};
|
|
5845
5845
|
type PostApiV1ResponsesResponse = PostApiV1ResponsesResponses[keyof PostApiV1ResponsesResponses];
|
|
5846
5846
|
type PostApiV1SubscriptionsCancelData = {
|
|
@@ -7166,6 +7166,30 @@ type LlmapiChatCompletionUsage = OpenaiCompletionUsage & {
|
|
|
7166
7166
|
* strategies/completions.ts `buildFinalResponse`. See that TODO for the full
|
|
7167
7167
|
* deprecation plan.
|
|
7168
7168
|
*/
|
|
7169
|
+
/**
|
|
7170
|
+
* Add the Responses API's terminal-state fields, which the portal's generated
|
|
7171
|
+
* schema does not declare.
|
|
7172
|
+
*
|
|
7173
|
+
* Without them the two transports are asymmetric: a completions consumer reads
|
|
7174
|
+
* `choices[0].finish_reason` and can see a turn cut off at the output ceiling,
|
|
7175
|
+
* while a Responses consumer has no field to read at all — the truncation the
|
|
7176
|
+
* SDK *did* detect (see the normalization in `strategies/responses.ts`) died at
|
|
7177
|
+
* the stream boundary. `runToolLoop` works around this with `terminalState` on
|
|
7178
|
+
* its own result, but a caller holding only a response object cannot (#805).
|
|
7179
|
+
*
|
|
7180
|
+
* These are standard OpenAI Responses fields, so this widens the type toward
|
|
7181
|
+
* the wire rather than inventing shape: they are optional because a
|
|
7182
|
+
* non-streaming direct call returns only what the portal serializes today.
|
|
7183
|
+
* Drop the override once the portal declares them upstream.
|
|
7184
|
+
*/
|
|
7185
|
+
type LlmapiResponseResponse = LlmapiResponseResponse$1 & {
|
|
7186
|
+
/** `"completed"` | `"incomplete"` — the turn's own status, not an output item's. */
|
|
7187
|
+
status?: string;
|
|
7188
|
+
/** Present when `status` is `"incomplete"`; `"max_output_tokens"` is a truncation. */
|
|
7189
|
+
incomplete_details?: {
|
|
7190
|
+
reason?: string;
|
|
7191
|
+
};
|
|
7192
|
+
};
|
|
7169
7193
|
type LlmapiChatCompletionResponse = Omit<LlmapiChatCompletionResponse$1, "usage"> & {
|
|
7170
7194
|
usage?: LlmapiChatCompletionUsage;
|
|
7171
7195
|
inference_id?: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -990,7 +990,7 @@ type LlmapiResponseRequest = {
|
|
|
990
990
|
*/
|
|
991
991
|
tools?: Array<LlmapiResponseTool>;
|
|
992
992
|
};
|
|
993
|
-
type LlmapiResponseResponse = {
|
|
993
|
+
type LlmapiResponseResponse$1 = {
|
|
994
994
|
/**
|
|
995
995
|
* ClientInjectedTools are tool names the client provided in the original request.
|
|
996
996
|
*/
|
|
@@ -5840,7 +5840,7 @@ type PostApiV1ResponsesResponses = {
|
|
|
5840
5840
|
/**
|
|
5841
5841
|
* OK
|
|
5842
5842
|
*/
|
|
5843
|
-
200: LlmapiResponseResponse | string;
|
|
5843
|
+
200: LlmapiResponseResponse$1 | string;
|
|
5844
5844
|
};
|
|
5845
5845
|
type PostApiV1ResponsesResponse = PostApiV1ResponsesResponses[keyof PostApiV1ResponsesResponses];
|
|
5846
5846
|
type PostApiV1SubscriptionsCancelData = {
|
|
@@ -7166,6 +7166,30 @@ type LlmapiChatCompletionUsage = OpenaiCompletionUsage & {
|
|
|
7166
7166
|
* strategies/completions.ts `buildFinalResponse`. See that TODO for the full
|
|
7167
7167
|
* deprecation plan.
|
|
7168
7168
|
*/
|
|
7169
|
+
/**
|
|
7170
|
+
* Add the Responses API's terminal-state fields, which the portal's generated
|
|
7171
|
+
* schema does not declare.
|
|
7172
|
+
*
|
|
7173
|
+
* Without them the two transports are asymmetric: a completions consumer reads
|
|
7174
|
+
* `choices[0].finish_reason` and can see a turn cut off at the output ceiling,
|
|
7175
|
+
* while a Responses consumer has no field to read at all — the truncation the
|
|
7176
|
+
* SDK *did* detect (see the normalization in `strategies/responses.ts`) died at
|
|
7177
|
+
* the stream boundary. `runToolLoop` works around this with `terminalState` on
|
|
7178
|
+
* its own result, but a caller holding only a response object cannot (#805).
|
|
7179
|
+
*
|
|
7180
|
+
* These are standard OpenAI Responses fields, so this widens the type toward
|
|
7181
|
+
* the wire rather than inventing shape: they are optional because a
|
|
7182
|
+
* non-streaming direct call returns only what the portal serializes today.
|
|
7183
|
+
* Drop the override once the portal declares them upstream.
|
|
7184
|
+
*/
|
|
7185
|
+
type LlmapiResponseResponse = LlmapiResponseResponse$1 & {
|
|
7186
|
+
/** `"completed"` | `"incomplete"` — the turn's own status, not an output item's. */
|
|
7187
|
+
status?: string;
|
|
7188
|
+
/** Present when `status` is `"incomplete"`; `"max_output_tokens"` is a truncation. */
|
|
7189
|
+
incomplete_details?: {
|
|
7190
|
+
reason?: string;
|
|
7191
|
+
};
|
|
7192
|
+
};
|
|
7169
7193
|
type LlmapiChatCompletionResponse = Omit<LlmapiChatCompletionResponse$1, "usage"> & {
|
|
7170
7194
|
usage?: LlmapiChatCompletionUsage;
|
|
7171
7195
|
inference_id?: string;
|
package/dist/react/index.cjs
CHANGED
|
@@ -11144,6 +11144,16 @@ var ResponsesStrategy = class {
|
|
|
11144
11144
|
}));
|
|
11145
11145
|
mergeToolCallEventsIntoAccumulator(accumulator, toolCallEvents);
|
|
11146
11146
|
}
|
|
11147
|
+
const fbStatus = typeof resp.status === "string" ? resp.status : void 0;
|
|
11148
|
+
const fbIncompleteReason = resp.incomplete_details?.reason;
|
|
11149
|
+
const fbFinishReason = typeof resp.finish_reason === "string" ? resp.finish_reason : void 0;
|
|
11150
|
+
if (fbStatus !== void 0) accumulator.responseStatus = fbStatus;
|
|
11151
|
+
if (fbIncompleteReason !== void 0) accumulator.incompleteReason = fbIncompleteReason;
|
|
11152
|
+
if (fbFinishReason !== void 0) {
|
|
11153
|
+
accumulator.finishReason = fbFinishReason;
|
|
11154
|
+
} else if (fbStatus === "incomplete" && fbIncompleteReason === "max_output_tokens") {
|
|
11155
|
+
accumulator.finishReason = "length";
|
|
11156
|
+
}
|
|
11147
11157
|
return result;
|
|
11148
11158
|
}
|
|
11149
11159
|
if (typedChunk.type === "response.created" && typedChunk.response) {
|
|
@@ -11179,6 +11189,8 @@ var ResponsesStrategy = class {
|
|
|
11179
11189
|
if (looksIncomplete && resp?.incomplete_details?.reason === "max_output_tokens") {
|
|
11180
11190
|
accumulator.finishReason = "length";
|
|
11181
11191
|
}
|
|
11192
|
+
accumulator.responseStatus = looksIncomplete ? "incomplete" : resp?.status;
|
|
11193
|
+
accumulator.incompleteReason = resp?.incomplete_details?.reason;
|
|
11182
11194
|
if (typedChunk.response?.tools_checksum && !accumulator.toolsChecksum) {
|
|
11183
11195
|
accumulator.toolsChecksum = typedChunk.response.tools_checksum;
|
|
11184
11196
|
}
|
|
@@ -11447,7 +11459,17 @@ var ResponsesStrategy = class {
|
|
|
11447
11459
|
output,
|
|
11448
11460
|
usage: Object.keys(accumulator.usage).length > 0 ? accumulator.usage : void 0,
|
|
11449
11461
|
tools_checksum: accumulator.toolsChecksum,
|
|
11450
|
-
tool_call_events: accumulator.toolCallEvents
|
|
11462
|
+
tool_call_events: accumulator.toolCallEvents,
|
|
11463
|
+
// Response-level terminal state (#805). Note the individual output items
|
|
11464
|
+
// above hardcode `status: "completed"` — that is the item's own status
|
|
11465
|
+
// and says nothing about the turn. Only these two fields can tell a
|
|
11466
|
+
// caller the turn was cut off, and until now neither survived the stream.
|
|
11467
|
+
// Omitted rather than emitted as `undefined` so a clean turn's response
|
|
11468
|
+
// shape is unchanged.
|
|
11469
|
+
...accumulator.responseStatus !== void 0 && { status: accumulator.responseStatus },
|
|
11470
|
+
...accumulator.incompleteReason !== void 0 && {
|
|
11471
|
+
incomplete_details: { reason: accumulator.incompleteReason }
|
|
11472
|
+
}
|
|
11451
11473
|
};
|
|
11452
11474
|
}
|
|
11453
11475
|
};
|
|
@@ -12466,6 +12488,9 @@ Executing tool: ${toolInfo}
|
|
|
12466
12488
|
usage: {
|
|
12467
12489
|
inputTokens: currentAccumulator.usage.prompt_tokens,
|
|
12468
12490
|
outputTokens: currentAccumulator.usage.completion_tokens
|
|
12491
|
+
},
|
|
12492
|
+
...currentAccumulator.finishReason !== void 0 && {
|
|
12493
|
+
finishReason: currentAccumulator.finishReason
|
|
12469
12494
|
}
|
|
12470
12495
|
});
|
|
12471
12496
|
}
|
|
@@ -18580,7 +18605,14 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
18580
18605
|
observationTrends
|
|
18581
18606
|
};
|
|
18582
18607
|
}
|
|
18583
|
-
const staleKeys = await computeStaleFacetKeys(
|
|
18608
|
+
const staleKeys = await computeStaleFacetKeys(
|
|
18609
|
+
ctx,
|
|
18610
|
+
memories,
|
|
18611
|
+
facets,
|
|
18612
|
+
previous,
|
|
18613
|
+
watermark,
|
|
18614
|
+
options.reviewedMemoryIds
|
|
18615
|
+
);
|
|
18584
18616
|
const settled = await Promise.allSettled(
|
|
18585
18617
|
facets.map(async (facet) => {
|
|
18586
18618
|
const prior = previous?.sections.find((s) => s.key === facet.key);
|
|
@@ -18641,7 +18673,7 @@ function computeVaultWatermark(memories) {
|
|
|
18641
18673
|
}
|
|
18642
18674
|
return max;
|
|
18643
18675
|
}
|
|
18644
|
-
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark) {
|
|
18676
|
+
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark, reviewedMemoryIds) {
|
|
18645
18677
|
const allKeys = new Set(facets.map((f) => f.key));
|
|
18646
18678
|
if (previous && watermark < previous.vaultWatermark) return allKeys;
|
|
18647
18679
|
if (!previous) return allKeys;
|
|
@@ -18664,9 +18696,13 @@ async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark)
|
|
|
18664
18696
|
if (!previous.sections.some((s) => s.key === facet.key)) stale.add(facet.key);
|
|
18665
18697
|
}
|
|
18666
18698
|
const citedIds = new Set(previous.sections.flatMap((s) => s.sourceMemoryIds));
|
|
18667
|
-
|
|
18699
|
+
let toAttribute = changed.filter(
|
|
18668
18700
|
(m) => !m.isDeleted && !m.supersededBy && !citedIds.has(m.uniqueId)
|
|
18669
18701
|
);
|
|
18702
|
+
if (reviewedMemoryIds !== void 0) {
|
|
18703
|
+
const allowed = new Set(reviewedMemoryIds);
|
|
18704
|
+
toAttribute = toAttribute.filter((m) => allowed.has(m.uniqueId));
|
|
18705
|
+
}
|
|
18670
18706
|
if (toAttribute.length > 0) {
|
|
18671
18707
|
const attributed = await attributeFacts(ctx, toAttribute, facets);
|
|
18672
18708
|
if (attributed === null) return allKeys;
|
package/dist/react/index.d.mts
CHANGED
|
@@ -703,7 +703,7 @@ type LlmapiResponseReasoning = {
|
|
|
703
703
|
*/
|
|
704
704
|
summary?: string;
|
|
705
705
|
};
|
|
706
|
-
type LlmapiResponseResponse = {
|
|
706
|
+
type LlmapiResponseResponse$1 = {
|
|
707
707
|
/**
|
|
708
708
|
* ClientInjectedTools are tool names the client provided in the original request.
|
|
709
709
|
*/
|
|
@@ -1669,6 +1669,30 @@ type LlmapiChatCompletionUsage = OpenaiCompletionUsage & {
|
|
|
1669
1669
|
* strategies/completions.ts `buildFinalResponse`. See that TODO for the full
|
|
1670
1670
|
* deprecation plan.
|
|
1671
1671
|
*/
|
|
1672
|
+
/**
|
|
1673
|
+
* Add the Responses API's terminal-state fields, which the portal's generated
|
|
1674
|
+
* schema does not declare.
|
|
1675
|
+
*
|
|
1676
|
+
* Without them the two transports are asymmetric: a completions consumer reads
|
|
1677
|
+
* `choices[0].finish_reason` and can see a turn cut off at the output ceiling,
|
|
1678
|
+
* while a Responses consumer has no field to read at all — the truncation the
|
|
1679
|
+
* SDK *did* detect (see the normalization in `strategies/responses.ts`) died at
|
|
1680
|
+
* the stream boundary. `runToolLoop` works around this with `terminalState` on
|
|
1681
|
+
* its own result, but a caller holding only a response object cannot (#805).
|
|
1682
|
+
*
|
|
1683
|
+
* These are standard OpenAI Responses fields, so this widens the type toward
|
|
1684
|
+
* the wire rather than inventing shape: they are optional because a
|
|
1685
|
+
* non-streaming direct call returns only what the portal serializes today.
|
|
1686
|
+
* Drop the override once the portal declares them upstream.
|
|
1687
|
+
*/
|
|
1688
|
+
type LlmapiResponseResponse = LlmapiResponseResponse$1 & {
|
|
1689
|
+
/** `"completed"` | `"incomplete"` — the turn's own status, not an output item's. */
|
|
1690
|
+
status?: string;
|
|
1691
|
+
/** Present when `status` is `"incomplete"`; `"max_output_tokens"` is a truncation. */
|
|
1692
|
+
incomplete_details?: {
|
|
1693
|
+
reason?: string;
|
|
1694
|
+
};
|
|
1695
|
+
};
|
|
1672
1696
|
type LlmapiChatCompletionResponse = Omit<LlmapiChatCompletionResponse$1, "usage"> & {
|
|
1673
1697
|
usage?: LlmapiChatCompletionUsage;
|
|
1674
1698
|
inference_id?: string;
|
|
@@ -2390,6 +2414,21 @@ type StepFinishEvent = {
|
|
|
2390
2414
|
inputTokens?: number;
|
|
2391
2415
|
outputTokens?: number;
|
|
2392
2416
|
};
|
|
2417
|
+
/**
|
|
2418
|
+
* The round's own finish reason, as the provider sent it — `"length"` means
|
|
2419
|
+
* this round hit the output ceiling.
|
|
2420
|
+
*
|
|
2421
|
+
* Per-round, not per-turn: a round can truncate and the loop still recover on
|
|
2422
|
+
* the next one, which is why the loop does not treat it as an error on its
|
|
2423
|
+
* own (see the truncation guard below). Without it a consumer watching steps
|
|
2424
|
+
* cannot tell a round that said everything it meant to from one that was cut
|
|
2425
|
+
* off mid-argument — they differ only in this field (#805).
|
|
2426
|
+
*
|
|
2427
|
+
* Absent when the provider sent no finish reason. Note that no step event
|
|
2428
|
+
* fires for the round that *ends* a turn, so use {@link RunTerminalState} on
|
|
2429
|
+
* the result for the final round.
|
|
2430
|
+
*/
|
|
2431
|
+
finishReason?: string;
|
|
2393
2432
|
};
|
|
2394
2433
|
/** Capability header: tells the portal this client can resume a detached stream. Pinned with zeta-chain/ai-portal#1139. */
|
|
2395
2434
|
declare const STREAM_RESUMABLE_HEADER = "X-Stream-Resumable";
|
package/dist/react/index.d.ts
CHANGED
|
@@ -703,7 +703,7 @@ type LlmapiResponseReasoning = {
|
|
|
703
703
|
*/
|
|
704
704
|
summary?: string;
|
|
705
705
|
};
|
|
706
|
-
type LlmapiResponseResponse = {
|
|
706
|
+
type LlmapiResponseResponse$1 = {
|
|
707
707
|
/**
|
|
708
708
|
* ClientInjectedTools are tool names the client provided in the original request.
|
|
709
709
|
*/
|
|
@@ -1669,6 +1669,30 @@ type LlmapiChatCompletionUsage = OpenaiCompletionUsage & {
|
|
|
1669
1669
|
* strategies/completions.ts `buildFinalResponse`. See that TODO for the full
|
|
1670
1670
|
* deprecation plan.
|
|
1671
1671
|
*/
|
|
1672
|
+
/**
|
|
1673
|
+
* Add the Responses API's terminal-state fields, which the portal's generated
|
|
1674
|
+
* schema does not declare.
|
|
1675
|
+
*
|
|
1676
|
+
* Without them the two transports are asymmetric: a completions consumer reads
|
|
1677
|
+
* `choices[0].finish_reason` and can see a turn cut off at the output ceiling,
|
|
1678
|
+
* while a Responses consumer has no field to read at all — the truncation the
|
|
1679
|
+
* SDK *did* detect (see the normalization in `strategies/responses.ts`) died at
|
|
1680
|
+
* the stream boundary. `runToolLoop` works around this with `terminalState` on
|
|
1681
|
+
* its own result, but a caller holding only a response object cannot (#805).
|
|
1682
|
+
*
|
|
1683
|
+
* These are standard OpenAI Responses fields, so this widens the type toward
|
|
1684
|
+
* the wire rather than inventing shape: they are optional because a
|
|
1685
|
+
* non-streaming direct call returns only what the portal serializes today.
|
|
1686
|
+
* Drop the override once the portal declares them upstream.
|
|
1687
|
+
*/
|
|
1688
|
+
type LlmapiResponseResponse = LlmapiResponseResponse$1 & {
|
|
1689
|
+
/** `"completed"` | `"incomplete"` — the turn's own status, not an output item's. */
|
|
1690
|
+
status?: string;
|
|
1691
|
+
/** Present when `status` is `"incomplete"`; `"max_output_tokens"` is a truncation. */
|
|
1692
|
+
incomplete_details?: {
|
|
1693
|
+
reason?: string;
|
|
1694
|
+
};
|
|
1695
|
+
};
|
|
1672
1696
|
type LlmapiChatCompletionResponse = Omit<LlmapiChatCompletionResponse$1, "usage"> & {
|
|
1673
1697
|
usage?: LlmapiChatCompletionUsage;
|
|
1674
1698
|
inference_id?: string;
|
|
@@ -2390,6 +2414,21 @@ type StepFinishEvent = {
|
|
|
2390
2414
|
inputTokens?: number;
|
|
2391
2415
|
outputTokens?: number;
|
|
2392
2416
|
};
|
|
2417
|
+
/**
|
|
2418
|
+
* The round's own finish reason, as the provider sent it — `"length"` means
|
|
2419
|
+
* this round hit the output ceiling.
|
|
2420
|
+
*
|
|
2421
|
+
* Per-round, not per-turn: a round can truncate and the loop still recover on
|
|
2422
|
+
* the next one, which is why the loop does not treat it as an error on its
|
|
2423
|
+
* own (see the truncation guard below). Without it a consumer watching steps
|
|
2424
|
+
* cannot tell a round that said everything it meant to from one that was cut
|
|
2425
|
+
* off mid-argument — they differ only in this field (#805).
|
|
2426
|
+
*
|
|
2427
|
+
* Absent when the provider sent no finish reason. Note that no step event
|
|
2428
|
+
* fires for the round that *ends* a turn, so use {@link RunTerminalState} on
|
|
2429
|
+
* the result for the final round.
|
|
2430
|
+
*/
|
|
2431
|
+
finishReason?: string;
|
|
2393
2432
|
};
|
|
2394
2433
|
/** Capability header: tells the portal this client can resume a detached stream. Pinned with zeta-chain/ai-portal#1139. */
|
|
2395
2434
|
declare const STREAM_RESUMABLE_HEADER = "X-Stream-Resumable";
|
package/dist/react/index.mjs
CHANGED
|
@@ -1700,6 +1700,16 @@ var ResponsesStrategy = class {
|
|
|
1700
1700
|
}));
|
|
1701
1701
|
mergeToolCallEventsIntoAccumulator(accumulator, toolCallEvents);
|
|
1702
1702
|
}
|
|
1703
|
+
const fbStatus = typeof resp.status === "string" ? resp.status : void 0;
|
|
1704
|
+
const fbIncompleteReason = resp.incomplete_details?.reason;
|
|
1705
|
+
const fbFinishReason = typeof resp.finish_reason === "string" ? resp.finish_reason : void 0;
|
|
1706
|
+
if (fbStatus !== void 0) accumulator.responseStatus = fbStatus;
|
|
1707
|
+
if (fbIncompleteReason !== void 0) accumulator.incompleteReason = fbIncompleteReason;
|
|
1708
|
+
if (fbFinishReason !== void 0) {
|
|
1709
|
+
accumulator.finishReason = fbFinishReason;
|
|
1710
|
+
} else if (fbStatus === "incomplete" && fbIncompleteReason === "max_output_tokens") {
|
|
1711
|
+
accumulator.finishReason = "length";
|
|
1712
|
+
}
|
|
1703
1713
|
return result;
|
|
1704
1714
|
}
|
|
1705
1715
|
if (typedChunk.type === "response.created" && typedChunk.response) {
|
|
@@ -1735,6 +1745,8 @@ var ResponsesStrategy = class {
|
|
|
1735
1745
|
if (looksIncomplete && resp?.incomplete_details?.reason === "max_output_tokens") {
|
|
1736
1746
|
accumulator.finishReason = "length";
|
|
1737
1747
|
}
|
|
1748
|
+
accumulator.responseStatus = looksIncomplete ? "incomplete" : resp?.status;
|
|
1749
|
+
accumulator.incompleteReason = resp?.incomplete_details?.reason;
|
|
1738
1750
|
if (typedChunk.response?.tools_checksum && !accumulator.toolsChecksum) {
|
|
1739
1751
|
accumulator.toolsChecksum = typedChunk.response.tools_checksum;
|
|
1740
1752
|
}
|
|
@@ -2003,7 +2015,17 @@ var ResponsesStrategy = class {
|
|
|
2003
2015
|
output,
|
|
2004
2016
|
usage: Object.keys(accumulator.usage).length > 0 ? accumulator.usage : void 0,
|
|
2005
2017
|
tools_checksum: accumulator.toolsChecksum,
|
|
2006
|
-
tool_call_events: accumulator.toolCallEvents
|
|
2018
|
+
tool_call_events: accumulator.toolCallEvents,
|
|
2019
|
+
// Response-level terminal state (#805). Note the individual output items
|
|
2020
|
+
// above hardcode `status: "completed"` — that is the item's own status
|
|
2021
|
+
// and says nothing about the turn. Only these two fields can tell a
|
|
2022
|
+
// caller the turn was cut off, and until now neither survived the stream.
|
|
2023
|
+
// Omitted rather than emitted as `undefined` so a clean turn's response
|
|
2024
|
+
// shape is unchanged.
|
|
2025
|
+
...accumulator.responseStatus !== void 0 && { status: accumulator.responseStatus },
|
|
2026
|
+
...accumulator.incompleteReason !== void 0 && {
|
|
2027
|
+
incomplete_details: { reason: accumulator.incompleteReason }
|
|
2028
|
+
}
|
|
2007
2029
|
};
|
|
2008
2030
|
}
|
|
2009
2031
|
};
|
|
@@ -3022,6 +3044,9 @@ Executing tool: ${toolInfo}
|
|
|
3022
3044
|
usage: {
|
|
3023
3045
|
inputTokens: currentAccumulator.usage.prompt_tokens,
|
|
3024
3046
|
outputTokens: currentAccumulator.usage.completion_tokens
|
|
3047
|
+
},
|
|
3048
|
+
...currentAccumulator.finishReason !== void 0 && {
|
|
3049
|
+
finishReason: currentAccumulator.finishReason
|
|
3025
3050
|
}
|
|
3026
3051
|
});
|
|
3027
3052
|
}
|
|
@@ -9054,7 +9079,14 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
9054
9079
|
observationTrends
|
|
9055
9080
|
};
|
|
9056
9081
|
}
|
|
9057
|
-
const staleKeys = await computeStaleFacetKeys(
|
|
9082
|
+
const staleKeys = await computeStaleFacetKeys(
|
|
9083
|
+
ctx,
|
|
9084
|
+
memories,
|
|
9085
|
+
facets,
|
|
9086
|
+
previous,
|
|
9087
|
+
watermark,
|
|
9088
|
+
options.reviewedMemoryIds
|
|
9089
|
+
);
|
|
9058
9090
|
const settled = await Promise.allSettled(
|
|
9059
9091
|
facets.map(async (facet) => {
|
|
9060
9092
|
const prior = previous?.sections.find((s) => s.key === facet.key);
|
|
@@ -9115,7 +9147,7 @@ function computeVaultWatermark(memories) {
|
|
|
9115
9147
|
}
|
|
9116
9148
|
return max;
|
|
9117
9149
|
}
|
|
9118
|
-
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark) {
|
|
9150
|
+
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark, reviewedMemoryIds) {
|
|
9119
9151
|
const allKeys = new Set(facets.map((f) => f.key));
|
|
9120
9152
|
if (previous && watermark < previous.vaultWatermark) return allKeys;
|
|
9121
9153
|
if (!previous) return allKeys;
|
|
@@ -9138,9 +9170,13 @@ async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark)
|
|
|
9138
9170
|
if (!previous.sections.some((s) => s.key === facet.key)) stale.add(facet.key);
|
|
9139
9171
|
}
|
|
9140
9172
|
const citedIds = new Set(previous.sections.flatMap((s) => s.sourceMemoryIds));
|
|
9141
|
-
|
|
9173
|
+
let toAttribute = changed.filter(
|
|
9142
9174
|
(m) => !m.isDeleted && !m.supersededBy && !citedIds.has(m.uniqueId)
|
|
9143
9175
|
);
|
|
9176
|
+
if (reviewedMemoryIds !== void 0) {
|
|
9177
|
+
const allowed = new Set(reviewedMemoryIds);
|
|
9178
|
+
toAttribute = toAttribute.filter((m) => allowed.has(m.uniqueId));
|
|
9179
|
+
}
|
|
9144
9180
|
if (toAttribute.length > 0) {
|
|
9145
9181
|
const attributed = await attributeFacts(ctx, toAttribute, facets);
|
|
9146
9182
|
if (attributed === null) return allKeys;
|
package/dist/server/index.cjs
CHANGED
|
@@ -30351,7 +30351,14 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
30351
30351
|
observationTrends
|
|
30352
30352
|
};
|
|
30353
30353
|
}
|
|
30354
|
-
const staleKeys = await computeStaleFacetKeys(
|
|
30354
|
+
const staleKeys = await computeStaleFacetKeys(
|
|
30355
|
+
ctx,
|
|
30356
|
+
memories,
|
|
30357
|
+
facets,
|
|
30358
|
+
previous,
|
|
30359
|
+
watermark,
|
|
30360
|
+
options.reviewedMemoryIds
|
|
30361
|
+
);
|
|
30355
30362
|
const settled = await Promise.allSettled(
|
|
30356
30363
|
facets.map(async (facet) => {
|
|
30357
30364
|
const prior = previous?.sections.find((s) => s.key === facet.key);
|
|
@@ -30412,7 +30419,7 @@ function computeVaultWatermark(memories) {
|
|
|
30412
30419
|
}
|
|
30413
30420
|
return max;
|
|
30414
30421
|
}
|
|
30415
|
-
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark) {
|
|
30422
|
+
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark, reviewedMemoryIds) {
|
|
30416
30423
|
const allKeys = new Set(facets.map((f) => f.key));
|
|
30417
30424
|
if (previous && watermark < previous.vaultWatermark) return allKeys;
|
|
30418
30425
|
if (!previous) return allKeys;
|
|
@@ -30435,9 +30442,13 @@ async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark)
|
|
|
30435
30442
|
if (!previous.sections.some((s) => s.key === facet.key)) stale.add(facet.key);
|
|
30436
30443
|
}
|
|
30437
30444
|
const citedIds = new Set(previous.sections.flatMap((s) => s.sourceMemoryIds));
|
|
30438
|
-
|
|
30445
|
+
let toAttribute = changed.filter(
|
|
30439
30446
|
(m) => !m.isDeleted && !m.supersededBy && !citedIds.has(m.uniqueId)
|
|
30440
30447
|
);
|
|
30448
|
+
if (reviewedMemoryIds !== void 0) {
|
|
30449
|
+
const allowed = new Set(reviewedMemoryIds);
|
|
30450
|
+
toAttribute = toAttribute.filter((m) => allowed.has(m.uniqueId));
|
|
30451
|
+
}
|
|
30441
30452
|
if (toAttribute.length > 0) {
|
|
30442
30453
|
const attributed = await attributeFacts(ctx, toAttribute, facets);
|
|
30443
30454
|
if (attributed === null) return allKeys;
|
|
@@ -34383,6 +34394,16 @@ var ResponsesStrategy = class {
|
|
|
34383
34394
|
}));
|
|
34384
34395
|
mergeToolCallEventsIntoAccumulator(accumulator, toolCallEvents);
|
|
34385
34396
|
}
|
|
34397
|
+
const fbStatus = typeof resp.status === "string" ? resp.status : void 0;
|
|
34398
|
+
const fbIncompleteReason = resp.incomplete_details?.reason;
|
|
34399
|
+
const fbFinishReason = typeof resp.finish_reason === "string" ? resp.finish_reason : void 0;
|
|
34400
|
+
if (fbStatus !== void 0) accumulator.responseStatus = fbStatus;
|
|
34401
|
+
if (fbIncompleteReason !== void 0) accumulator.incompleteReason = fbIncompleteReason;
|
|
34402
|
+
if (fbFinishReason !== void 0) {
|
|
34403
|
+
accumulator.finishReason = fbFinishReason;
|
|
34404
|
+
} else if (fbStatus === "incomplete" && fbIncompleteReason === "max_output_tokens") {
|
|
34405
|
+
accumulator.finishReason = "length";
|
|
34406
|
+
}
|
|
34386
34407
|
return result;
|
|
34387
34408
|
}
|
|
34388
34409
|
if (typedChunk.type === "response.created" && typedChunk.response) {
|
|
@@ -34418,6 +34439,8 @@ var ResponsesStrategy = class {
|
|
|
34418
34439
|
if (looksIncomplete && resp?.incomplete_details?.reason === "max_output_tokens") {
|
|
34419
34440
|
accumulator.finishReason = "length";
|
|
34420
34441
|
}
|
|
34442
|
+
accumulator.responseStatus = looksIncomplete ? "incomplete" : resp?.status;
|
|
34443
|
+
accumulator.incompleteReason = resp?.incomplete_details?.reason;
|
|
34421
34444
|
if (typedChunk.response?.tools_checksum && !accumulator.toolsChecksum) {
|
|
34422
34445
|
accumulator.toolsChecksum = typedChunk.response.tools_checksum;
|
|
34423
34446
|
}
|
|
@@ -34686,7 +34709,17 @@ var ResponsesStrategy = class {
|
|
|
34686
34709
|
output,
|
|
34687
34710
|
usage: Object.keys(accumulator.usage).length > 0 ? accumulator.usage : void 0,
|
|
34688
34711
|
tools_checksum: accumulator.toolsChecksum,
|
|
34689
|
-
tool_call_events: accumulator.toolCallEvents
|
|
34712
|
+
tool_call_events: accumulator.toolCallEvents,
|
|
34713
|
+
// Response-level terminal state (#805). Note the individual output items
|
|
34714
|
+
// above hardcode `status: "completed"` — that is the item's own status
|
|
34715
|
+
// and says nothing about the turn. Only these two fields can tell a
|
|
34716
|
+
// caller the turn was cut off, and until now neither survived the stream.
|
|
34717
|
+
// Omitted rather than emitted as `undefined` so a clean turn's response
|
|
34718
|
+
// shape is unchanged.
|
|
34719
|
+
...accumulator.responseStatus !== void 0 && { status: accumulator.responseStatus },
|
|
34720
|
+
...accumulator.incompleteReason !== void 0 && {
|
|
34721
|
+
incomplete_details: { reason: accumulator.incompleteReason }
|
|
34722
|
+
}
|
|
34690
34723
|
};
|
|
34691
34724
|
}
|
|
34692
34725
|
};
|
|
@@ -35705,6 +35738,9 @@ Executing tool: ${toolInfo}
|
|
|
35705
35738
|
usage: {
|
|
35706
35739
|
inputTokens: currentAccumulator.usage.prompt_tokens,
|
|
35707
35740
|
outputTokens: currentAccumulator.usage.completion_tokens
|
|
35741
|
+
},
|
|
35742
|
+
...currentAccumulator.finishReason !== void 0 && {
|
|
35743
|
+
finishReason: currentAccumulator.finishReason
|
|
35708
35744
|
}
|
|
35709
35745
|
});
|
|
35710
35746
|
}
|
package/dist/server/index.d.mts
CHANGED
|
@@ -830,7 +830,7 @@ type LlmapiResponseReasoning = {
|
|
|
830
830
|
*/
|
|
831
831
|
summary?: string;
|
|
832
832
|
};
|
|
833
|
-
type LlmapiResponseResponse = {
|
|
833
|
+
type LlmapiResponseResponse$1 = {
|
|
834
834
|
/**
|
|
835
835
|
* ClientInjectedTools are tool names the client provided in the original request.
|
|
836
836
|
*/
|
|
@@ -1613,6 +1613,30 @@ type LlmapiChatCompletionUsage = OpenaiCompletionUsage & {
|
|
|
1613
1613
|
* strategies/completions.ts `buildFinalResponse`. See that TODO for the full
|
|
1614
1614
|
* deprecation plan.
|
|
1615
1615
|
*/
|
|
1616
|
+
/**
|
|
1617
|
+
* Add the Responses API's terminal-state fields, which the portal's generated
|
|
1618
|
+
* schema does not declare.
|
|
1619
|
+
*
|
|
1620
|
+
* Without them the two transports are asymmetric: a completions consumer reads
|
|
1621
|
+
* `choices[0].finish_reason` and can see a turn cut off at the output ceiling,
|
|
1622
|
+
* while a Responses consumer has no field to read at all — the truncation the
|
|
1623
|
+
* SDK *did* detect (see the normalization in `strategies/responses.ts`) died at
|
|
1624
|
+
* the stream boundary. `runToolLoop` works around this with `terminalState` on
|
|
1625
|
+
* its own result, but a caller holding only a response object cannot (#805).
|
|
1626
|
+
*
|
|
1627
|
+
* These are standard OpenAI Responses fields, so this widens the type toward
|
|
1628
|
+
* the wire rather than inventing shape: they are optional because a
|
|
1629
|
+
* non-streaming direct call returns only what the portal serializes today.
|
|
1630
|
+
* Drop the override once the portal declares them upstream.
|
|
1631
|
+
*/
|
|
1632
|
+
type LlmapiResponseResponse = LlmapiResponseResponse$1 & {
|
|
1633
|
+
/** `"completed"` | `"incomplete"` — the turn's own status, not an output item's. */
|
|
1634
|
+
status?: string;
|
|
1635
|
+
/** Present when `status` is `"incomplete"`; `"max_output_tokens"` is a truncation. */
|
|
1636
|
+
incomplete_details?: {
|
|
1637
|
+
reason?: string;
|
|
1638
|
+
};
|
|
1639
|
+
};
|
|
1616
1640
|
type LlmapiChatCompletionResponse = Omit<LlmapiChatCompletionResponse$1, "usage"> & {
|
|
1617
1641
|
usage?: LlmapiChatCompletionUsage;
|
|
1618
1642
|
inference_id?: string;
|
|
@@ -2231,6 +2255,21 @@ type StepFinishEvent = {
|
|
|
2231
2255
|
inputTokens?: number;
|
|
2232
2256
|
outputTokens?: number;
|
|
2233
2257
|
};
|
|
2258
|
+
/**
|
|
2259
|
+
* The round's own finish reason, as the provider sent it — `"length"` means
|
|
2260
|
+
* this round hit the output ceiling.
|
|
2261
|
+
*
|
|
2262
|
+
* Per-round, not per-turn: a round can truncate and the loop still recover on
|
|
2263
|
+
* the next one, which is why the loop does not treat it as an error on its
|
|
2264
|
+
* own (see the truncation guard below). Without it a consumer watching steps
|
|
2265
|
+
* cannot tell a round that said everything it meant to from one that was cut
|
|
2266
|
+
* off mid-argument — they differ only in this field (#805).
|
|
2267
|
+
*
|
|
2268
|
+
* Absent when the provider sent no finish reason. Note that no step event
|
|
2269
|
+
* fires for the round that *ends* a turn, so use {@link RunTerminalState} on
|
|
2270
|
+
* the result for the final round.
|
|
2271
|
+
*/
|
|
2272
|
+
finishReason?: string;
|
|
2234
2273
|
};
|
|
2235
2274
|
/**
|
|
2236
2275
|
* Options for `runToolLoop`.
|
|
@@ -2444,13 +2483,14 @@ type RunToolLoopOptions = {
|
|
|
2444
2483
|
* specific values). `undefined` when the stream carried no finish reason at all.
|
|
2445
2484
|
*
|
|
2446
2485
|
* Exposed because neither response shape reliably carries it out to a caller.
|
|
2447
|
-
* The Responses
|
|
2448
|
-
*
|
|
2449
|
-
*
|
|
2450
|
-
*
|
|
2451
|
-
* `choices[0].finish_reason`, but omits `tool_calls` entirely when
|
|
2452
|
-
* none, so a caller sniffing the response cannot tell "no tool calls"
|
|
2453
|
-
* "field absent".
|
|
2486
|
+
* The Responses shape now carries `status` / `incomplete_details` — added in
|
|
2487
|
+
* `clientCompat` and emitted by `buildFinalResponse` — but only in the
|
|
2488
|
+
* Responses vocabulary, so a caller reading it has to translate
|
|
2489
|
+
* `incomplete_details.reason === "max_output_tokens"` itself. Completions
|
|
2490
|
+
* exposes `choices[0].finish_reason`, but omits `tool_calls` entirely when
|
|
2491
|
+
* there are none, so a caller sniffing the response cannot tell "no tool calls"
|
|
2492
|
+
* from "field absent". This field answers both questions in one vocabulary,
|
|
2493
|
+
* for either transport.
|
|
2454
2494
|
*
|
|
2455
2495
|
* The loop already knows both, unambiguously and identically for either API.
|
|
2456
2496
|
* Reporting them here means callers and test harnesses stop reverse-engineering
|
package/dist/server/index.d.ts
CHANGED
|
@@ -830,7 +830,7 @@ type LlmapiResponseReasoning = {
|
|
|
830
830
|
*/
|
|
831
831
|
summary?: string;
|
|
832
832
|
};
|
|
833
|
-
type LlmapiResponseResponse = {
|
|
833
|
+
type LlmapiResponseResponse$1 = {
|
|
834
834
|
/**
|
|
835
835
|
* ClientInjectedTools are tool names the client provided in the original request.
|
|
836
836
|
*/
|
|
@@ -1613,6 +1613,30 @@ type LlmapiChatCompletionUsage = OpenaiCompletionUsage & {
|
|
|
1613
1613
|
* strategies/completions.ts `buildFinalResponse`. See that TODO for the full
|
|
1614
1614
|
* deprecation plan.
|
|
1615
1615
|
*/
|
|
1616
|
+
/**
|
|
1617
|
+
* Add the Responses API's terminal-state fields, which the portal's generated
|
|
1618
|
+
* schema does not declare.
|
|
1619
|
+
*
|
|
1620
|
+
* Without them the two transports are asymmetric: a completions consumer reads
|
|
1621
|
+
* `choices[0].finish_reason` and can see a turn cut off at the output ceiling,
|
|
1622
|
+
* while a Responses consumer has no field to read at all — the truncation the
|
|
1623
|
+
* SDK *did* detect (see the normalization in `strategies/responses.ts`) died at
|
|
1624
|
+
* the stream boundary. `runToolLoop` works around this with `terminalState` on
|
|
1625
|
+
* its own result, but a caller holding only a response object cannot (#805).
|
|
1626
|
+
*
|
|
1627
|
+
* These are standard OpenAI Responses fields, so this widens the type toward
|
|
1628
|
+
* the wire rather than inventing shape: they are optional because a
|
|
1629
|
+
* non-streaming direct call returns only what the portal serializes today.
|
|
1630
|
+
* Drop the override once the portal declares them upstream.
|
|
1631
|
+
*/
|
|
1632
|
+
type LlmapiResponseResponse = LlmapiResponseResponse$1 & {
|
|
1633
|
+
/** `"completed"` | `"incomplete"` — the turn's own status, not an output item's. */
|
|
1634
|
+
status?: string;
|
|
1635
|
+
/** Present when `status` is `"incomplete"`; `"max_output_tokens"` is a truncation. */
|
|
1636
|
+
incomplete_details?: {
|
|
1637
|
+
reason?: string;
|
|
1638
|
+
};
|
|
1639
|
+
};
|
|
1616
1640
|
type LlmapiChatCompletionResponse = Omit<LlmapiChatCompletionResponse$1, "usage"> & {
|
|
1617
1641
|
usage?: LlmapiChatCompletionUsage;
|
|
1618
1642
|
inference_id?: string;
|
|
@@ -2231,6 +2255,21 @@ type StepFinishEvent = {
|
|
|
2231
2255
|
inputTokens?: number;
|
|
2232
2256
|
outputTokens?: number;
|
|
2233
2257
|
};
|
|
2258
|
+
/**
|
|
2259
|
+
* The round's own finish reason, as the provider sent it — `"length"` means
|
|
2260
|
+
* this round hit the output ceiling.
|
|
2261
|
+
*
|
|
2262
|
+
* Per-round, not per-turn: a round can truncate and the loop still recover on
|
|
2263
|
+
* the next one, which is why the loop does not treat it as an error on its
|
|
2264
|
+
* own (see the truncation guard below). Without it a consumer watching steps
|
|
2265
|
+
* cannot tell a round that said everything it meant to from one that was cut
|
|
2266
|
+
* off mid-argument — they differ only in this field (#805).
|
|
2267
|
+
*
|
|
2268
|
+
* Absent when the provider sent no finish reason. Note that no step event
|
|
2269
|
+
* fires for the round that *ends* a turn, so use {@link RunTerminalState} on
|
|
2270
|
+
* the result for the final round.
|
|
2271
|
+
*/
|
|
2272
|
+
finishReason?: string;
|
|
2234
2273
|
};
|
|
2235
2274
|
/**
|
|
2236
2275
|
* Options for `runToolLoop`.
|
|
@@ -2444,13 +2483,14 @@ type RunToolLoopOptions = {
|
|
|
2444
2483
|
* specific values). `undefined` when the stream carried no finish reason at all.
|
|
2445
2484
|
*
|
|
2446
2485
|
* Exposed because neither response shape reliably carries it out to a caller.
|
|
2447
|
-
* The Responses
|
|
2448
|
-
*
|
|
2449
|
-
*
|
|
2450
|
-
*
|
|
2451
|
-
* `choices[0].finish_reason`, but omits `tool_calls` entirely when
|
|
2452
|
-
* none, so a caller sniffing the response cannot tell "no tool calls"
|
|
2453
|
-
* "field absent".
|
|
2486
|
+
* The Responses shape now carries `status` / `incomplete_details` — added in
|
|
2487
|
+
* `clientCompat` and emitted by `buildFinalResponse` — but only in the
|
|
2488
|
+
* Responses vocabulary, so a caller reading it has to translate
|
|
2489
|
+
* `incomplete_details.reason === "max_output_tokens"` itself. Completions
|
|
2490
|
+
* exposes `choices[0].finish_reason`, but omits `tool_calls` entirely when
|
|
2491
|
+
* there are none, so a caller sniffing the response cannot tell "no tool calls"
|
|
2492
|
+
* from "field absent". This field answers both questions in one vocabulary,
|
|
2493
|
+
* for either transport.
|
|
2454
2494
|
*
|
|
2455
2495
|
* The loop already knows both, unambiguously and identically for either API.
|
|
2456
2496
|
* Reporting them here means callers and test harnesses stop reverse-engineering
|
package/dist/server/index.mjs
CHANGED
|
@@ -7061,7 +7061,14 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
7061
7061
|
observationTrends
|
|
7062
7062
|
};
|
|
7063
7063
|
}
|
|
7064
|
-
const staleKeys = await computeStaleFacetKeys(
|
|
7064
|
+
const staleKeys = await computeStaleFacetKeys(
|
|
7065
|
+
ctx,
|
|
7066
|
+
memories,
|
|
7067
|
+
facets,
|
|
7068
|
+
previous,
|
|
7069
|
+
watermark,
|
|
7070
|
+
options.reviewedMemoryIds
|
|
7071
|
+
);
|
|
7065
7072
|
const settled = await Promise.allSettled(
|
|
7066
7073
|
facets.map(async (facet) => {
|
|
7067
7074
|
const prior = previous?.sections.find((s) => s.key === facet.key);
|
|
@@ -7122,7 +7129,7 @@ function computeVaultWatermark(memories) {
|
|
|
7122
7129
|
}
|
|
7123
7130
|
return max;
|
|
7124
7131
|
}
|
|
7125
|
-
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark) {
|
|
7132
|
+
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark, reviewedMemoryIds) {
|
|
7126
7133
|
const allKeys = new Set(facets.map((f) => f.key));
|
|
7127
7134
|
if (previous && watermark < previous.vaultWatermark) return allKeys;
|
|
7128
7135
|
if (!previous) return allKeys;
|
|
@@ -7145,9 +7152,13 @@ async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark)
|
|
|
7145
7152
|
if (!previous.sections.some((s) => s.key === facet.key)) stale.add(facet.key);
|
|
7146
7153
|
}
|
|
7147
7154
|
const citedIds = new Set(previous.sections.flatMap((s) => s.sourceMemoryIds));
|
|
7148
|
-
|
|
7155
|
+
let toAttribute = changed.filter(
|
|
7149
7156
|
(m) => !m.isDeleted && !m.supersededBy && !citedIds.has(m.uniqueId)
|
|
7150
7157
|
);
|
|
7158
|
+
if (reviewedMemoryIds !== void 0) {
|
|
7159
|
+
const allowed = new Set(reviewedMemoryIds);
|
|
7160
|
+
toAttribute = toAttribute.filter((m) => allowed.has(m.uniqueId));
|
|
7161
|
+
}
|
|
7151
7162
|
if (toAttribute.length > 0) {
|
|
7152
7163
|
const attributed = await attributeFacts(ctx, toAttribute, facets);
|
|
7153
7164
|
if (attributed === null) return allKeys;
|
|
@@ -11054,6 +11065,16 @@ var ResponsesStrategy = class {
|
|
|
11054
11065
|
}));
|
|
11055
11066
|
mergeToolCallEventsIntoAccumulator(accumulator, toolCallEvents);
|
|
11056
11067
|
}
|
|
11068
|
+
const fbStatus = typeof resp.status === "string" ? resp.status : void 0;
|
|
11069
|
+
const fbIncompleteReason = resp.incomplete_details?.reason;
|
|
11070
|
+
const fbFinishReason = typeof resp.finish_reason === "string" ? resp.finish_reason : void 0;
|
|
11071
|
+
if (fbStatus !== void 0) accumulator.responseStatus = fbStatus;
|
|
11072
|
+
if (fbIncompleteReason !== void 0) accumulator.incompleteReason = fbIncompleteReason;
|
|
11073
|
+
if (fbFinishReason !== void 0) {
|
|
11074
|
+
accumulator.finishReason = fbFinishReason;
|
|
11075
|
+
} else if (fbStatus === "incomplete" && fbIncompleteReason === "max_output_tokens") {
|
|
11076
|
+
accumulator.finishReason = "length";
|
|
11077
|
+
}
|
|
11057
11078
|
return result;
|
|
11058
11079
|
}
|
|
11059
11080
|
if (typedChunk.type === "response.created" && typedChunk.response) {
|
|
@@ -11089,6 +11110,8 @@ var ResponsesStrategy = class {
|
|
|
11089
11110
|
if (looksIncomplete && resp?.incomplete_details?.reason === "max_output_tokens") {
|
|
11090
11111
|
accumulator.finishReason = "length";
|
|
11091
11112
|
}
|
|
11113
|
+
accumulator.responseStatus = looksIncomplete ? "incomplete" : resp?.status;
|
|
11114
|
+
accumulator.incompleteReason = resp?.incomplete_details?.reason;
|
|
11092
11115
|
if (typedChunk.response?.tools_checksum && !accumulator.toolsChecksum) {
|
|
11093
11116
|
accumulator.toolsChecksum = typedChunk.response.tools_checksum;
|
|
11094
11117
|
}
|
|
@@ -11357,7 +11380,17 @@ var ResponsesStrategy = class {
|
|
|
11357
11380
|
output,
|
|
11358
11381
|
usage: Object.keys(accumulator.usage).length > 0 ? accumulator.usage : void 0,
|
|
11359
11382
|
tools_checksum: accumulator.toolsChecksum,
|
|
11360
|
-
tool_call_events: accumulator.toolCallEvents
|
|
11383
|
+
tool_call_events: accumulator.toolCallEvents,
|
|
11384
|
+
// Response-level terminal state (#805). Note the individual output items
|
|
11385
|
+
// above hardcode `status: "completed"` — that is the item's own status
|
|
11386
|
+
// and says nothing about the turn. Only these two fields can tell a
|
|
11387
|
+
// caller the turn was cut off, and until now neither survived the stream.
|
|
11388
|
+
// Omitted rather than emitted as `undefined` so a clean turn's response
|
|
11389
|
+
// shape is unchanged.
|
|
11390
|
+
...accumulator.responseStatus !== void 0 && { status: accumulator.responseStatus },
|
|
11391
|
+
...accumulator.incompleteReason !== void 0 && {
|
|
11392
|
+
incomplete_details: { reason: accumulator.incompleteReason }
|
|
11393
|
+
}
|
|
11361
11394
|
};
|
|
11362
11395
|
}
|
|
11363
11396
|
};
|
|
@@ -12376,6 +12409,9 @@ Executing tool: ${toolInfo}
|
|
|
12376
12409
|
usage: {
|
|
12377
12410
|
inputTokens: currentAccumulator.usage.prompt_tokens,
|
|
12378
12411
|
outputTokens: currentAccumulator.usage.completion_tokens
|
|
12412
|
+
},
|
|
12413
|
+
...currentAccumulator.finishReason !== void 0 && {
|
|
12414
|
+
finishReason: currentAccumulator.finishReason
|
|
12379
12415
|
}
|
|
12380
12416
|
});
|
|
12381
12417
|
}
|