diff --git a/.vscode/settings.json b/.vscode/settings.json index c4d2553..e048cc2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -47,9 +47,4 @@ "pcss", "postcss" ], - - // Enable unstable_ts_config - "eslint.options": { - "flags": ["unstable_ts_config"] - } } diff --git a/packages/generate-object/src/index.ts b/packages/generate-object/src/index.ts index 6b29fe3..527bfea 100644 --- a/packages/generate-object/src/index.ts +++ b/packages/generate-object/src/index.ts @@ -8,8 +8,8 @@ export interface GenerateObjectOptions extends GenerateTextOpt schemaName?: string } -// TODO: toolCalls, toolResults -export interface GenerateObjectResult extends Omit { +// TODO: toolCalls +export interface GenerateObjectResult extends Omit { object: Infer } diff --git a/packages/generate-text/package.json b/packages/generate-text/package.json index e9e0622..bf6dee7 100644 --- a/packages/generate-text/package.json +++ b/packages/generate-text/package.json @@ -32,7 +32,8 @@ "test:watch": "vitest" }, "dependencies": { - "@xsai/shared-chat": "workspace:" + "@xsai/shared-chat": "workspace:", + "@xsai/tool": "workspace:" }, "devDependencies": { "@xsai/providers": "workspace:" diff --git a/packages/generate-text/src/index.ts b/packages/generate-text/src/index.ts index c0bdcbb..192d542 100644 --- a/packages/generate-text/src/index.ts +++ b/packages/generate-text/src/index.ts @@ -1,12 +1,13 @@ -import { - type AssistantMessageResponse, - chat, - type ChatOptions, - type FinishReason, - type Message, - type Tool, - type Usage, +import type { + AssistantMessageResponse, + ChatOptions, + FinishReason, + Message, + Usage, } from '@xsai/shared-chat' +import type { ToolCall } from '@xsai/tool' + +import { chat } from '@xsai/shared-chat' export interface GenerateTextOptions extends ChatOptions { /** @default 1 */ @@ -37,7 +38,6 @@ export interface GenerateTextResult { steps: StepResult[] text?: string toolCalls: ToolCall[] - toolResults: ToolResult[] usage: Usage } @@ -46,24 +46,9 @@ export interface StepResult { // TODO: step type // type: 'continue' | 'initial' | 'tool-result' toolCalls: ToolCall[] - toolResults: ToolResult[] usage: Usage } -export interface ToolCall { - args: string - toolCallId: string - toolCallType: 'function' - toolName: string -} - -export interface ToolResult { - args: Record - result: string - toolCallId: string - toolName: string -} - /** @internal */ type RawGenerateText = (options: GenerateTextOptions) => RawGenerateTextTrampoline @@ -84,7 +69,6 @@ const rawGenerateText: RawGenerateText = async (options: GenerateTextOptions) => const messages: Message[] = options.messages const steps: StepResult[] = options.steps ?? [] const toolCalls: ToolCall[] = [] - const toolResults: ToolResult[] = [] const { finish_reason: finishReason, message } = choices[0] @@ -92,7 +76,6 @@ const rawGenerateText: RawGenerateText = async (options: GenerateTextOptions) => const step: StepResult = { text: message.content, toolCalls, - toolResults, usage, } @@ -115,22 +98,21 @@ const rawGenerateText: RawGenerateText = async (options: GenerateTextOptions) => id: toolCallId, type: toolCallType, } of message.tool_calls) { - const tool = (options.tools as Tool[]).find(tool => tool.function.name === toolName)! + const tool = options.tools?.find(tool => tool.function.name === toolName) + if (!tool) { + continue + } + const parsedArgs: Record = JSON.parse(toolArgs) - const result = await tool.execute(parsedArgs) + const result = await tool.execute(parsedArgs as never) toolCalls.push({ - args: toolArgs, - toolCallId, - toolCallType, - toolName, - }) - - toolResults.push({ - args: parsedArgs, + id: toolCallId, + name: toolName, + parameters: toolArgs, + parsedParameters: parsedArgs, result, - toolCallId, - toolName, + type: toolCallType, }) messages.push({ @@ -143,7 +125,6 @@ const rawGenerateText: RawGenerateText = async (options: GenerateTextOptions) => const step: StepResult = { text: message.content, toolCalls, - toolResults, usage, } diff --git a/packages/generate-text/test/index.test.ts b/packages/generate-text/test/index.test.ts index fe4dc0b..69d10b0 100644 --- a/packages/generate-text/test/index.test.ts +++ b/packages/generate-text/test/index.test.ts @@ -7,7 +7,7 @@ describe('@xsai/generate-text', () => { it('basic', async () => { let step: StepResult | undefined - const { finishReason, steps, text, toolCalls, toolResults } = await generateText({ + const { finishReason, steps, text, toolCalls } = await generateText({ ...ollama.chat('llama3.2'), messages: [ { @@ -27,7 +27,6 @@ describe('@xsai/generate-text', () => { expect(text).toStrictEqual('YES') expect(finishReason).toBe('stop') expect(toolCalls.length).toBe(0) - expect(toolResults.length).toBe(0) expect(steps).toMatchSnapshot() expect(steps[0]).toStrictEqual(step) diff --git a/packages/shared-chat/package.json b/packages/shared-chat/package.json index 046d19e..d88164a 100644 --- a/packages/shared-chat/package.json +++ b/packages/shared-chat/package.json @@ -30,6 +30,7 @@ "build:watch": "pkgroll --watch" }, "dependencies": { - "@xsai/shared": "workspace:" + "@xsai/shared": "workspace:", + "@xsai/tool": "workspace:" } } diff --git a/packages/shared-chat/src/types/chat-options.ts b/packages/shared-chat/src/types/chat-options.ts index 3952cee..cb0673d 100644 --- a/packages/shared-chat/src/types/chat-options.ts +++ b/packages/shared-chat/src/types/chat-options.ts @@ -1,4 +1,5 @@ import type { CommonRequestOptions } from '@xsai/shared' +import type { Tool } from '@xsai/tool' import type { Message } from './message' import type { ToolChoice } from './tool-choice' @@ -7,4 +8,5 @@ export interface ChatOptions extends CommonRequestOptions { [key: string]: unknown messages: Message[] toolChoice?: ToolChoice + tools?: Tool[] } diff --git a/packages/shared-chat/src/types/index.ts b/packages/shared-chat/src/types/index.ts index ba56499..e0b5de0 100644 --- a/packages/shared-chat/src/types/index.ts +++ b/packages/shared-chat/src/types/index.ts @@ -2,6 +2,5 @@ export type * from './chat-options' export type * from './finish-reason' export type * from './message' export type * from './message-part' -export type * from './tool' export type * from './tool-choice' export type * from './usage' diff --git a/packages/shared-chat/src/types/tool.ts b/packages/shared-chat/src/types/tool.ts deleted file mode 100644 index aea0f06..0000000 --- a/packages/shared-chat/src/types/tool.ts +++ /dev/null @@ -1,10 +0,0 @@ -export interface Tool { - execute: (input: unknown) => Promise | string - function: { - description?: string - name: string - parameters: Record - strict?: boolean - } - type: 'function' -} diff --git a/packages/shared-chat/src/utils/chat.ts b/packages/shared-chat/src/utils/chat.ts index efe7543..9e9a62f 100644 --- a/packages/shared-chat/src/utils/chat.ts +++ b/packages/shared-chat/src/utils/chat.ts @@ -1,12 +1,12 @@ import { requestBody, requestHeaders, requestURL, responseCatch } from '@xsai/shared' -import type { ChatOptions, Tool } from '../types' +import type { ChatOptions } from '../types' export const chat = async (options: T) => await (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: tool.function, type: 'function', })), diff --git a/packages/tool/package.json b/packages/tool/package.json index f3d03b6..ff0a00a 100644 --- a/packages/tool/package.json +++ b/packages/tool/package.json @@ -20,9 +20,6 @@ ".": { "types": "./dist/index.d.ts", "default": "./dist/index.js" - }, - "./generate-text": { - "types": "./dist/generate-text.d.ts" } }, "files": [ diff --git a/packages/tool/src/generate-text.ts b/packages/tool/src/generate-text.ts deleted file mode 100644 index 17b35a3..0000000 --- a/packages/tool/src/generate-text.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { Schema } from '@typeschema/main' -// eslint-disable-next-line unused-imports/no-unused-imports -import type { GenerateTextOptions as _GTO } from '@xsai/generate-text' - -import type { ToolResult } from '.' - -declare module '@xsai/generate-text' { - export interface GenerateTextOptions { - tools?: ToolResult[] - } -} diff --git a/packages/tool/src/index.ts b/packages/tool/src/index.ts index fb9c71d..79373cc 100644 --- a/packages/tool/src/index.ts +++ b/packages/tool/src/index.ts @@ -3,26 +3,35 @@ import type { InferIn, Schema } from '@typeschema/main' import { toJSONSchema } from '@typeschema/main' import { clean } from '@xsai/shared' -export interface ToolOptions { - description?: string - execute: (input: InferIn) => Promise | string - name: string - parameters: T - strict?: boolean -} - -export interface ToolResult { - execute: (input: InferIn) => Promise | string +export interface Tool { + execute: (input: unknown extends InferIn ? never : InferIn) => Promise | string function: { description?: string name: string - parameters: Record + parameters: InferIn strict?: boolean } type: 'function' } -export const tool = async (options: ToolOptions): Promise> => ({ +export interface ToolCall { + id: string + name: string + parameters: string + parsedParameters: Record + result: string + type: 'function' +} + +export interface ToolOptions { + description?: string + execute: (input: InferIn) => Promise | string + name: string + parameters: T + strict?: boolean +} + +export const tool = async (options: ToolOptions): Promise> => ({ execute: options.execute, function: { description: options.description, diff --git a/packages/tool/test/index.test.ts b/packages/tool/test/index.test.ts index e28318b..39a3249 100644 --- a/packages/tool/test/index.test.ts +++ b/packages/tool/test/index.test.ts @@ -70,13 +70,11 @@ describe('@xsai/tool', () => { expect(text).toMatchSnapshot() - const { toolCalls, toolResults } = steps[0] + const { toolCalls } = steps[0] - expect(toolCalls[0].toolName).toBe('weather') - expect(toolCalls[0].args).toBe('{"location":"San Francisco"}') - - expect(toolCalls[0].toolName).toBe('weather') - expect(toolResults[0].args).toStrictEqual({ location: 'San Francisco' }) - expect(toolResults[0].result).toBe('{"location":"San Francisco","temperature":42}') + expect(toolCalls[0].name).toBe('weather') + expect(toolCalls[0].parameters).toBe('{"location":"San Francisco"}') + expect(toolCalls[0].parsedParameters).toStrictEqual({ location: 'San Francisco' }) + expect(toolCalls[0].result).toBe('{"location":"San Francisco","temperature":42}') }, 20000) }) diff --git a/packages/xsai/src/index.ts b/packages/xsai/src/index.ts index 5dfb2b9..7289a35 100644 --- a/packages/xsai/src/index.ts +++ b/packages/xsai/src/index.ts @@ -13,4 +13,4 @@ export { listModels, type ListModelsOptions, type ListModelsResponse, type Model export * from '@xsai/shared-chat' export { streamObject, type StreamObjectOptions, type StreamObjectResult } from '@xsai/stream-object' export { type ChunkResult, streamText, type StreamTextOptions, type StreamTextResult } from '@xsai/stream-text' -export { tool, type ToolOptions, type ToolResult } from '@xsai/tool' +export { tool, type Tool, type ToolCall, type ToolOptions } from '@xsai/tool' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5f56b8e..8d781a7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -216,6 +216,9 @@ importers: '@xsai/shared-chat': specifier: 'workspace:' version: link:../shared-chat + '@xsai/tool': + specifier: 'workspace:' + version: link:../tool devDependencies: '@xsai/providers': specifier: 'workspace:' @@ -257,6 +260,9 @@ importers: '@xsai/shared': specifier: 'workspace:' version: link:../shared + '@xsai/tool': + specifier: 'workspace:' + version: link:../tool packages/stream-object: dependencies: