@code-yeongyu/senpi-ai 2026.7.29 → 2026.7.30
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/api/openai-completions.d.ts.map +1 -1
- package/dist/api/openai-completions.js +121 -38
- package/dist/api/openai-completions.js.map +1 -1
- package/dist/providers/data/.manifest.json +1 -1
- package/dist/providers/data/openrouter.json +1 -1
- package/dist/tool-call-middleware/recovery-diagnostics.d.ts +2 -1
- package/dist/tool-call-middleware/recovery-diagnostics.d.ts.map +1 -1
- package/dist/tool-call-middleware/recovery-diagnostics.js +2 -2
- package/dist/tool-call-middleware/recovery-diagnostics.js.map +1 -1
- package/dist/tool-call-middleware/recovery-native-projection.d.ts +3 -2
- package/dist/tool-call-middleware/recovery-native-projection.d.ts.map +1 -1
- package/dist/tool-call-middleware/recovery-native-projection.js +3 -2
- package/dist/tool-call-middleware/recovery-native-projection.js.map +1 -1
- package/dist/tool-call-middleware/recovery-stream-failure.d.ts +6 -1
- package/dist/tool-call-middleware/recovery-stream-failure.d.ts.map +1 -1
- package/dist/tool-call-middleware/recovery-stream-failure.js +3 -2
- package/dist/tool-call-middleware/recovery-stream-failure.js.map +1 -1
- package/dist/tool-call-middleware/recovery-stream-wrapper.d.ts +6 -1
- package/dist/tool-call-middleware/recovery-stream-wrapper.d.ts.map +1 -1
- package/dist/tool-call-middleware/recovery-stream-wrapper.js +11 -5
- package/dist/tool-call-middleware/recovery-stream-wrapper.js.map +1 -1
- package/dist/tool-call-middleware/recovery-text-projection.d.ts +6 -1
- package/dist/tool-call-middleware/recovery-text-projection.d.ts.map +1 -1
- package/dist/tool-call-middleware/recovery-text-projection.js +6 -4
- package/dist/tool-call-middleware/recovery-text-projection.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-completions.d.ts","sourceRoot":"","sources":["../../src/api/openai-completions.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,KAAK,EAOX,0BAA0B,EAI1B,MAAM,sCAAsC,CAAC;AAG9C,OAAO,KAAK,EAIX,OAAO,EAGP,KAAK,EAIL,mBAAmB,EAEnB,cAAc,EACd,aAAa,EAMb,MAAM,aAAa,CAAC;AAMrB,OAAO,EAEN,KAAK,+BAA+B,EACpC,MAAM,8BAA8B,CAAC;AA4BtC,OAAO,EACN,0BAA0B,IAAI,SAAS,EACvC,KAAK,+BAA+B,GACpC,MAAM,8BAA8B,CAAC;AA4MtC,MAAM,WAAW,wBAAyB,SAAQ,aAAa;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,8BAA8B,CAAC;IACpE,eAAe,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;CAC1E;AAED,MAAM,WAAW,iCAAiC;IACjD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,0BAA0B,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzD;AAwCD,eAAO,MAAM,MAAM,EAAE,cAAc,CAAC,oBAAoB,EAAE,wBAAwB,
|
|
1
|
+
{"version":3,"file":"openai-completions.d.ts","sourceRoot":"","sources":["../../src/api/openai-completions.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,KAAK,EAOX,0BAA0B,EAI1B,MAAM,sCAAsC,CAAC;AAG9C,OAAO,KAAK,EAIX,OAAO,EAGP,KAAK,EAIL,mBAAmB,EAEnB,cAAc,EACd,aAAa,EAMb,MAAM,aAAa,CAAC;AAMrB,OAAO,EAEN,KAAK,+BAA+B,EACpC,MAAM,8BAA8B,CAAC;AA4BtC,OAAO,EACN,0BAA0B,IAAI,SAAS,EACvC,KAAK,+BAA+B,GACpC,MAAM,8BAA8B,CAAC;AA4MtC,MAAM,WAAW,wBAAyB,SAAQ,aAAa;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,8BAA8B,CAAC;IACpE,eAAe,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;CAC1E;AAED,MAAM,WAAW,iCAAiC;IACjD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,0BAA0B,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzD;AAwCD,eAAO,MAAM,MAAM,EAAE,cAAc,CAAC,oBAAoB,EAAE,wBAAwB,CA0fjF,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,cAAc,CAAC,oBAAoB,EAAE,mBAAmB,CAyBlF,CAAC;AA8XF,wBAAgB,eAAe,CAC9B,KAAK,EAAE,KAAK,CAAC,oBAAoB,CAAC,EAClC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,+BAA+B,EACvC,OAAO,GAAE,iCAAsC,GAC7C,0BAA0B,EAAE,CAgS9B"}
|
|
@@ -240,7 +240,12 @@ export const stream = (model, context, options) => {
|
|
|
240
240
|
stream.push({ type: "start", partial: output });
|
|
241
241
|
let textBlock = null;
|
|
242
242
|
let thinkingBlock = null;
|
|
243
|
+
let activeBlock = null;
|
|
244
|
+
let deferMixedEvents = false;
|
|
243
245
|
let hasFinishReason = false;
|
|
246
|
+
const deferredTextDeltas = [];
|
|
247
|
+
const deferredThinkingDeltas = [];
|
|
248
|
+
const deferredToolCallDeltas = new Map();
|
|
244
249
|
const toolCallBlocksByIndex = new Map();
|
|
245
250
|
const toolCallBlocksById = new Map();
|
|
246
251
|
const pendingReasoningDetailsByToolCallId = new Map();
|
|
@@ -310,23 +315,47 @@ export const stream = (model, context, options) => {
|
|
|
310
315
|
});
|
|
311
316
|
}
|
|
312
317
|
};
|
|
318
|
+
const finishActiveBlock = () => {
|
|
319
|
+
if (!activeBlock)
|
|
320
|
+
return;
|
|
321
|
+
finishBlock(activeBlock);
|
|
322
|
+
activeBlock = null;
|
|
323
|
+
};
|
|
313
324
|
const ensureTextBlock = () => {
|
|
314
325
|
if (!textBlock) {
|
|
326
|
+
if (!deferMixedEvents) {
|
|
327
|
+
finishActiveBlock();
|
|
328
|
+
thinkingBlock = null;
|
|
329
|
+
}
|
|
315
330
|
textBlock = { type: "text", text: "" };
|
|
316
331
|
blocks.push(textBlock);
|
|
317
|
-
|
|
332
|
+
if (!deferMixedEvents) {
|
|
333
|
+
activeBlock = textBlock;
|
|
334
|
+
stream.push({ type: "text_start", contentIndex: getContentIndex(textBlock), partial: output });
|
|
335
|
+
}
|
|
318
336
|
}
|
|
319
337
|
return textBlock;
|
|
320
338
|
};
|
|
321
339
|
const ensureThinkingBlock = (thinkingSignature) => {
|
|
322
340
|
if (!thinkingBlock) {
|
|
341
|
+
if (!deferMixedEvents) {
|
|
342
|
+
finishActiveBlock();
|
|
343
|
+
textBlock = null;
|
|
344
|
+
}
|
|
323
345
|
thinkingBlock = {
|
|
324
346
|
type: "thinking",
|
|
325
347
|
thinking: "",
|
|
326
348
|
thinkingSignature,
|
|
327
349
|
};
|
|
328
350
|
blocks.push(thinkingBlock);
|
|
329
|
-
|
|
351
|
+
if (!deferMixedEvents) {
|
|
352
|
+
activeBlock = thinkingBlock;
|
|
353
|
+
stream.push({
|
|
354
|
+
type: "thinking_start",
|
|
355
|
+
contentIndex: getContentIndex(thinkingBlock),
|
|
356
|
+
partial: output,
|
|
357
|
+
});
|
|
358
|
+
}
|
|
330
359
|
}
|
|
331
360
|
return thinkingBlock;
|
|
332
361
|
};
|
|
@@ -348,6 +377,11 @@ export const stream = (model, context, options) => {
|
|
|
348
377
|
block = toolCallBlocksById.get(toolCall.id);
|
|
349
378
|
}
|
|
350
379
|
if (!block) {
|
|
380
|
+
if (!deferMixedEvents) {
|
|
381
|
+
finishActiveBlock();
|
|
382
|
+
textBlock = null;
|
|
383
|
+
thinkingBlock = null;
|
|
384
|
+
}
|
|
351
385
|
// Note: the "input" fallback here should/must not be taken. in case the LLM makes up
|
|
352
386
|
// a tool we don't knwo about, we at least have a place to stash our stuff.
|
|
353
387
|
const customInputProperty = toolCall.custom
|
|
@@ -372,11 +406,14 @@ export const stream = (model, context, options) => {
|
|
|
372
406
|
toolCallBlocksById.set(toolCall.id, block);
|
|
373
407
|
}
|
|
374
408
|
blocks.push(block);
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
409
|
+
if (!deferMixedEvents) {
|
|
410
|
+
activeBlock = block;
|
|
411
|
+
stream.push({
|
|
412
|
+
type: "toolcall_start",
|
|
413
|
+
contentIndex: getContentIndex(block),
|
|
414
|
+
partial: output,
|
|
415
|
+
});
|
|
416
|
+
}
|
|
380
417
|
}
|
|
381
418
|
if (streamIndex !== undefined && block.streamIndex === undefined) {
|
|
382
419
|
block.streamIndex = streamIndex;
|
|
@@ -400,6 +437,30 @@ export const stream = (model, context, options) => {
|
|
|
400
437
|
applyPendingReasoningDetail(block);
|
|
401
438
|
return block;
|
|
402
439
|
};
|
|
440
|
+
const flushDeferredBlocks = () => {
|
|
441
|
+
for (const block of blocks) {
|
|
442
|
+
const contentIndex = getContentIndex(block);
|
|
443
|
+
if (block.type === "text") {
|
|
444
|
+
stream.push({ type: "text_start", contentIndex, partial: output });
|
|
445
|
+
for (const delta of deferredTextDeltas) {
|
|
446
|
+
stream.push({ type: "text_delta", contentIndex, delta, partial: output });
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
else if (block.type === "thinking") {
|
|
450
|
+
stream.push({ type: "thinking_start", contentIndex, partial: output });
|
|
451
|
+
for (const delta of deferredThinkingDeltas) {
|
|
452
|
+
stream.push({ type: "thinking_delta", contentIndex, delta, partial: output });
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
else {
|
|
456
|
+
stream.push({ type: "toolcall_start", contentIndex, partial: output });
|
|
457
|
+
for (const delta of deferredToolCallDeltas.get(block) ?? []) {
|
|
458
|
+
stream.push({ type: "toolcall_delta", contentIndex, delta, partial: output });
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
finishBlock(block);
|
|
462
|
+
}
|
|
463
|
+
};
|
|
403
464
|
for await (const chunk of openaiStream) {
|
|
404
465
|
if (!chunk || typeof chunk !== "object")
|
|
405
466
|
continue;
|
|
@@ -430,22 +491,9 @@ export const stream = (model, context, options) => {
|
|
|
430
491
|
hasFinishReason = true;
|
|
431
492
|
}
|
|
432
493
|
if (choice.delta) {
|
|
433
|
-
|
|
434
|
-
choice.delta.content
|
|
435
|
-
|
|
436
|
-
const block = ensureTextBlock();
|
|
437
|
-
block.text += choice.delta.content;
|
|
438
|
-
stream.push({
|
|
439
|
-
type: "text_delta",
|
|
440
|
-
contentIndex: getContentIndex(block),
|
|
441
|
-
delta: choice.delta.content,
|
|
442
|
-
partial: output,
|
|
443
|
-
});
|
|
444
|
-
}
|
|
445
|
-
// Some endpoints return reasoning in reasoning_content (llama.cpp),
|
|
446
|
-
// or reasoning (other openai compatible endpoints)
|
|
447
|
-
// Use the first non-empty reasoning field to avoid duplication
|
|
448
|
-
// (e.g., chutes.ai returns both reasoning_content and reasoning with same content)
|
|
494
|
+
const contentDelta = typeof choice.delta.content === "string" && choice.delta.content.length > 0
|
|
495
|
+
? choice.delta.content
|
|
496
|
+
: null;
|
|
449
497
|
const reasoningFields = ["reasoning_content", "reasoning", "reasoning_text"];
|
|
450
498
|
const deltaFields = choice.delta;
|
|
451
499
|
let foundReasoningField = null;
|
|
@@ -456,6 +504,28 @@ export const stream = (model, context, options) => {
|
|
|
456
504
|
break;
|
|
457
505
|
}
|
|
458
506
|
}
|
|
507
|
+
if (blocks.length === 0 && contentDelta && foundReasoningField) {
|
|
508
|
+
deferMixedEvents = true;
|
|
509
|
+
}
|
|
510
|
+
if (contentDelta) {
|
|
511
|
+
const block = ensureTextBlock();
|
|
512
|
+
block.text += contentDelta;
|
|
513
|
+
if (deferMixedEvents) {
|
|
514
|
+
deferredTextDeltas.push(contentDelta);
|
|
515
|
+
}
|
|
516
|
+
else {
|
|
517
|
+
stream.push({
|
|
518
|
+
type: "text_delta",
|
|
519
|
+
contentIndex: getContentIndex(block),
|
|
520
|
+
delta: contentDelta,
|
|
521
|
+
partial: output,
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
// Some endpoints return reasoning in reasoning_content (llama.cpp),
|
|
526
|
+
// or reasoning (other openai compatible endpoints)
|
|
527
|
+
// Use the first non-empty reasoning field to avoid duplication
|
|
528
|
+
// (e.g., chutes.ai returns both reasoning_content and reasoning with same content)
|
|
459
529
|
if (foundReasoningField) {
|
|
460
530
|
const delta = deltaFields[foundReasoningField];
|
|
461
531
|
if (typeof delta === "string" && delta.length > 0) {
|
|
@@ -464,12 +534,17 @@ export const stream = (model, context, options) => {
|
|
|
464
534
|
: foundReasoningField;
|
|
465
535
|
const block = ensureThinkingBlock(thinkingSignature);
|
|
466
536
|
block.thinking += delta;
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
537
|
+
if (deferMixedEvents) {
|
|
538
|
+
deferredThinkingDeltas.push(delta);
|
|
539
|
+
}
|
|
540
|
+
else {
|
|
541
|
+
stream.push({
|
|
542
|
+
type: "thinking_delta",
|
|
543
|
+
contentIndex: getContentIndex(block),
|
|
544
|
+
delta,
|
|
545
|
+
partial: output,
|
|
546
|
+
});
|
|
547
|
+
}
|
|
473
548
|
}
|
|
474
549
|
}
|
|
475
550
|
if (choice?.delta?.tool_calls) {
|
|
@@ -493,12 +568,19 @@ export const stream = (model, context, options) => {
|
|
|
493
568
|
const nextInput = getCustomToolCallInput(block) + toolCall.custom.input;
|
|
494
569
|
delta = appendCustomToolCallInput(block, nextInput, false) ?? "";
|
|
495
570
|
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
571
|
+
if (deferMixedEvents) {
|
|
572
|
+
const deltas = deferredToolCallDeltas.get(block) ?? [];
|
|
573
|
+
deltas.push(delta);
|
|
574
|
+
deferredToolCallDeltas.set(block, deltas);
|
|
575
|
+
}
|
|
576
|
+
else {
|
|
577
|
+
stream.push({
|
|
578
|
+
type: "toolcall_delta",
|
|
579
|
+
contentIndex: getContentIndex(block),
|
|
580
|
+
delta,
|
|
581
|
+
partial: output,
|
|
582
|
+
});
|
|
583
|
+
}
|
|
502
584
|
}
|
|
503
585
|
}
|
|
504
586
|
const reasoningDetails = choice.delta.reasoning_details;
|
|
@@ -518,9 +600,10 @@ export const stream = (model, context, options) => {
|
|
|
518
600
|
}
|
|
519
601
|
}
|
|
520
602
|
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
603
|
+
if (deferMixedEvents)
|
|
604
|
+
flushDeferredBlocks();
|
|
605
|
+
else
|
|
606
|
+
finishActiveBlock();
|
|
524
607
|
if (options?.signal?.aborted) {
|
|
525
608
|
throw new Error("Request was aborted");
|
|
526
609
|
}
|