refactor!: move step interface, tools option to shared-chat (#173)

* refactor!: move step interface to shared-chat

* refactor: move tools to chat options

* fix: optional type
This commit is contained in:
藍+85CD authored and GitHub committed 2025-07-04 20:20:47 +08:00
1 parent 65f0c01eee
commit f429e33920
9 files changed
+34 -48

No files matched your search

+7 -17
View File
@@ -1,4 +1,4 @@
import type { AssistantMessageResponse, ChatOptions, CompletionToolCall, CompletionToolResult, FinishReason, Message, StepType, Tool, Usage } from '@xsai/shared-chat'
import type { AssistantMessageResponse, ChatOptions, CompletionStep, CompletionToolCall, CompletionToolResult, FinishReason, Message, Usage } from '@xsai/shared-chat'
import { responseJSON, trampoline } from '@xsai/shared'
import { chat, determineStepType, executeTool } from '@xsai/shared-chat'
@@ -6,12 +6,11 @@ import { chat, determineStepType, executeTool } from '@xsai/shared-chat'
export interface GenerateTextOptions extends ChatOptions {
/** @default 1 */
maxSteps?: number
onStepFinish?: (step: GenerateTextStepResult) => Promise<unknown> | unknown
onStepFinish?: (step: CompletionStep<true>) => Promise<unknown> | unknown
/** @internal */
steps?: GenerateTextStepResult[]
steps?: CompletionStep<true>[]
/** if you want to enable stream, use `@xsai/stream-{text,object}` */
stream?: never
tools?: Tool[]
}
export interface GenerateTextResponse {
@@ -31,16 +30,7 @@ export interface GenerateTextResponse {
export interface GenerateTextResult {
finishReason: FinishReason
messages: Message[]
steps: GenerateTextStepResult[]
text?: string
toolCalls: CompletionToolCall[]
toolResults: CompletionToolResult[]
usage: Usage
}
export interface GenerateTextStepResult {
finishReason: FinishReason
stepType: StepType
steps: CompletionStep<true>[]
text?: string
toolCalls: CompletionToolCall[]
toolResults: CompletionToolResult[]
@@ -70,7 +60,7 @@ const rawGenerateText: RawGenerateText = async (options: GenerateTextOptions) =>
throw new Error(`No choices returned, response body: ${JSON.stringify(res)}`)
const messages: Message[] = structuredClone(options.messages)
const steps: GenerateTextStepResult[] = options.steps ? structuredClone(options.steps) : []
const steps: CompletionStep<true>[] = options.steps ? structuredClone(options.steps) : []
const toolCalls: CompletionToolCall[] = []
const toolResults: CompletionToolResult[] = []
@@ -87,7 +77,7 @@ const rawGenerateText: RawGenerateText = async (options: GenerateTextOptions) =>
messages.push({ ...message, content: message.content })
if (finishReason === 'stop' || stepType === 'done') {
const step: GenerateTextStepResult = {
const step: CompletionStep<true> = {
finishReason,
stepType,
text: message.content,
@@ -129,7 +119,7 @@ const rawGenerateText: RawGenerateText = async (options: GenerateTextOptions) =>
})
}
const step: GenerateTextStepResult = {
const step: CompletionStep<true> = {
finishReason,
stepType,
text: message.content,
+1 -1
View File
@@ -1,7 +1,7 @@
export type * from './finish-reason'
export type * from './message'
export type * from './message-part'
export type * from './step-type'
export type * from './step'
export type * from './tool'
export type * from './tool-choice'
export type * from './usage'
@@ -1 +0,0 @@
export type StepType = 'continue' | 'done' | 'initial' | 'tool-result'
+13
View File
@@ -0,0 +1,13 @@
import type { FinishReason } from './finish-reason'
import type { CompletionToolCall, CompletionToolResult } from './tool'
import type { Usage } from './usage'
export type CompletionStep<T extends boolean = false> = (T extends true ? { usage: Usage } : { usage?: Usage }) & {
finishReason: FinishReason
stepType: CompletionStepType
text?: string
toolCalls: CompletionToolCall[]
toolResults: CompletionToolResult[]
}
export type CompletionStepType = 'continue' | 'done' | 'initial' | 'tool-result'
+2 -1
View File
@@ -27,6 +27,7 @@ export interface ChatOptions extends CommonRequestOptions {
*/
temperature?: number
toolChoice?: ToolChoice
tools?: Tool[]
/** @default 1 */
topP?: number
}
@@ -35,7 +36,7 @@ export const chat = async <T extends ChatOptions>(options: T) =>
(options.fetch ?? globalThis.fetch)(requestURL('chat/completions', options.baseURL), {
body: requestBody({
...options,
tools: (options.tools as Tool[] | undefined)?.map(tool => ({
tools: (options.tools)?.map(tool => ({
function: clean({
...tool.function,
returns: undefined,
@@ -1,4 +1,4 @@
import type { FinishReason, StepType } from '../types'
import type { CompletionStepType, FinishReason } from '../types'
export interface DetermineStepTypeOptions {
finishReason: FinishReason
@@ -8,7 +8,7 @@ export interface DetermineStepTypeOptions {
}
/** @internal */
export const determineStepType = ({ finishReason, maxSteps, stepsLength, toolCallsLength }: DetermineStepTypeOptions): StepType => {
export const determineStepType = ({ finishReason, maxSteps, stepsLength, toolCallsLength }: DetermineStepTypeOptions): CompletionStepType => {
if (stepsLength === 0) {
return 'initial'
}
@@ -1,10 +1,9 @@
import type { ChatOptions, CompletionToolCall, CompletionToolResult, FinishReason, Message, Tool, ToolCall, Usage } from '@xsai/shared-chat'
import type { ChatOptions, CompletionStep, CompletionToolCall, CompletionToolResult, FinishReason, Message, ToolCall, Usage } from '@xsai/shared-chat'
import { objCamelToSnake, trampoline } from '@xsai/shared'
import { chat, determineStepType, executeTool } from '@xsai/shared-chat'
import type { StreamTextEvent } from './types/event'
import type { StreamTextStep } from './types/step-result'
import { transformChunk } from './_transform-chunk'
import { DelayedPromise } from './internal/delayed-promise'
@@ -13,8 +12,8 @@ export interface StreamTextOptions extends ChatOptions {
/** @default 1 */
maxSteps?: number
onEvent?: (event: StreamTextEvent) => Promise<unknown> | unknown
onFinish?: (step?: StreamTextStep) => Promise<unknown> | unknown
onStepFinish?: (step: StreamTextStep) => Promise<unknown> | unknown
onFinish?: (step?: CompletionStep) => Promise<unknown> | unknown
onStepFinish?: (step: CompletionStep) => Promise<unknown> | unknown
/**
* If you want to disable stream, use `@xsai/generate-{text,object}`.
*/
@@ -26,13 +25,12 @@ export interface StreamTextOptions extends ChatOptions {
*/
includeUsage?: boolean
}
tools?: Tool[]
}
export interface StreamTextResult {
fullStream: ReadableStream<StreamTextEvent>
messages: Promise<Message[]>
steps: Promise<StreamTextStep[]>
steps: Promise<CompletionStep[]>
textStream: ReadableStream<string>
usage: Promise<undefined | Usage>
// TODO: totalUsage
@@ -40,13 +38,13 @@ export interface StreamTextResult {
export const streamText = async (options: StreamTextOptions): Promise<StreamTextResult> => {
// state
const steps: StreamTextStep[] = []
const steps: CompletionStep[] = []
const messages: Message[] = structuredClone(options.messages)
const maxSteps = options.maxSteps ?? 1
let usage: undefined | Usage
// result state
const resultSteps = new DelayedPromise<StreamTextStep[]>()
const resultSteps = new DelayedPromise<CompletionStep[]>()
const resultMessages = new DelayedPromise<Message[]>()
const resultUsage = new DelayedPromise<undefined | Usage>()
@@ -62,7 +60,7 @@ export const streamText = async (options: StreamTextOptions): Promise<StreamText
void options.onEvent?.(stepEvent)
}
const pushStep = (step: StreamTextStep) => {
const pushStep = (step: CompletionStep) => {
steps.push(step)
// eslint-disable-next-line sonarjs/void-use
void options.onStepFinish?.(step)
@@ -1,10 +0,0 @@
import type { CompletionToolCall, CompletionToolResult, FinishReason, StepType, Usage } from '@xsai/shared-chat'
export interface StreamTextStep {
finishReason: FinishReason
stepType: StepType
text?: string
toolCalls: CompletionToolCall[]
toolResults: CompletionToolResult[]
usage?: Usage
}
+2 -7
View File
@@ -1,4 +1,4 @@
import type { AssistantMessage, ChatOptions, CompletionToolCall, CompletionToolResult, FinishReason, Message, StepType, Tool, ToolCall, ToolMessagePart, Usage } from '@xsai/shared-chat'
import type { AssistantMessage, ChatOptions, CompletionStepType, CompletionToolCall, CompletionToolResult, FinishReason, Message, ToolCall, ToolMessagePart, Usage } from '@xsai/shared-chat'
import { objCamelToSnake, XSAIError } from '@xsai/shared'
import { chat, determineStepType, executeTool } from '@xsai/shared-chat'
@@ -75,11 +75,6 @@ export interface StreamTextOptions extends ChatOptions {
*/
includeUsage?: boolean
}
/**
* List of tools to be used in the stream.
*/
tools?: Tool[]
}
export interface StreamTextResult {
@@ -92,7 +87,7 @@ export interface StreamTextStep {
choices: StreamTextChoice[]
finishReason: FinishReason
messages: Message[]
stepType: StepType
stepType: CompletionStepType
toolCalls: CompletionToolCall[]
toolResults: CompletionToolResult[]
usage?: Usage