thaipass 0.1.0 → 0.1.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.js +31 -10
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -646,6 +646,11 @@ const fileFrameSchema = fileEventSchema.extend({
|
|
|
646
646
|
data: fileEventSchema.optional(),
|
|
647
647
|
type: z.literal("file")
|
|
648
648
|
});
|
|
649
|
+
const toolErrorSchema = (type) => z.object({
|
|
650
|
+
errorText: optionalText,
|
|
651
|
+
toolName: optionalText,
|
|
652
|
+
type: z.literal(type)
|
|
653
|
+
});
|
|
649
654
|
const upstreamEventSchema = z.discriminatedUnion("type", [
|
|
650
655
|
z.object({
|
|
651
656
|
delta: z.string(),
|
|
@@ -660,12 +665,23 @@ const upstreamEventSchema = z.discriminatedUnion("type", [
|
|
|
660
665
|
finishReason: optionalText,
|
|
661
666
|
type: z.literal("finish")
|
|
662
667
|
}),
|
|
668
|
+
toolErrorSchema("tool-input-error"),
|
|
669
|
+
toolErrorSchema("tool-output-error"),
|
|
663
670
|
z.object({
|
|
664
671
|
error: optionalText,
|
|
665
672
|
errorText: optionalText,
|
|
666
673
|
type: z.literal("error")
|
|
667
674
|
})
|
|
668
675
|
]);
|
|
676
|
+
const toFileEvent = (frame) => {
|
|
677
|
+
const { data } = frame;
|
|
678
|
+
return {
|
|
679
|
+
filename: frame.filename ?? data?.filename,
|
|
680
|
+
mediaType: frame.mediaType ?? data?.mediaType,
|
|
681
|
+
snapshotUrl: frame.snapshotUrl ?? data?.snapshotUrl,
|
|
682
|
+
url: frame.url ?? data?.url
|
|
683
|
+
};
|
|
684
|
+
};
|
|
669
685
|
const skippedTypeSchema = z.object({ type: z.string() });
|
|
670
686
|
const parseAipassSSE = async function* parseAipassSSE(body, skips) {
|
|
671
687
|
const chunks = parseJsonEventStream({
|
|
@@ -695,25 +711,25 @@ const parseAipassSSE = async function* parseAipassSSE(body, skips) {
|
|
|
695
711
|
text: event.delta
|
|
696
712
|
};
|
|
697
713
|
break;
|
|
698
|
-
case "file":
|
|
699
|
-
const { data } = event;
|
|
714
|
+
case "file":
|
|
700
715
|
yield {
|
|
701
|
-
file:
|
|
702
|
-
filename: event.filename ?? data?.filename,
|
|
703
|
-
mediaType: event.mediaType ?? data?.mediaType,
|
|
704
|
-
snapshotUrl: event.snapshotUrl ?? data?.snapshotUrl,
|
|
705
|
-
url: event.url ?? data?.url
|
|
706
|
-
},
|
|
716
|
+
file: toFileEvent(event),
|
|
707
717
|
kind: "file"
|
|
708
718
|
};
|
|
709
719
|
break;
|
|
710
|
-
}
|
|
711
720
|
case "finish":
|
|
712
721
|
yield {
|
|
713
722
|
kind: "finish",
|
|
714
723
|
reason: event.finishReason ?? "stop"
|
|
715
724
|
};
|
|
716
725
|
break;
|
|
726
|
+
case "tool-input-error":
|
|
727
|
+
case "tool-output-error":
|
|
728
|
+
yield {
|
|
729
|
+
kind: "error",
|
|
730
|
+
message: `upstream failed on ${event.toolName ?? "a tool"}: ${event.errorText ?? "no detail"}`
|
|
731
|
+
};
|
|
732
|
+
break;
|
|
717
733
|
default: yield {
|
|
718
734
|
kind: "error",
|
|
719
735
|
message: event.errorText ?? event.error ?? "upstream error"
|
|
@@ -928,7 +944,12 @@ const prepareTurn = async (conversation, model, thinking, catalog) => {
|
|
|
928
944
|
thinkingLevel
|
|
929
945
|
};
|
|
930
946
|
};
|
|
931
|
-
|
|
947
|
+
/** Upstream promised a call and made none, so what it left is an apology. */
|
|
948
|
+
const isAbandonedToolCall = (tally) => tally.finishReason === "tool-calls" && tally.calls === 0;
|
|
949
|
+
const finishReasonOf = (tally) => {
|
|
950
|
+
if (isAbandonedToolCall(tally)) return "error";
|
|
951
|
+
return tally.calls > 0 && tally.finishReason === "stop" ? "tool-calls" : tally.finishReason;
|
|
952
|
+
};
|
|
932
953
|
const replyTokens = (tally) => charTokens(tally.reply);
|
|
933
954
|
/**
|
|
934
955
|
* Text goes through the tool-call splitter, so a fenced call never reaches the
|