@xsai/text 1.0.0-beta.5 → 1.0.0-beta.7

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,5 +1,5 @@
1
- import { S as StepEndDoneEvent, T as ToolCallPart, a as ToolResultPart, U as Usage, b as TextEvent, M as Message, L as LanguageModelOptions, c as LanguageModel, d as ToolExecuteOptions } from './language-model-Dne8NRLD.js';
2
- export { A as AssistantMessage, e as AssistantMessageContent, f as AudioPart, C as CombinedStandardSchema, g as Content, h as ContentEndEvent, i as ContentMap, j as ContentStartEvent, k as ContentType, D as DeveloperMessage, l as DeveloperMessageContent, E as ExecutableTool, F as FilePart, m as FinishReason, I as ImagePart, n as InferSchemaInput, o as InferSchemaOutput, J as JSONSchema7, p as JSONSchema7Definition, q as LanguageModelProviderOptions, r as MessageMap, s as MessageProviderMetadata, t as MessageType, P as PartProviderMetadata, u as ProviderPart, R as RawEvent, v as ReasoningDeltaEvent, w as ReasoningPart, x as ReasoningPartContent, y as RefusalDeltaEvent, z as RefusalPart, B as ResolvedSchema, G as StepEndEvent, H as StepEndFailEvent, K as StepStartEvent, N as StepStatus, O as SystemMessage, Q as SystemMessageContent, V as TextDeltaEvent, W as TextEventMap, X as TextEventType, Y as TextPart, Z as Tool, _ as ToolCallDeltaEvent, $ as ToolChoice, a0 as ToolOptions, a1 as ToolResultPartContent, a2 as UnresolvedSchema, a3 as UserMessage, a4 as UserMessageContent, a5 as resolveSchema, a6 as tool } from './language-model-Dne8NRLD.js';
1
+ import { S as StepEndDoneEvent, T as ToolCallPart, a as ToolResultPart, U as Usage, b as TextEvent, L as LanguageModelOptions, M as Message, c as LanguageModel, d as ToolExecuteOptions } from './language-model-CAPBb-ti.js';
2
+ export { A as AssistantMessage, e as AssistantMessageContent, f as AudioPart, C as CombinedStandardSchema, g as Content, h as ContentEndEvent, i as ContentMap, j as ContentStartEvent, k as ContentType, D as DeveloperMessage, l as DeveloperMessageContent, E as ExecutableTool, F as FilePart, m as FinishReason, I as ImagePart, n as InferSchemaInput, o as InferSchemaOutput, J as JSONSchema7, p as JSONSchema7Definition, q as LanguageModelProviderOptions, r as MessageMap, s as MessageProviderMetadata, t as MessageType, P as PartProviderMetadata, u as ProviderPart, R as RawEvent, v as ReasoningDeltaEvent, w as ReasoningPart, x as ReasoningPartContent, y as RefusalDeltaEvent, z as RefusalPart, B as ResolvedSchema, G as StepEndEvent, H as StepEndFailEvent, K as StepStartEvent, N as StepStatus, O as SystemMessage, Q as SystemMessageContent, V as TextDeltaEvent, W as TextEventMap, X as TextEventType, Y as TextPart, Z as Tool, _ as ToolCallDeltaEvent, $ as ToolChoice, a0 as ToolOptions, a1 as ToolResultPartContent, a2 as UnresolvedSchema, a3 as UserMessage, a4 as UserMessageContent, a5 as formatIssues, a6 as resolveSchema, a7 as tool } from './language-model-CAPBb-ti.js';
3
3
  import { Promisable } from '@xsai/shared';
4
4
  export { HttpError, XSAIError, XSAIErrorCause, XSAIErrorCauseMap, XSAIErrorCode, XSAIErrorOptions } from '@xsai/shared';
5
5
 
@@ -16,8 +16,9 @@ interface CollectResult extends StepResult {
16
16
  declare const collect: (stream: ReadableStream<TextEvent>) => Promise<CollectResult>;
17
17
 
18
18
  type PrepareStep = (options: PrepareStepOptions) => Promisable<PrepareStepResult | undefined>;
19
- interface PrepareStepOptions {
19
+ interface PrepareStepOptions extends Pick<LanguageModelOptions, 'instructions' | 'tools'> {
20
20
  input: readonly Message[];
21
+ model: LanguageModel;
21
22
  signal: AbortSignal;
22
23
  stepNumber: number;
23
24
  steps: readonly StepResult[];
@@ -40,8 +41,13 @@ declare const hasToolCall: (name?: string) => StopCondition;
40
41
  /** @deprecated use `maxSteps` instead. */
41
42
  declare const stepCountAtLeast: (count: number) => StopCondition;
42
43
 
44
+ interface ExecuteToolOptions extends Pick<LanguageModelOptions, 'signal' | 'tools'> {
45
+ postToolCall?: PostToolCall;
46
+ preToolCall?: PreToolCall;
47
+ }
43
48
  type PostToolCall = (toolResult: ToolResultPart, options: ToolExecuteOptions) => Promisable<ToolResultPart | void>;
44
49
  type PreToolCall = (toolCall: ToolCallPart, options: ToolExecuteOptions) => Promisable<ToolCallPart | ToolResultPart | void>;
50
+ declare const executeTool: (call: ToolCallPart, { postToolCall, preToolCall, signal, tools }: ExecuteToolOptions) => Promise<ToolResultPart>;
45
51
 
46
52
  interface StreamTextOptions extends LanguageModelOptions {
47
53
  postToolCall?: PostToolCall;
@@ -82,5 +88,5 @@ declare module '@xsai/shared' {
82
88
  }
83
89
  }
84
90
 
85
- export { LanguageModel, LanguageModelOptions, Message, StepEndDoneEvent, TextEvent, TextEventTarget, ToolCallPart, ToolExecuteOptions, ToolResultPart, Usage, and, collect, generateText, hasToolCall, maxSteps, not, or, stepCountAtLeast, streamText, toCustomEvent, withEventTarget };
86
- export type { CollectResult, PostToolCall, PreToolCall, PrepareStep, PrepareStepOptions, PrepareStepResult, StepResult, StopCondition, StopContext, StreamTextOptions };
91
+ export { LanguageModel, LanguageModelOptions, Message, StepEndDoneEvent, TextEvent, TextEventTarget, ToolCallPart, ToolExecuteOptions, ToolResultPart, Usage, and, collect, executeTool, generateText, hasToolCall, maxSteps, not, or, stepCountAtLeast, streamText, toCustomEvent, withEventTarget };
92
+ export type { CollectResult, ExecuteToolOptions, PostToolCall, PreToolCall, PrepareStep, PrepareStepOptions, PrepareStepResult, StepResult, StopCondition, StopContext, StreamTextOptions };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { XSAIError } from '@xsai/shared';
2
2
  export { HttpError, XSAIError } from '@xsai/shared';
3
- import { r as resolveSchema } from './schema-Bny4Y6lV.js';
3
+ import { f as formatIssues, r as readStep, a as resolveSchema } from './read-step-DXGjtk1d.js';
4
4
 
5
5
  const getText = (message) => typeof message.content === "string" ? message.content : message.content.filter((part) => part.type === "text").map((part) => part.text).join("");
6
6
  const getToolCalls = (message) => typeof message.content === "string" ? [] : message.content.filter((part) => part.type === "tool-call");
@@ -80,7 +80,7 @@ const assertSameCallId = (source, next) => {
80
80
  if (source !== next)
81
81
  throw new Error(`Tool call hooks must preserve callId "${source}".`);
82
82
  };
83
- const catchToolError = async (call, signal, callback) => {
83
+ const attempt = async (call, signal, callback) => {
84
84
  try {
85
85
  return await callback();
86
86
  } catch (error) {
@@ -88,85 +88,50 @@ const catchToolError = async (call, signal, callback) => {
88
88
  return toolError(call, error instanceof Error ? error.message : String(error));
89
89
  }
90
90
  };
91
- const executeTool = async (call, { postToolCall, preToolCall, signal, tools }) => {
92
- const executeOptions = { callId: call.callId, signal };
93
- const preToolCallResult = await catchToolError(call, signal, async () => preToolCall?.(call, executeOptions));
94
- if (preToolCallResult != null) {
95
- assertSameCallId(call.callId, preToolCallResult.callId);
96
- if (preToolCallResult.type === "tool-result")
97
- return preToolCallResult;
98
- call = preToolCallResult;
91
+ const parseInput = (args) => {
92
+ try {
93
+ return JSON.parse(args.trim() || "{}");
94
+ } catch {
95
+ throw new Error("Failed to parse tool input.");
99
96
  }
100
- let shouldPostToolCall = false;
101
- const toolResult = await catchToolError(call, signal, async () => {
102
- const tool = tools?.find((candidate) => candidate.name === call.name);
103
- const executableTool = tool;
104
- if (executableTool == null || executableTool.execute == null) {
105
- const available = tools?.map((candidate) => candidate.name).join(", ");
106
- return toolError(call, tool == null ? `Model tried to call unavailable tool "${call.name}", ${available == null || available === "" ? "No tools are available" : `Available tools: ${available}`}.` : `Tool "${call.name}" is not executable.`);
107
- }
108
- let toolInput;
109
- try {
110
- toolInput = JSON.parse(call.arguments.trim() || "{}");
111
- } catch {
112
- return toolError(call, "Failed to parse tool input.");
113
- }
114
- let validatedInput = toolInput;
115
- if (executableTool.inputSchema.validate != null) {
116
- const validation = await executableTool.inputSchema.validate(toolInput);
117
- if (validation.issues)
118
- return toolError(call, `Tool input validation failed for "${call.name}".`);
119
- validatedInput = validation.value;
120
- }
121
- shouldPostToolCall = true;
122
- return {
123
- callId: call.callId,
124
- output: await executableTool.execute(validatedInput, executeOptions),
125
- type: "tool-result"
126
- };
127
- });
128
- if (!shouldPostToolCall || postToolCall == null)
129
- return toolResult;
130
- const postToolCallResult = await catchToolError(call, signal, async () => postToolCall(toolResult, executeOptions));
131
- if (postToolCallResult == null)
132
- return toolResult;
133
- assertSameCallId(toolResult.callId, postToolCallResult.callId);
134
- return postToolCallResult;
135
97
  };
136
- const executeTools = async ({ reason, toolCalls, ...options }) => reason === "length" ? toolCalls.map((call) => toolError(call, "The response reached the output token limit before the tool call was complete.")) : Promise.all(toolCalls.map(async (call) => executeTool(call, options)));
137
-
138
- const readStep = async function* (stream, signal) {
139
- const reader = stream.getReader();
140
- let cancellation;
141
- const abort = () => {
142
- cancellation = reader.cancel(signal.reason);
143
- void cancellation.catch(() => {
144
- });
145
- };
146
- let stepEnd;
147
- signal.addEventListener("abort", abort, { once: true });
148
- try {
149
- signal.throwIfAborted();
150
- while (true) {
151
- const { done, value: event } = await reader.read();
152
- signal.throwIfAborted();
153
- if (done)
154
- break;
155
- if (event.type === "step.end") {
156
- if (stepEnd != null)
157
- throw new XSAIError("protocol-error", "model stream produced more than one step.end event");
158
- stepEnd = event;
159
- }
160
- yield event;
161
- }
162
- if (stepEnd == null)
163
- throw new XSAIError("truncated-stream", "model stream ended without a step.end event");
164
- return stepEnd;
165
- } finally {
166
- signal.removeEventListener("abort", abort);
167
- await (cancellation ?? reader.cancel(signal.reason)).finally(() => reader.releaseLock());
98
+ const runTool = async (call, tools, options) => {
99
+ const tool = tools?.find((candidate) => candidate.name === call.name);
100
+ if (tool == null) {
101
+ const available = tools?.map((candidate) => candidate.name).join(", ");
102
+ throw new Error(`Model tried to call unavailable tool "${call.name}", ${available == null || available === "" ? "No tools are available" : `Available tools: ${available}`}.`);
103
+ }
104
+ if (tool.execute == null)
105
+ throw new Error(`Tool "${call.name}" is not executable.`);
106
+ let input = parseInput(call.arguments);
107
+ if (tool.inputSchema.validate != null) {
108
+ const validation = await tool.inputSchema.validate(input);
109
+ if (validation.issues)
110
+ throw new Error(`Tool input validation failed for "${call.name}": ${formatIssues(validation.issues)}`);
111
+ input = validation.value;
112
+ }
113
+ return { callId: call.callId, output: await tool.execute(input, options), type: "tool-result" };
114
+ };
115
+ const finishTool = async (call, result, { postToolCall, signal }) => {
116
+ const posted = await attempt(call, signal, async () => postToolCall?.(result, { callId: call.callId, signal }));
117
+ if (posted == null)
118
+ return result;
119
+ assertSameCallId(result.callId, posted.callId);
120
+ return posted;
121
+ };
122
+ const executeTool = async (call, { postToolCall, preToolCall, signal, tools }) => {
123
+ const options = { callId: call.callId, signal };
124
+ const prepared = await attempt(call, signal, async () => preToolCall?.(call, options));
125
+ if (prepared != null) {
126
+ assertSameCallId(call.callId, prepared.callId);
127
+ if (prepared.type === "tool-result")
128
+ return prepared;
129
+ call = prepared;
168
130
  }
131
+ const result = await attempt(call, signal, async () => runTool(call, tools, options));
132
+ return finishTool(call, result, { postToolCall, signal });
169
133
  };
134
+
170
135
  const streamText = (model, { postToolCall, prepareStep, preToolCall, stopWhen: stopWhenOption, ...options }) => {
171
136
  const stopWhen = stopWhenOption ?? maxSteps(10);
172
137
  const input = [...Array.isArray(options.input) ? options.input : [{ content: options.input, role: "user" }]];
@@ -176,7 +141,7 @@ const streamText = (model, { postToolCall, prepareStep, preToolCall, stopWhen: s
176
141
  const generate = async function* () {
177
142
  while (true) {
178
143
  signal.throwIfAborted();
179
- const { model: preparedModel = model, ...preparedOptions } = await prepareStep?.({ input, signal, stepNumber: steps.length, steps }) ?? {};
144
+ const { model: preparedModel = model, ...preparedOptions } = await prepareStep?.({ input, instructions: options.instructions, model, signal, stepNumber: steps.length, steps, tools: options.tools }) ?? {};
180
145
  signal.throwIfAborted();
181
146
  const modelOptions = {
182
147
  ...options,
@@ -196,13 +161,8 @@ const streamText = (model, { postToolCall, prepareStep, preToolCall, stopWhen: s
196
161
  signal.throwIfAborted();
197
162
  if (step.toolCalls.length === 0)
198
163
  continue;
199
- const results = await executeTools({
200
- ...modelOptions,
201
- postToolCall,
202
- preToolCall,
203
- reason: step.reason,
204
- toolCalls: step.toolCalls
205
- });
164
+ const toolOptions = { ...modelOptions, postToolCall, preToolCall };
165
+ const results = await Promise.all(step.toolCalls.map(async (call) => step.reason === "length" ? finishTool(call, toolError(call, "The response reached the output token limit before the tool call was complete."), toolOptions) : executeTool(call, toolOptions)));
206
166
  signal.throwIfAborted();
207
167
  step.toolResults.push(...results);
208
168
  input.push({ content: results, role: "user" });
@@ -253,26 +213,24 @@ const tool = ((options) => {
253
213
  name: options.name,
254
214
  outputSchema
255
215
  };
256
- if (options.execute == null) {
216
+ if (options.execute == null)
257
217
  return tool2;
258
- } else {
259
- return {
260
- ...tool2,
261
- execute: async (input, executeOptions) => {
262
- let result = await options.execute(input, executeOptions);
263
- if (outputSchema?.validate != null) {
264
- const validation = await outputSchema.validate(result);
265
- if (validation.issues)
266
- throw new Error(`Tool output validation failed for "${options.name}".`);
267
- result = validation.value;
268
- }
269
- if (outputSchema)
270
- return JSON.stringify(result);
271
- else
272
- return result;
218
+ return {
219
+ ...tool2,
220
+ execute: async (input, executeOptions) => {
221
+ let result = await options.execute(input, executeOptions);
222
+ if (outputSchema?.validate != null) {
223
+ const validation = await outputSchema.validate(result);
224
+ if (validation.issues)
225
+ throw new Error(`Tool output validation failed for "${options.name}": ${formatIssues(validation.issues)}`);
226
+ result = validation.value;
273
227
  }
274
- };
275
- }
228
+ if (outputSchema)
229
+ return JSON.stringify(result);
230
+ else
231
+ return result;
232
+ }
233
+ };
276
234
  });
277
235
 
278
- export { TextEventTarget, and, collect, generateText, hasToolCall, maxSteps, not, or, stepCountAtLeast, streamText, toCustomEvent, tool, withEventTarget };
236
+ export { TextEventTarget, and, collect, executeTool, generateText, hasToolCall, maxSteps, not, or, stepCountAtLeast, streamText, toCustomEvent, tool, withEventTarget };
@@ -1,5 +1,5 @@
1
- import { StepStatus, FinishReason, AssistantMessage, AssistantMessageContent, PartProviderMetadata, Usage, TextEvent, LanguageModelOptions } from './index.js';
2
- export { C as CombinedStandardSchema, n as InferSchemaInput, o as InferSchemaOutput, J as JSONSchema7, p as JSONSchema7Definition, B as ResolvedSchema, a2 as UnresolvedSchema, a5 as resolveSchema } from './language-model-Dne8NRLD.js';
1
+ import { StepStatus, FinishReason, AssistantMessage, AssistantMessageContent, PartProviderMetadata, Usage, TextEvent, StepEndEvent, LanguageModelOptions } from './index.js';
2
+ export { C as CombinedStandardSchema, n as InferSchemaInput, o as InferSchemaOutput, J as JSONSchema7, p as JSONSchema7Definition, B as ResolvedSchema, a2 as UnresolvedSchema, a5 as formatIssues, a6 as resolveSchema } from './language-model-CAPBb-ti.js';
3
3
  import { XSAIError, EventSourceMessage, SendRequestOptions, HttpOptions } from '@xsai/shared';
4
4
 
5
5
  interface EventBuilder {
@@ -17,6 +17,7 @@ interface EventBuilder {
17
17
  }
18
18
  interface FinishMeta {
19
19
  messageId?: string;
20
+ model?: string;
20
21
  usage?: Usage;
21
22
  }
22
23
  interface PartDeltaExtra {
@@ -51,8 +52,24 @@ declare class EventSourceDataStream extends TransformStream<EventSourceMessage,
51
52
  constructor();
52
53
  }
53
54
 
55
+ /**
56
+ * Reads a model stream until it ends or `signal` aborts. Unlike `for await` on the stream itself,
57
+ * an abort ends a pending read even if the model ignores its signal, and the model sees the reason.
58
+ * Not covered by semver.
59
+ *
60
+ * @internal
61
+ */
62
+ declare const readEvents: (stream: ReadableStream<TextEvent>, signal: AbortSignal) => AsyncGenerator<TextEvent, void>;
63
+ /**
64
+ * Reads one model step and checks that it has exactly one `step.end`.
65
+ * Not covered by semver.
66
+ *
67
+ * @internal
68
+ */
69
+ declare const readStep: (stream: ReadableStream<TextEvent>, signal: AbortSignal) => AsyncGenerator<TextEvent, StepEndEvent>;
70
+
54
71
  /** @internal */
55
72
  declare const wireRequest: (options: SendRequestOptions, httpOptions: HttpOptions, modelOptions: LanguageModelOptions, eventStream: TransformStream<string, TextEvent>) => Promise<ReadableStream<TextEvent>>;
56
73
 
57
- export { EventSourceDataStream, WireEventStream, eventBuilder, wireRequest };
74
+ export { EventSourceDataStream, WireEventStream, eventBuilder, readEvents, readStep, wireRequest };
58
75
  export type { EventBuilder, FinishMeta, PartDeltaExtra, PartEndExtra, PartKey, PartStartInit };
package/dist/internal.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { XSAIError, sendRequest, EventSourceParserStream } from '@xsai/shared';
2
- export { r as resolveSchema } from './schema-Bny4Y6lV.js';
2
+ export { f as formatIssues, b as readEvents, r as readStep, a as resolveSchema } from './read-step-DXGjtk1d.js';
3
3
 
4
4
  const emptyContent = (type, init) => {
5
5
  switch (type) {
@@ -28,6 +28,7 @@ const eventBuilder = (emit, fail) => {
28
28
  let terminalEmitted = false;
29
29
  let messageId;
30
30
  let terminal;
31
+ let model;
31
32
  let usage;
32
33
  const updateReasoning = (state, text) => {
33
34
  if (text === "")
@@ -139,6 +140,7 @@ const eventBuilder = (emit, fail) => {
139
140
  };
140
141
  const common = {
141
142
  message: message.id == null && messageId != null ? { ...message, id: messageId } : message,
143
+ model,
142
144
  type: "step.end",
143
145
  usage
144
146
  };
@@ -186,6 +188,8 @@ const eventBuilder = (emit, fail) => {
186
188
  meta: (meta) => {
187
189
  if (meta.messageId != null)
188
190
  messageId = meta.messageId;
191
+ if (meta.model != null)
192
+ model = meta.model;
189
193
  if (meta.usage != null)
190
194
  usage = meta.usage;
191
195
  },
@@ -82,6 +82,7 @@ interface AssistantMessage {
82
82
  type AssistantMessageContent = ProviderPart | ReasoningPart | RefusalPart | TextPart | ToolCallPart;
83
83
  interface DeveloperMessage {
84
84
  content: readonly DeveloperMessageContent[] | string;
85
+ providerMetadata?: MessageProviderMetadata;
85
86
  role: 'developer';
86
87
  }
87
88
  type DeveloperMessageContent = TextPart;
@@ -95,6 +96,7 @@ interface MessageMap {
95
96
  type MessageType = keyof MessageMap;
96
97
  interface SystemMessage {
97
98
  content: readonly SystemMessageContent[] | string;
99
+ providerMetadata?: MessageProviderMetadata;
98
100
  role: 'system';
99
101
  }
100
102
  type SystemMessageContent = TextPart;
@@ -141,6 +143,8 @@ interface RefusalDeltaEvent {
141
143
  interface StepEndDoneEvent {
142
144
  error?: never;
143
145
  message: AssistantMessage;
146
+ /** The model that the provider says answered, if it says. */
147
+ model?: string;
144
148
  reason?: FinishReason;
145
149
  status: Exclude<StepStatus, 'failed'>;
146
150
  type: 'step.end';
@@ -151,6 +155,8 @@ type StepEndEvent = StepEndDoneEvent | StepEndFailEvent;
151
155
  interface StepEndFailEvent {
152
156
  error: XSAIError;
153
157
  message: AssistantMessage;
158
+ /** The model that the provider says answered, if it says. */
159
+ model?: string;
154
160
  reason?: never;
155
161
  status: 'failed';
156
162
  type: 'step.end';
@@ -481,6 +487,7 @@ interface ResolvedSchema<Input = unknown, Output = Input> {
481
487
  validate?: StandardSchemaV1.Props<Input, Output>['validate'];
482
488
  }
483
489
  type UnresolvedSchema<Input = unknown, Output = Input> = CombinedStandardSchema<Input, Output> | JSONSchema7;
490
+ declare const formatIssues: (issues: readonly StandardSchemaV1.Issue[]) => string;
484
491
  declare const resolveSchema: <Input = unknown, Output = Input>(schema: UnresolvedSchema<Input, Output>) => ResolvedSchema<Input, Output>;
485
492
 
486
493
  interface ExecutableTool extends Tool {
@@ -532,5 +539,5 @@ type ToolChoice = 'auto' | 'none' | 'required' | {
532
539
  name: string;
533
540
  };
534
541
 
535
- export { resolveSchema as a5, tool as a6 };
542
+ export { formatIssues as a5, resolveSchema as a6, tool as a7 };
536
543
  export type { ToolChoice as $, AssistantMessage as A, ResolvedSchema as B, CombinedStandardSchema as C, DeveloperMessage as D, ExecutableTool as E, FilePart as F, StepEndEvent as G, StepEndFailEvent as H, ImagePart as I, JSONSchema7 as J, StepStartEvent as K, LanguageModelOptions as L, Message as M, StepStatus as N, SystemMessage as O, PartProviderMetadata as P, SystemMessageContent as Q, RawEvent as R, StepEndDoneEvent as S, ToolCallPart as T, Usage as U, TextDeltaEvent as V, TextEventMap as W, TextEventType as X, TextPart as Y, Tool as Z, ToolCallDeltaEvent as _, ToolResultPart as a, ToolOptions as a0, ToolResultPartContent as a1, UnresolvedSchema as a2, UserMessage as a3, UserMessageContent as a4, TextEvent as b, LanguageModel as c, ToolExecuteOptions as d, AssistantMessageContent as e, AudioPart as f, Content as g, ContentEndEvent as h, ContentMap as i, ContentStartEvent as j, ContentType as k, DeveloperMessageContent as l, FinishReason as m, InferSchemaInput as n, InferSchemaOutput as o, JSONSchema7Definition as p, LanguageModelProviderOptions as q, MessageMap as r, MessageProviderMetadata as s, MessageType as t, ProviderPart as u, ReasoningDeltaEvent as v, ReasoningPart as w, ReasoningPartContent as x, RefusalDeltaEvent as y, RefusalPart as z };
@@ -0,0 +1,50 @@
1
+ import { XSAIError } from '@xsai/shared';
2
+
3
+ const formatIssues = (issues) => issues.map(({ message, path }) => {
4
+ const location = path?.map((segment) => String(typeof segment === "object" ? segment.key : segment)).join(".");
5
+ return location == null || location === "" ? message : `${location}: ${message}`;
6
+ }).join("; ");
7
+ const resolveSchema = (schema) => "~standard" in schema ? {
8
+ schema: schema["~standard"].jsonSchema.input({ target: "draft-07" }),
9
+ validate: schema["~standard"].validate
10
+ } : { schema };
11
+
12
+ const readEvents = async function* (stream, signal) {
13
+ const reader = stream.getReader();
14
+ let cancellation;
15
+ const abort = () => {
16
+ cancellation = reader.cancel(signal.reason);
17
+ void cancellation.catch(() => {
18
+ });
19
+ };
20
+ signal.addEventListener("abort", abort, { once: true });
21
+ try {
22
+ signal.throwIfAborted();
23
+ while (true) {
24
+ const { done, value } = await reader.read();
25
+ signal.throwIfAborted();
26
+ if (done)
27
+ return;
28
+ yield value;
29
+ }
30
+ } finally {
31
+ signal.removeEventListener("abort", abort);
32
+ await (cancellation ?? reader.cancel(signal.reason)).finally(() => reader.releaseLock());
33
+ }
34
+ };
35
+ const readStep = async function* (stream, signal) {
36
+ let stepEnd;
37
+ for await (const event of readEvents(stream, signal)) {
38
+ if (event.type === "step.end") {
39
+ if (stepEnd != null)
40
+ throw new XSAIError("protocol-error", "model stream produced more than one step.end event");
41
+ stepEnd = event;
42
+ }
43
+ yield event;
44
+ }
45
+ if (stepEnd == null)
46
+ throw new XSAIError("truncated-stream", "model stream ended without a step.end event");
47
+ return stepEnd;
48
+ };
49
+
50
+ export { resolveSchema as a, readEvents as b, formatIssues as f, readStep as r };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xsai/text",
3
3
  "type": "module",
4
- "version": "1.0.0-beta.5",
4
+ "version": "1.0.0-beta.7",
5
5
  "description": "extra-small AI SDK: provider-agnostic text generation, streaming and tool calling.",
6
6
  "author": "Moeru AI",
7
7
  "license": "MIT",
@@ -41,7 +41,7 @@
41
41
  "node": ">=26"
42
42
  },
43
43
  "dependencies": {
44
- "@xsai/shared": "1.0.0-beta.5"
44
+ "@xsai/shared": "1.0.0-beta.7"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@standard-schema/spec": "1.1.0",
@@ -1,6 +0,0 @@
1
- const resolveSchema = (schema) => "~standard" in schema ? {
2
- schema: schema["~standard"].jsonSchema.input({ target: "draft-07" }),
3
- validate: schema["~standard"].validate
4
- } : { schema };
5
-
6
- export { resolveSchema as r };