@xsai/stream-text 0.4.0-beta.2 → 0.4.0-beta.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/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { WithUnknown } from '@xsai/shared';
1
2
  import { CompletionToolCall, CompletionToolResult, FinishReason, Usage, ChatOptions, CompletionStep, Message } from '@xsai/shared-chat';
2
3
 
3
4
  type StreamTextEvent = (CompletionToolCall & {
@@ -51,8 +52,9 @@ interface StreamTextResult {
51
52
  messages: Promise<Message[]>;
52
53
  steps: Promise<CompletionStep[]>;
53
54
  textStream: ReadableStream<string>;
55
+ totalUsage: Promise<undefined | Usage>;
54
56
  usage: Promise<undefined | Usage>;
55
57
  }
56
- declare const streamText: (options: StreamTextOptions) => Promise<StreamTextResult>;
58
+ declare const streamText: (options: WithUnknown<StreamTextOptions>) => StreamTextResult;
57
59
 
58
60
  export { type StreamTextEvent, type StreamTextOptions, type StreamTextResult, streamText };
package/dist/index.js CHANGED
@@ -1,15 +1,6 @@
1
+ import { trampoline, objCamelToSnake } from '@xsai/shared';
1
2
  import { chat, executeTool, determineStepType } from '@xsai/shared-chat';
2
3
 
3
- const strCamelToSnake = (str) => str.replace(/[A-Z]/g, (s) => `_${s.toLowerCase()}`);
4
- const objCamelToSnake = (obj) => Object.fromEntries(Object.entries(obj).map(([k, v]) => [strCamelToSnake(k), v]));
5
-
6
- const trampoline = async (fn) => {
7
- let result = await fn();
8
- while (result instanceof Function)
9
- result = await result();
10
- return result;
11
- };
12
-
13
4
  class DelayedPromise {
14
5
  get promise() {
15
6
  if (this._promise == null) {
@@ -82,14 +73,16 @@ const transformChunk = () => {
82
73
  });
83
74
  };
84
75
 
85
- const streamText = async (options) => {
76
+ const streamText = (options) => {
86
77
  const steps = [];
87
78
  const messages = structuredClone(options.messages);
88
79
  const maxSteps = options.maxSteps ?? 1;
89
80
  let usage;
81
+ let totalUsage;
90
82
  const resultSteps = new DelayedPromise();
91
83
  const resultMessages = new DelayedPromise();
92
84
  const resultUsage = new DelayedPromise();
85
+ const resultTotalUsage = new DelayedPromise();
93
86
  let eventCtrl;
94
87
  let textCtrl;
95
88
  const eventStream = new ReadableStream({ start: (controller) => eventCtrl = controller });
@@ -102,16 +95,21 @@ const streamText = async (options) => {
102
95
  steps.push(step);
103
96
  void options.onStepFinish?.(step);
104
97
  };
105
- const startStream = async () => chat({
106
- ...options,
107
- maxSteps: void 0,
108
- messages,
109
- stream: true,
110
- streamOptions: options.streamOptions != null ? objCamelToSnake(options.streamOptions) : void 0
111
- }).then((res) => res.body);
112
- const handleStream = async (stream2) => {
98
+ const doStream = async () => {
99
+ const { body: stream } = await chat({
100
+ ...options,
101
+ maxSteps: void 0,
102
+ messages,
103
+ stream: true,
104
+ streamOptions: options.streamOptions != null ? objCamelToSnake(options.streamOptions) : void 0
105
+ });
113
106
  const pushUsage = (u) => {
114
107
  usage = u;
108
+ totalUsage = totalUsage ? {
109
+ completion_tokens: totalUsage.completion_tokens + u.completion_tokens,
110
+ prompt_tokens: totalUsage.prompt_tokens + u.prompt_tokens,
111
+ total_tokens: totalUsage.total_tokens + u.total_tokens
112
+ } : { ...u };
115
113
  };
116
114
  let text = "";
117
115
  const pushText = (content) => {
@@ -122,7 +120,7 @@ const streamText = async (options) => {
122
120
  const toolCalls = [];
123
121
  const toolResults = [];
124
122
  let finishReason = "other";
125
- await stream2.pipeThrough(transformChunk()).pipeTo(new WritableStream({
123
+ await stream.pipeThrough(transformChunk()).pipeTo(new WritableStream({
126
124
  abort: (reason) => {
127
125
  eventCtrl?.error(reason);
128
126
  textCtrl?.error(reason);
@@ -166,6 +164,8 @@ const streamText = async (options) => {
166
164
  messages.push({ content: text, role: "assistant", tool_calls });
167
165
  if (tool_calls.length !== 0) {
168
166
  for (const toolCall of tool_calls) {
167
+ if (toolCall == null)
168
+ continue;
169
169
  const { completionToolCall, completionToolResult, message } = await executeTool({
170
170
  abortSignal: options.abortSignal,
171
171
  messages,
@@ -194,12 +194,11 @@ const streamText = async (options) => {
194
194
  usage
195
195
  });
196
196
  if (toolCalls.length !== 0 && steps.length < maxSteps)
197
- return async () => handleStream(await startStream());
197
+ return async () => doStream();
198
198
  };
199
- const stream = await startStream();
200
199
  void (async () => {
201
200
  try {
202
- await trampoline(async () => handleStream(stream));
201
+ await trampoline(async () => doStream());
203
202
  eventCtrl?.close();
204
203
  textCtrl?.close();
205
204
  } catch (err) {
@@ -208,10 +207,12 @@ const streamText = async (options) => {
208
207
  resultSteps.reject(err);
209
208
  resultMessages.reject(err);
210
209
  resultUsage.reject(err);
210
+ resultTotalUsage.reject(err);
211
211
  } finally {
212
212
  resultSteps.resolve(steps);
213
213
  resultMessages.resolve(messages);
214
214
  resultUsage.resolve(usage);
215
+ resultTotalUsage.resolve(totalUsage);
215
216
  void options.onFinish?.(steps.at(-1));
216
217
  }
217
218
  })();
@@ -220,6 +221,7 @@ const streamText = async (options) => {
220
221
  messages: resultMessages.promise,
221
222
  steps: resultSteps.promise,
222
223
  textStream,
224
+ totalUsage: resultTotalUsage.promise,
223
225
  usage: resultUsage.promise
224
226
  };
225
227
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xsai/stream-text",
3
3
  "type": "module",
4
- "version": "0.4.0-beta.2",
4
+ "version": "0.4.0-beta.4",
5
5
  "description": "extra-small AI SDK.",
6
6
  "author": "Moeru AI",
7
7
  "license": "MIT",
@@ -29,12 +29,12 @@
29
29
  "dist"
30
30
  ],
31
31
  "dependencies": {
32
- "@xsai/shared-chat": "~0.4.0-beta.2"
32
+ "@xsai/shared": "~0.4.0-beta.4",
33
+ "@xsai/shared-chat": "~0.4.0-beta.4"
33
34
  },
34
35
  "devDependencies": {
35
36
  "valibot": "^1.0.0",
36
- "@xsai/shared": "~0.4.0-beta.2",
37
- "@xsai/tool": "~0.4.0-beta.2"
37
+ "@xsai/tool": "~0.4.0-beta.4"
38
38
  },
39
39
  "scripts": {
40
40
  "build": "pkgroll",