@code-yeongyu/senpi-ai 2026.10.26-1 → 2026.10.26-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/providers/data/.manifest.json +1 -1
- package/dist/providers/data/opengateway.json +1 -1
- package/dist/providers/data/openrouter.json +1 -1
- package/dist/tool-call-middleware/protocols/kimi-xtml/thinking-recovery-stream.js +37 -2
- package/dist/tool-call-middleware/recovery-event-stream.d.ts +12 -1
- package/dist/tool-call-middleware/recovery-event-stream.js +30 -4
- package/dist/tool-call-middleware/recovery-native-projection.d.ts +10 -0
- package/dist/tool-call-middleware/recovery-native-projection.js +36 -7
- package/dist/tool-call-middleware/recovery-stream-failure.js +3 -2
- package/dist/tool-call-middleware/recovery-stream-terminal.d.ts +6 -0
- package/dist/tool-call-middleware/recovery-stream-terminal.js +35 -17
- package/dist/tool-call-middleware/recovery-stream-wrapper.js +26 -12
- package/dist/tool-call-middleware/stream-wrapper.js +3 -1
- package/dist/utils/assistant-capture.d.ts +16 -0
- package/dist/utils/assistant-capture.js +51 -14
- package/package.json +2 -2
|
@@ -123,6 +123,7 @@ export function assistantEvents(source, onProgress) {
|
|
|
123
123
|
}) ?? source[Symbol.asyncIterator](),
|
|
124
124
|
};
|
|
125
125
|
}
|
|
126
|
+
/** Internal readers address a block by `capture.contentIndex ?? event.contentIndex`; the public index can drift (Google/Vertex). */
|
|
126
127
|
export function getAssistantCapture(event) {
|
|
127
128
|
return captures.get(event);
|
|
128
129
|
}
|
|
@@ -178,28 +179,44 @@ export function carryAssistantCapture(source, target, terminal) {
|
|
|
178
179
|
if (!capture)
|
|
179
180
|
return target;
|
|
180
181
|
try {
|
|
181
|
-
captures.set(target, terminal
|
|
182
|
-
? Object.freeze({
|
|
183
|
-
...capture,
|
|
184
|
-
message: freezeCapture({ ...terminal, content: terminal.content.map(publicBlock) }),
|
|
185
|
-
})
|
|
186
|
-
: capture);
|
|
182
|
+
captures.set(target, terminal ? terminalCapture(capture, terminal) : capture);
|
|
187
183
|
}
|
|
188
184
|
catch (error) {
|
|
189
185
|
dropCapture(source, error);
|
|
190
186
|
}
|
|
191
187
|
return target;
|
|
192
188
|
}
|
|
189
|
+
/** A terminal replaced downstream: its usage and message, plus every scalar that differs from the source terminal. */
|
|
190
|
+
function terminalCapture(capture, terminal) {
|
|
191
|
+
const metadata = { ...capture.metadata };
|
|
192
|
+
const previous = capture.message ?? {};
|
|
193
|
+
for (const key of new Set([...Object.keys(previous), ...Object.keys(terminal)])) {
|
|
194
|
+
if (key === "content" || key === "usage")
|
|
195
|
+
continue;
|
|
196
|
+
const value = Reflect.get(terminal, key);
|
|
197
|
+
if (!sameValue(value, Reflect.get(previous, key)))
|
|
198
|
+
metadata[key] = key in terminal ? value : null;
|
|
199
|
+
}
|
|
200
|
+
return Object.freeze({
|
|
201
|
+
usage: frozenUsage(terminal.usage),
|
|
202
|
+
metadata: freezeCapture(metadata),
|
|
203
|
+
message: freezeCapture({ ...terminal, content: terminal.content.map(publicBlock) }),
|
|
204
|
+
...(capture.rewrittenFrom === undefined ? {} : { rewrittenFrom: capture.rewrittenFrom }),
|
|
205
|
+
});
|
|
206
|
+
}
|
|
193
207
|
/** Never parses or traverses a block on a delta, including a no-growth delta. */
|
|
194
208
|
export function captureAssistantEvent(owner, event, hint = {}) {
|
|
195
209
|
const state = activeState(owner);
|
|
196
|
-
|
|
210
|
+
// A relay of a source that captured nothing, or captured a drifted index, gets no record: lack, never wrong.
|
|
211
|
+
if (!state || captures.has(event) || hint.carried === null || hint.carried?.contentIndex !== undefined)
|
|
197
212
|
return;
|
|
198
213
|
const contentIndex = "contentIndex" in event ? (hint.contentIndex ?? event.contentIndex) : undefined;
|
|
199
214
|
if (contentIndex !== undefined && state.failedBlocks.has(contentIndex))
|
|
200
215
|
return;
|
|
201
216
|
try {
|
|
202
|
-
|
|
217
|
+
const capture = buildCapture(state, event, hint);
|
|
218
|
+
if (capture)
|
|
219
|
+
captures.set(event, capture);
|
|
203
220
|
}
|
|
204
221
|
catch (error) {
|
|
205
222
|
dropCapture(owner, error, state, contentIndex);
|
|
@@ -213,11 +230,21 @@ function buildCapture(state, event, hint) {
|
|
|
213
230
|
usage,
|
|
214
231
|
metadata: changedMetadata(state, message),
|
|
215
232
|
message: freezeCapture({ ...message, content: message.content.map(publicBlock) }),
|
|
233
|
+
...(hint.rewrittenFrom === undefined ? {} : { rewrittenFrom: hint.rewrittenFrom }),
|
|
216
234
|
});
|
|
217
235
|
}
|
|
218
236
|
const index = hint.contentIndex ?? event.contentIndex;
|
|
219
237
|
const own = index === event.contentIndex ? {} : { contentIndex: index };
|
|
238
|
+
const carried = hint.carried;
|
|
220
239
|
if ("delta" in event) {
|
|
240
|
+
if (carried) {
|
|
241
|
+
const { parsedThrough } = carried;
|
|
242
|
+
return Object.freeze({
|
|
243
|
+
usage,
|
|
244
|
+
offset: carried.offset,
|
|
245
|
+
...(parsedThrough === undefined ? {} : { parsedThrough }),
|
|
246
|
+
});
|
|
247
|
+
}
|
|
221
248
|
const position = state.positions.get(index) ?? { offset: 0, parsedThrough: 0 };
|
|
222
249
|
const offset = hint.offset ?? position.offset;
|
|
223
250
|
position.offset = offset + event.delta.length;
|
|
@@ -233,10 +260,18 @@ function buildCapture(state, event, hint) {
|
|
|
233
260
|
});
|
|
234
261
|
}
|
|
235
262
|
const metadata = changedMetadata(state, message);
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
return Object.freeze({ usage, metadata
|
|
263
|
+
if (carried) {
|
|
264
|
+
const { usage: _usage, metadata: _metadata, message: _message, offset: _offset, ...facts } = carried;
|
|
265
|
+
return Object.freeze({ ...facts, usage, metadata });
|
|
239
266
|
}
|
|
267
|
+
const starts = event.type === "text_start" || event.type === "thinking_start" || event.type === "toolcall_start";
|
|
268
|
+
const source = event.type === "toolcall_end" ? event.toolCall : message.content[index];
|
|
269
|
+
// A start announced before its block is appended has no seed to freeze yet.
|
|
270
|
+
if (starts && source === undefined)
|
|
271
|
+
return undefined;
|
|
272
|
+
const block = freezeCapture(publicBlock(source));
|
|
273
|
+
if (!starts)
|
|
274
|
+
return Object.freeze({ usage, metadata, block, ...own });
|
|
240
275
|
const rawArgumentPrefix = hint.rawArgumentPrefix ?? "";
|
|
241
276
|
const coveredCodeUnits = block.type === "text"
|
|
242
277
|
? block.text.length
|
|
@@ -257,13 +292,15 @@ function buildCapture(state, event, hint) {
|
|
|
257
292
|
function usageCopy(state, usage) {
|
|
258
293
|
if (state.usage !== undefined && sameValue(usage, state.usage))
|
|
259
294
|
return state.usage;
|
|
260
|
-
|
|
295
|
+
state.usage = frozenUsage(usage);
|
|
296
|
+
return state.usage;
|
|
297
|
+
}
|
|
298
|
+
function frozenUsage(usage) {
|
|
299
|
+
return Object.freeze({
|
|
261
300
|
...usage,
|
|
262
301
|
cost: Object.freeze({ ...usage.cost }),
|
|
263
302
|
...(usage.contextUsage ? { contextUsage: Object.freeze({ ...usage.contextUsage }) } : {}),
|
|
264
303
|
});
|
|
265
|
-
state.usage = copy;
|
|
266
|
-
return copy;
|
|
267
304
|
}
|
|
268
305
|
/** Scalar message fields changed since the last non-delta capture; the baseline moves only once its copy exists. */
|
|
269
306
|
function changedMetadata(state, message) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-yeongyu/senpi-ai",
|
|
3
|
-
"version": "2026.10.26-
|
|
3
|
+
"version": "2026.10.26-2",
|
|
4
4
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
"dependencies": {
|
|
89
89
|
"@anthropic-ai/sdk": "0.127.0",
|
|
90
90
|
"@aws-sdk/client-bedrock-runtime": "3.1136.0",
|
|
91
|
-
"@earendil-works/pi-telemetry": "npm:@code-yeongyu/senpi-telemetry@2026.10.26-
|
|
91
|
+
"@earendil-works/pi-telemetry": "npm:@code-yeongyu/senpi-telemetry@2026.10.26-2",
|
|
92
92
|
"@google/genai": "2.23.0",
|
|
93
93
|
"@smithy/node-http-handler": "4.12.1",
|
|
94
94
|
"google-auth-library": "10.6.2",
|