From 13c0b4a43f00fde24a72de88463d3758e538537f Mon Sep 17 00:00:00 2001 From: tbxark Date: Mon, 11 Nov 2024 16:30:16 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=9F=BA=E4=BA=8Evercel=20ai=20?= =?UTF-8?q?=E7=9A=84API=E8=AE=BE=E8=AE=A1=E9=87=8D=E6=9E=84chat=20agent=20?= =?UTF-8?q?feat:=20gemini=20=E4=BF=AE=E6=94=B9=E4=B8=BA=20openai=20api?= =?UTF-8?q?=E5=85=BC=E5=AE=B9=E6=A8=A1=E5=BC=8F,=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E6=97=A7=20chore:=20=E5=BA=9F=E5=BC=83SYSTEM=5FINIT=5FMESSAGE?= =?UTF-8?q?=5FROLE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dist/buildinfo.json | 2 +- dist/index.js | 331 +++++++++++++++++---------------- package.json | 4 + src/agent/anthropic.ts | 49 +++-- src/agent/azure.ts | 19 +- src/agent/chat.ts | 39 ++-- src/agent/cohere.ts | 18 +- src/agent/gemini.ts | 77 ++------ src/agent/index.test.ts | 8 +- src/agent/index.ts | 2 +- src/agent/mistralai.ts | 24 +-- src/agent/openai.ts | 62 +++--- src/agent/types.ts | 45 ++--- src/agent/utils.ts | 49 +++++ src/agent/workersai.ts | 18 +- src/config/config.ts | 26 ++- src/config/version.ts | 4 +- src/telegram/command/system.ts | 22 ++- src/telegram/handler/chat.ts | 23 ++- tsconfig.json | 12 +- yarn.lock | 327 +++++++++++++++++++++++++++++++- 21 files changed, 766 insertions(+), 395 deletions(-) create mode 100644 src/agent/utils.ts diff --git a/dist/buildinfo.json b/dist/buildinfo.json index 92762565..67145a68 100644 --- a/dist/buildinfo.json +++ b/dist/buildinfo.json @@ -1 +1 @@ -{"sha":"62b8147","timestamp":1730790946} \ No newline at end of file +{"sha":"08366a5","timestamp":1731312843} \ No newline at end of file diff --git a/dist/index.js b/dist/index.js index d2639cb0..b3182f70 100644 --- a/dist/index.js +++ b/dist/index.js @@ -69,13 +69,13 @@ class AgentShareConfig { AI_PROVIDER = "auto"; AI_IMAGE_PROVIDER = "auto"; SYSTEM_INIT_MESSAGE = null; - SYSTEM_INIT_MESSAGE_ROLE = "system"; } class OpenAIConfig { OPENAI_API_KEY = []; OPENAI_CHAT_MODEL = "gpt-4o-mini"; OPENAI_API_BASE = "https://api.openai.com/v1"; OPENAI_API_EXTRA_PARAMS = {}; + OPENAI_CHAT_MODELS_LIST = "https://api.openai.com/v1/models"; } class DalleAIConfig { DALL_E_MODEL = "dall-e-2"; @@ -87,32 +87,38 @@ class AzureConfig { AZURE_API_KEY = null; AZURE_COMPLETIONS_API = null; AZURE_DALLE_API = null; + AZURE_CHAT_MODELS_LIST = "[]"; } class WorkersConfig { CLOUDFLARE_ACCOUNT_ID = null; CLOUDFLARE_TOKEN = null; WORKERS_CHAT_MODEL = "@cf/mistral/mistral-7b-instruct-v0.1 "; WORKERS_IMAGE_MODEL = "@cf/stabilityai/stable-diffusion-xl-base-1.0"; + WORKERS_CHAT_MODELS_LIST = "https://api.cloudflare.com/client/v4/accounts/_YOUR_ACCOUNT_ID_/ai/models/search?task=Text%20Generation"; } class GeminiConfig { GOOGLE_API_KEY = null; - GOOGLE_COMPLETIONS_API = "https://generativelanguage.googleapis.com/v1beta/models/"; - GOOGLE_COMPLETIONS_MODEL = "gemini-pro"; + GOOGLE_API_BASE = "https://generativelanguage.googleapis.com/v1beta"; + GOOGLE_COMPLETIONS_MODEL = "gemini-1.5-flash"; + GOOGLE_CHAT_MODELS_LIST = `["gemini-1.5-flash"]`; } class MistralConfig { MISTRAL_API_KEY = null; MISTRAL_API_BASE = "https://api.mistral.ai/v1"; MISTRAL_CHAT_MODEL = "mistral-tiny"; + MISTRAL_CHAT_MODELS_LIST = "https://api.mistral.ai/v1/models"; } class CohereConfig { COHERE_API_KEY = null; COHERE_API_BASE = "https://api.cohere.com/v2"; COHERE_CHAT_MODEL = "command-r-plus"; + COHERE_CHAT_MODELS_LIST = "https://api.cohere.com/v1/models"; } class AnthropicConfig { ANTHROPIC_API_KEY = null; ANTHROPIC_API_BASE = "https://api.anthropic.com/v1"; - ANTHROPIC_CHAT_MODEL = "claude-3-haiku-20240307"; + ANTHROPIC_CHAT_MODEL = "claude-3-5-haiku-latest"; + ANTHROPIC_CHAT_MODELS_LIST = `["claude-3-5-sonnet-latest", "claude-3-5-haiku-latest"]`; } class DefineKeys { DEFINE_KEYS = []; @@ -190,8 +196,8 @@ class ConfigMerger { } } -const BUILD_TIMESTAMP = 1730790946; -const BUILD_VERSION = "62b8147"; +const BUILD_TIMESTAMP = 1731312843; +const BUILD_VERSION = "08366a5"; function createAgentUserConfig() { return Object.assign( @@ -843,9 +849,6 @@ async function imageToBase64String(url) { format: `image/${format}` }; } -function renderBase64DataURI(params) { - return `data:${params.format};base64,${params.data}`; -} class Stream { response; @@ -1148,6 +1151,45 @@ ERROR: ${e.message}`; } } +function extractTextContent(history) { + if (typeof history.content === "string") { + return history.content; + } + if (Array.isArray(history.content)) { + return history.content.map((item) => { + if (item.type === "text") { + return item.text; + } + return ""; + }).join(""); + } + return ""; +} +function extractImageContent(imageData) { + if (imageData instanceof URL) { + return { url: imageData.href }; + } + if (typeof imageData === "string") { + if (imageData.startsWith("http")) { + return { url: imageData }; + } else { + return { base64: imageData }; + } + } + if (imageData instanceof Uint8Array) { + return { base64: Buffer.from(imageData).toString("base64") }; + } + if (Buffer.isBuffer(imageData)) { + return { base64: Buffer.from(imageData).toString("base64") }; + } + return {}; +} +function convertStringToResponseMessages(input) { + return input.then((res) => { + return [{ role: "assistant", content: res }]; + }); +} + class Anthropic { name = "anthropic"; modelKey = "ANTHROPIC_CHAT_MODEL"; @@ -1159,16 +1201,30 @@ class Anthropic { role: item.role, content: item.content }; - if (item.images && item.images.length > 0) { - res.content = []; - if (item.content) { - res.content.push({ type: "text", text: item.content }); - } - for (const image of item.images) { - res.content.push(await imageToBase64String(image).then(({ format, data }) => { - return { type: "image", source: { type: "base64", media_type: format, data } }; - })); + if (item.role === "system") { + return null; + } + if (Array.isArray(item.content)) { + const contents = []; + for (const content of item.content) { + switch (content.type) { + case "text": + contents.push({ type: "text", text: content.text }); + break; + case "image": { + const data = extractImageContent(content.image); + if (data.url) { + contents.push(await imageToBase64String(data.url).then(({ format, data: data2 }) => { + return { type: "image", source: { type: "base64", media_type: format, data: data2 } }; + })); + } else if (data.base64) { + contents.push({ type: "image", source: { type: "base64", media_type: "image/jpeg", data: data.base64 } }); + } + break; + } + } } + res.content = contents; } return res; }; @@ -1195,21 +1251,20 @@ class Anthropic { } } request = async (params, context, onStream) => { - const { message, images, prompt, history } = params; + const { prompt, messages } = params; const url = `${context.ANTHROPIC_API_BASE}/messages`; const header = { "x-api-key": context.ANTHROPIC_API_KEY || "", "anthropic-version": "2023-06-01", "content-type": "application/json" }; - const messages = (history || []).concat({ role: "user", content: message, images }); if (messages.length > 0 && messages[0].role === "assistant") { messages.shift(); } const body = { system: prompt, model: context.ANTHROPIC_CHAT_MODEL, - messages: await Promise.all(messages.map((item) => this.render(item))), + messages: (await Promise.all(messages.map((item) => this.render(item)))).filter((i) => i !== null), stream: onStream != null, max_tokens: ENV.MAX_TOKEN_LENGTH > 0 ? ENV.MAX_TOKEN_LENGTH : 2048 }; @@ -1229,36 +1284,48 @@ class Anthropic { options.errorExtractor = function(data) { return data?.error?.message; }; - return requestChatCompletions(url, header, body, onStream, null, options); + return convertStringToResponseMessages(requestChatCompletions(url, header, body, onStream, null, options)); }; } -async function renderOpenAIMessage(item) { +async function renderOpenAIMessage(item, supportImage) { const res = { role: item.role, content: item.content }; - if (item.images && item.images.length > 0) { - res.content = []; - if (item.content) { - res.content.push({ type: "text", text: item.content }); - } - for (const image of item.images) { - switch (ENV.TELEGRAM_IMAGE_TRANSFER_MODE) { - case "base64": - res.content.push({ type: "image_url", image_url: { - url: renderBase64DataURI(await imageToBase64String(image)) - } }); + if (Array.isArray(item.content)) { + const contents = []; + for (const content of item.content) { + switch (content.type) { + case "text": + contents.push({ type: "text", text: content.text }); break; - case "url": - default: - res.content.push({ type: "image_url", image_url: { url: image } }); + case "image": + if (supportImage) { + const data = extractImageContent(content.image); + if (data.url) { + contents.push({ type: "image_url", image_url: { url: data.url } }); + } else if (data.base64) { + contents.push({ type: "image_url", image_url: { url: data.base64 } }); + } + } break; } } + res.content = contents; } return res; } +async function renderOpenAIMessages(prompt, items, supportImage) { + const messages = await Promise.all(items.map((r) => renderOpenAIMessage(r, supportImage))); + if (prompt) { + if (messages.length > 0 && messages[0].role === "system") { + messages.shift(); + } + messages.unshift({ role: "system", content: prompt }); + } + return messages; +} class OpenAIBase { name = "openai"; apikey = (context) => { @@ -1278,23 +1345,19 @@ class OpenAI extends OpenAIBase { return renderOpenAIMessage(item); }; request = async (params, context, onStream) => { - const { message, images, prompt, history } = params; + const { prompt, messages } = params; const url = `${context.OPENAI_API_BASE}/chat/completions`; const header = { "Content-Type": "application/json", "Authorization": `Bearer ${this.apikey(context)}` }; - const messages = [...history || [], { role: "user", content: message, images }]; - if (prompt) { - messages.unshift({ role: context.SYSTEM_INIT_MESSAGE_ROLE, content: prompt }); - } const body = { model: context.OPENAI_CHAT_MODEL, ...context.OPENAI_API_EXTRA_PARAMS, - messages: await Promise.all(messages.map(this.render)), + messages: await renderOpenAIMessages(prompt, messages, true), stream: onStream != null }; - return requestChatCompletions(url, header, body, onStream); + return convertStringToResponseMessages(requestChatCompletions(url, header, body, onStream)); }; } class Dalle extends OpenAIBase { @@ -1356,7 +1419,7 @@ class AzureChatAI extends AzureBase { return this.modelFromURI(ctx.AZURE_COMPLETIONS_API); }; request = async (params, context, onStream) => { - const { message, images, prompt, history } = params; + const { prompt, messages } = params; const url = context.AZURE_COMPLETIONS_API; if (!url || !context.AZURE_API_KEY) { throw new Error("Azure Completions API is not set"); @@ -1365,16 +1428,12 @@ class AzureChatAI extends AzureBase { "Content-Type": "application/json", "api-key": context.AZURE_API_KEY }; - const messages = [...history || [], { role: "user", content: message, images }]; - if (prompt) { - messages.unshift({ role: context.SYSTEM_INIT_MESSAGE_ROLE, content: prompt }); - } const body = { ...context.OPENAI_API_EXTRA_PARAMS, - messages: await Promise.all(messages.map(renderOpenAIMessage)), + messages: await renderOpenAIMessages(prompt, messages, true), stream: onStream != null }; - return requestChatCompletions(url, header, body, onStream); + return convertStringToResponseMessages(requestChatCompletions(url, header, body, onStream)); }; } class AzureImageAI extends AzureBase { @@ -1427,19 +1486,15 @@ class Cohere { return ctx.COHERE_CHAT_MODEL; }; request = async (params, context, onStream) => { - const { message, prompt, history } = params; + const { prompt, messages } = params; const url = `${context.COHERE_API_BASE}/chat`; const header = { "Authorization": `Bearer ${context.COHERE_API_KEY}`, "Content-Type": "application/json", "Accept": onStream !== null ? "text/event-stream" : "application/json" }; - const messages = [...history || [], { role: "user", content: message }]; - if (prompt) { - messages.unshift({ role: "assistant", content: prompt }); - } const body = { - messages, + messages: await renderOpenAIMessages(prompt, messages), model: context.COHERE_CHAT_MODEL, stream: onStream != null }; @@ -1453,72 +1508,33 @@ class Cohere { options.errorExtractor = function(data) { return data?.message; }; - return requestChatCompletions(url, header, body, onStream, null, options); + return convertStringToResponseMessages(requestChatCompletions(url, header, body, onStream, null, options)); }; } class Gemini { name = "gemini"; modelKey = "GOOGLE_COMPLETIONS_MODEL"; - static GEMINI_ROLE_MAP = { - assistant: "model", - system: "user", - user: "user" - }; enable = (context) => { return !!context.GOOGLE_API_KEY; }; model = (ctx) => { return ctx.GOOGLE_COMPLETIONS_MODEL; }; - render = (item) => { - return { - role: Gemini.GEMINI_ROLE_MAP[item.role], - parts: [ - { - text: item.content || "" - } - ] - }; - }; request = async (params, context, onStream) => { - const { message, prompt, history } = params; - if (onStream !== null) { - console.warn("Stream mode is not supported"); - } - const mode = "generateContent"; - const url = `${context.GOOGLE_COMPLETIONS_API}${context.GOOGLE_COMPLETIONS_MODEL}:${mode}`; - const contentsTemp = [...history || [], { role: "user", content: message }]; - if (prompt) { - contentsTemp.unshift({ role: "assistant", content: prompt }); - } - const contents = []; - for (const msg of contentsTemp) { - msg.role = Gemini.GEMINI_ROLE_MAP[msg.role]; - if (contents.length === 0 || contents[contents.length - 1].role !== msg.role) { - contents.push(this.render(msg)); - } else { - contents[contents.length - 1].parts[0].text += msg.content; - } - } - const resp = await fetch(url, { - method: "POST", - headers: { - "Content-Type": "application/json", - "x-goog-api-key": context.GOOGLE_API_KEY - }, - body: JSON.stringify({ contents }) - }); - const data = await resp.json(); - try { - return data.candidates[0].content.parts[0].text; - } catch (e) { - console.error(e); - if (!data) { - throw new Error("Empty response"); - } - throw new Error(data?.error?.message || JSON.stringify(data)); - } + const { prompt, messages } = params; + const url = `${context.GOOGLE_API_BASE}/chat`; + const header = { + "Authorization": `Bearer ${context.GOOGLE_API_KEY}`, + "Content-Type": "application/json", + "Accept": onStream !== null ? "text/event-stream" : "application/json" + }; + const body = { + messages: await renderOpenAIMessages(prompt, messages), + model: context.GOOGLE_COMPLETIONS_MODEL, + stream: onStream != null + }; + return convertStringToResponseMessages(requestChatCompletions(url, header, body, onStream)); }; } @@ -1531,29 +1547,19 @@ class Mistral { model = (ctx) => { return ctx.MISTRAL_CHAT_MODEL; }; - render = (item) => { - return { - role: item.role, - content: item.content - }; - }; request = async (params, context, onStream) => { - const { message, prompt, history } = params; + const { prompt, messages } = params; const url = `${context.MISTRAL_API_BASE}/chat/completions`; const header = { "Content-Type": "application/json", "Authorization": `Bearer ${context.MISTRAL_API_KEY}` }; - const messages = [...history || [], { role: "user", content: message }]; - if (prompt) { - messages.unshift({ role: context.SYSTEM_INIT_MESSAGE_ROLE, content: prompt }); - } const body = { model: context.MISTRAL_CHAT_MODEL, - messages: messages.map(this.render), + messages: await renderOpenAIMessages(prompt, messages), stream: onStream != null }; - return requestChatCompletions(url, header, body, onStream); + return convertStringToResponseMessages(requestChatCompletions(url, header, body, onStream)); }; } @@ -1585,7 +1591,7 @@ class WorkersChat extends WorkerBase { }; }; request = async (params, context, onStream) => { - const { message, prompt, history } = params; + const { prompt, messages } = params; const id = context.CLOUDFLARE_ACCOUNT_ID; const token = context.CLOUDFLARE_TOKEN; const model = context.WORKERS_CHAT_MODEL; @@ -1593,12 +1599,8 @@ class WorkersChat extends WorkerBase { const header = { Authorization: `Bearer ${token}` }; - const messages = [...history || [], { role: "user", content: message }]; - if (prompt) { - messages.unshift({ role: context.SYSTEM_INIT_MESSAGE_ROLE, content: prompt }); - } const body = { - messages: messages.map(this.render), + messages: await renderOpenAIMessages(prompt, messages), stream: onStream !== null }; const options = {}; @@ -1611,7 +1613,7 @@ class WorkersChat extends WorkerBase { options.errorExtractor = function(data) { return data?.errors?.[0]?.message; }; - return requestChatCompletions(url, header, body, onStream, null, options); + return convertStringToResponseMessages(requestChatCompletions(url, header, body, onStream, null, options)); }; } class WorkersImage extends WorkerBase { @@ -1715,7 +1717,7 @@ async function loadHistory(key) { const historyItem = list[i]; let length = 0; if (historyItem.content) { - length = counter(historyItem.content); + length = counter(extractTextContent(historyItem)); } else { historyItem.content = ""; } @@ -1741,28 +1743,31 @@ async function requestCompletionsFromLLM(params, context, agent, modifier, onStr } let history = await loadHistory(historyKey); if (modifier) { - const modifierData = modifier(history, params.message || null); + const modifierData = modifier(history, params || null); history = modifierData.history; - params.message = modifierData.message; + params = modifierData.message; + } + if (!params) { + throw new Error("Message is empty"); } + history.push(params); const llmParams = { - ...params, - history, - prompt: context.USER_CONFIG.SYSTEM_INIT_MESSAGE + prompt: context.USER_CONFIG.SYSTEM_INIT_MESSAGE || void 0, + messages: history }; const answer = await agent.request(llmParams, context.USER_CONFIG, onStream); if (!historyDisable) { - const userMessage = { role: "user", content: params.message || "", images: params.images }; - if (ENV.HISTORY_IMAGE_PLACEHOLDER && userMessage.images && userMessage.images.length > 0) { - delete userMessage.images; - userMessage.content = `${ENV.HISTORY_IMAGE_PLACEHOLDER} -${userMessage.content}`; - } - history.push(userMessage); - history.push({ role: "assistant", content: answer }); + if (ENV.HISTORY_IMAGE_PLACEHOLDER) ; + history.push(params); + history.push(...answer); await ENV.DATABASE.put(historyKey, JSON.stringify(history)).catch(console.error); } - return answer; + for (const item of answer) { + if (item.role === "assistant") { + return extractTextContent(item); + } + } + return ""; } async function chatWithLLM(message, params, context, modifier) { @@ -1838,16 +1843,24 @@ function findPhotoFileID(photos, offset) { } class ChatHandler { handle = async (message, context) => { + const text = message.text || message.caption || ""; const params = { - message: message.text || message.caption || "" + role: "user", + content: text }; if (message.photo && message.photo.length > 0) { const id = findPhotoFileID(message.photo, ENV.TELEGRAM_PHOTO_SIZE_OFFSET); const api = createTelegramBotAPI(context.SHARE_CONTEXT.botToken); const file = await api.getFileWithReturns({ file_id: id }); - const url = file.result.file_path; - if (url) { - params.images = [url]; + const filePath = file.result.file_path; + if (filePath) { + const url = URL.parse(filePath); + if (url) { + params.content = [ + { type: "text", text }, + { type: "image", image: url } + ]; + } } } return chatWithLLM(message, params, context, null); @@ -2151,8 +2164,8 @@ class RedoCommandHandler { command = "/redo"; scopes = ["all_private_chats", "all_group_chats", "all_chat_administrators"]; handle = async (message, subcommand, context) => { - const mf = (history, text) => { - let nextText = text; + const mf = (history, message2) => { + let nextMessage = message2; if (!(history && Array.isArray(history) && history.length > 0)) { throw new Error("History not found"); } @@ -2162,18 +2175,22 @@ class RedoCommandHandler { if (data === void 0 || data === null) { break; } else if (data.role === "user") { - if (text === "" || text === void 0 || text === null) { - nextText = data.content || null; - } + nextMessage = data; break; } } if (subcommand) { - nextText = subcommand; + nextMessage = { + role: "user", + content: subcommand + }; + } + if (nextMessage === null) { + throw new Error("Redo message not found"); } - return { history: historyCopy, message: nextText }; + return { history: historyCopy, message: nextMessage }; }; - return chatWithLLM(message, { message: null }, context, mf); + return chatWithLLM(message, null, context, mf); }; } class EchoCommandHandler { diff --git a/package.json b/package.json index 56b83e3e..7a0222f5 100644 --- a/package.json +++ b/package.json @@ -40,15 +40,19 @@ "test": "tsx ./src/agent/index.test.ts" }, "dependencies": { + "ai": "^3.4.33", "cloudflare-worker-adapter": "^1.3.3" }, "devDependencies": { "@antfu/eslint-config": "^3.6.2", "@rollup/plugin-node-resolve": "^15.2.3", "@types/node": "^22.5.5", + "@types/react": "^18.3.11", "@vercel/node": "^3.2.14", "eslint": "^9.10.0", "eslint-plugin-format": "^0.1.2", + "openai": "^4.68.1", + "react-dom": "^18.3.1", "rollup-plugin-cleanup": "^3.2.1", "rollup-plugin-node-externals": "^7.1.3", "telegram-bot-api-types": "^7.9.12", diff --git a/src/agent/anthropic.ts b/src/agent/anthropic.ts index 2c2c397e..92ffa102 100644 --- a/src/agent/anthropic.ts +++ b/src/agent/anthropic.ts @@ -1,11 +1,12 @@ import type { AgentUserConfig } from '../config/env'; import type { SseChatCompatibleOptions } from './request'; import type { SSEMessage, SSEParserResult } from './stream'; -import type { ChatAgent, ChatStreamTextHandler, HistoryItem, LLMChatParams } from './types'; +import type { ChatAgent, ChatStreamTextHandler, HistoryItem, LLMChatParams, ResponseMessage } from './types'; import { ENV } from '../config/env'; import { imageToBase64String } from '../utils/image'; import { requestChatCompletions } from './request'; import { Stream } from './stream'; +import { convertStringToResponseMessages, extractImageContent } from './utils'; export class Anthropic implements ChatAgent { readonly name = 'anthropic'; @@ -20,17 +21,32 @@ export class Anthropic implements ChatAgent { role: item.role, content: item.content, }; - - if (item.images && item.images.length > 0) { - res.content = []; - if (item.content) { - res.content.push({ type: 'text', text: item.content }); - } - for (const image of item.images) { - res.content.push(await imageToBase64String(image).then(({ format, data }) => { - return { type: 'image', source: { type: 'base64', media_type: format, data } }; - })); + if (item.role === 'system') { + return null; + } + if (Array.isArray(item.content)) { + const contents = []; + for (const content of item.content) { + switch (content.type) { + case 'text': + contents.push({ type: 'text', text: content.text }); + break; + case 'image': { + const data = extractImageContent(content.image); + if (data.url) { + contents.push(await imageToBase64String(data.url).then(({ format, data }) => { + return { type: 'image', source: { type: 'base64', media_type: format, data } }; + })); + } else if (data.base64) { + contents.push({ type: 'image', source: { type: 'base64', media_type: 'image/jpeg', data: data.base64 } }); + } + break; + } + default: + break; + } } + res.content = contents; } return res; }; @@ -64,8 +80,8 @@ export class Anthropic implements ChatAgent { } } - readonly request = async (params: LLMChatParams, context: AgentUserConfig, onStream: ChatStreamTextHandler | null): Promise => { - const { message, images, prompt, history } = params; + readonly request = async (params: LLMChatParams, context: AgentUserConfig, onStream: ChatStreamTextHandler | null): Promise => { + const { prompt, messages } = params; const url = `${context.ANTHROPIC_API_BASE}/messages`; const header = { 'x-api-key': context.ANTHROPIC_API_KEY || '', @@ -73,8 +89,6 @@ export class Anthropic implements ChatAgent { 'content-type': 'application/json', }; - const messages: HistoryItem[] = (history || []).concat({ role: 'user', content: message, images }); - if (messages.length > 0 && messages[0].role === 'assistant') { messages.shift(); } @@ -82,14 +96,13 @@ export class Anthropic implements ChatAgent { const body = { system: prompt, model: context.ANTHROPIC_CHAT_MODEL, - messages: await Promise.all(messages.map(item => this.render(item))), + messages: (await Promise.all(messages.map(item => this.render(item)))).filter(i => i !== null), stream: onStream != null, max_tokens: ENV.MAX_TOKEN_LENGTH > 0 ? ENV.MAX_TOKEN_LENGTH : 2048, }; if (!body.system) { delete body.system; } - const options: SseChatCompatibleOptions = {}; options.streamBuilder = function (r, c) { return new Stream(r, c, Anthropic.parser); @@ -103,6 +116,6 @@ export class Anthropic implements ChatAgent { options.errorExtractor = function (data: any) { return data?.error?.message; }; - return requestChatCompletions(url, header, body, onStream, null, options); + return convertStringToResponseMessages(requestChatCompletions(url, header, body, onStream, null, options)); }; } diff --git a/src/agent/azure.ts b/src/agent/azure.ts index d53fd781..5d6e17ae 100644 --- a/src/agent/azure.ts +++ b/src/agent/azure.ts @@ -1,7 +1,8 @@ import type { AgentUserConfig } from '../config/env'; -import type { ChatAgent, ChatStreamTextHandler, ImageAgent, LLMChatParams } from './types'; -import { renderOpenAIMessage } from './openai'; +import type { ChatAgent, ChatStreamTextHandler, ImageAgent, LLMChatParams, ResponseMessage } from './types'; +import { renderOpenAIMessages } from './openai'; import { requestChatCompletions } from './request'; +import { convertStringToResponseMessages } from './utils'; class AzureBase { readonly name = 'azure'; @@ -29,8 +30,8 @@ export class AzureChatAI extends AzureBase implements ChatAgent { return this.modelFromURI(ctx.AZURE_COMPLETIONS_API); }; - readonly request = async (params: LLMChatParams, context: AgentUserConfig, onStream: ChatStreamTextHandler | null): Promise => { - const { message, images, prompt, history } = params; + readonly request = async (params: LLMChatParams, context: AgentUserConfig, onStream: ChatStreamTextHandler | null): Promise => { + const { prompt, messages } = params; const url = context.AZURE_COMPLETIONS_API; if (!url || !context.AZURE_API_KEY) { throw new Error('Azure Completions API is not set'); @@ -40,18 +41,12 @@ export class AzureChatAI extends AzureBase implements ChatAgent { 'api-key': context.AZURE_API_KEY, }; - const messages = [...(history || []), { role: 'user', content: message, images }]; - if (prompt) { - messages.unshift({ role: context.SYSTEM_INIT_MESSAGE_ROLE, content: prompt }); - } - const body = { ...context.OPENAI_API_EXTRA_PARAMS, - messages: await Promise.all(messages.map(renderOpenAIMessage)), + messages: await renderOpenAIMessages(prompt, messages, true), stream: onStream != null, }; - - return requestChatCompletions(url, header, body, onStream); + return convertStringToResponseMessages(requestChatCompletions(url, header, body, onStream)); }; } diff --git a/src/agent/chat.ts b/src/agent/chat.ts index df7b4210..8e0f15ac 100644 --- a/src/agent/chat.ts +++ b/src/agent/chat.ts @@ -1,6 +1,7 @@ import type { WorkerContext } from '../config/context'; -import type { ChatAgent, HistoryItem, HistoryModifier, LLMChatRequestParams } from './types'; +import type { ChatAgent, HistoryItem, HistoryModifier, LLMChatParams, UserMessageItem } from './types'; import { ENV } from '../config/env'; +import { extractTextContent } from './utils'; /** * @returns {(function(string): number)} @@ -37,7 +38,7 @@ async function loadHistory(key: string): Promise { const historyItem = list[i]; let length = 0; if (historyItem.content) { - length = counter(historyItem.content); + length = counter(extractTextContent(historyItem)); } else { historyItem.content = ''; } @@ -62,7 +63,7 @@ async function loadHistory(key: string): Promise { export type StreamResultHandler = (text: string) => Promise; -export async function requestCompletionsFromLLM(params: LLMChatRequestParams, context: WorkerContext, agent: ChatAgent, modifier: HistoryModifier | null, onStream: StreamResultHandler | null): Promise { +export async function requestCompletionsFromLLM(params: UserMessageItem | null, context: WorkerContext, agent: ChatAgent, modifier: HistoryModifier | null, onStream: StreamResultHandler | null): Promise { const historyDisable = ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH <= 0; const historyKey = context.SHARE_CONTEXT.chatHistoryKey; if (!historyKey) { @@ -70,25 +71,31 @@ export async function requestCompletionsFromLLM(params: LLMChatRequestParams, co } let history = await loadHistory(historyKey); if (modifier) { - const modifierData = modifier(history, params.message || null); + const modifierData = modifier(history, params || null); history = modifierData.history; - params.message = modifierData.message; + params = modifierData.message; } - const llmParams = { - ...params, - history, - prompt: context.USER_CONFIG.SYSTEM_INIT_MESSAGE, + if (!params) { + throw new Error('Message is empty'); + } + history.push(params); + const llmParams: LLMChatParams = { + prompt: context.USER_CONFIG.SYSTEM_INIT_MESSAGE || undefined, + messages: history, }; const answer = await agent.request(llmParams, context.USER_CONFIG, onStream); if (!historyDisable) { - const userMessage = { role: 'user', content: params.message || '', images: params.images }; - if (ENV.HISTORY_IMAGE_PLACEHOLDER && userMessage.images && userMessage.images.length > 0) { - delete userMessage.images; - userMessage.content = `${ENV.HISTORY_IMAGE_PLACEHOLDER}\n${userMessage.content}`; + if (ENV.HISTORY_IMAGE_PLACEHOLDER) { + // TODO: Add image placeholder } - history.push(userMessage); - history.push({ role: 'assistant', content: answer }); + history.push(params); + history.push(...answer); await ENV.DATABASE.put(historyKey, JSON.stringify(history)).catch(console.error); } - return answer; + for (const item of answer) { + if (item.role === 'assistant') { + return extractTextContent(item); + } + } + return ''; } diff --git a/src/agent/cohere.ts b/src/agent/cohere.ts index 3085c971..8a650c1c 100644 --- a/src/agent/cohere.ts +++ b/src/agent/cohere.ts @@ -1,7 +1,9 @@ import type { AgentUserConfig } from '../config/env'; import type { SseChatCompatibleOptions } from './request'; -import type { ChatAgent, ChatStreamTextHandler, LLMChatParams } from './types'; +import type { ChatAgent, ChatStreamTextHandler, LLMChatParams, ResponseMessage } from './types'; +import { renderOpenAIMessages } from './openai'; import { requestChatCompletions } from './request'; +import { convertStringToResponseMessages } from './utils'; export class Cohere implements ChatAgent { readonly name = 'cohere'; @@ -15,22 +17,16 @@ export class Cohere implements ChatAgent { return ctx.COHERE_CHAT_MODEL; }; - readonly request = async (params: LLMChatParams, context: AgentUserConfig, onStream: ChatStreamTextHandler | null): Promise => { - const { message, prompt, history } = params; + readonly request = async (params: LLMChatParams, context: AgentUserConfig, onStream: ChatStreamTextHandler | null): Promise => { + const { prompt, messages } = params; const url = `${context.COHERE_API_BASE}/chat`; const header = { 'Authorization': `Bearer ${context.COHERE_API_KEY}`, 'Content-Type': 'application/json', 'Accept': onStream !== null ? 'text/event-stream' : 'application/json', }; - - const messages = [...history || [], { role: 'user', content: message }]; - if (prompt) { - messages.unshift({ role: 'assistant', content: prompt }); - } - const body = { - messages, + messages: await renderOpenAIMessages(prompt, messages), model: context.COHERE_CHAT_MODEL, stream: onStream != null, }; @@ -45,6 +41,6 @@ export class Cohere implements ChatAgent { options.errorExtractor = function (data: any) { return data?.message; }; - return requestChatCompletions(url, header, body, onStream, null, options); + return convertStringToResponseMessages(requestChatCompletions(url, header, body, onStream, null, options)); }; } diff --git a/src/agent/gemini.ts b/src/agent/gemini.ts index 0452e025..b82b5c59 100644 --- a/src/agent/gemini.ts +++ b/src/agent/gemini.ts @@ -1,16 +1,13 @@ import type { AgentUserConfig } from '../config/env'; -import type { ChatAgent, ChatStreamTextHandler, HistoryItem, LLMChatParams } from './types'; +import type { ChatAgent, ChatStreamTextHandler, LLMChatParams, ResponseMessage } from './types'; +import { renderOpenAIMessages } from './openai'; +import { requestChatCompletions } from './request'; +import { convertStringToResponseMessages } from './utils'; export class Gemini implements ChatAgent { readonly name = 'gemini'; readonly modelKey = 'GOOGLE_COMPLETIONS_MODEL'; - static GEMINI_ROLE_MAP: Record = { - assistant: 'model', - system: 'user', - user: 'user', - }; - readonly enable = (context: AgentUserConfig): boolean => { return !!(context.GOOGLE_API_KEY); }; @@ -19,59 +16,19 @@ export class Gemini implements ChatAgent { return ctx.GOOGLE_COMPLETIONS_MODEL; }; - private render = (item: HistoryItem): object => { - return { - role: Gemini.GEMINI_ROLE_MAP[item.role], - parts: [ - { - text: item.content || '', - }, - ], + readonly request = async (params: LLMChatParams, context: AgentUserConfig, onStream: ChatStreamTextHandler | null): Promise => { + const { prompt, messages } = params; + const url = `${context.GOOGLE_API_BASE}/chat`; + const header = { + 'Authorization': `Bearer ${context.GOOGLE_API_KEY}`, + 'Content-Type': 'application/json', + 'Accept': onStream !== null ? 'text/event-stream' : 'application/json', }; - }; - - readonly request = async (params: LLMChatParams, context: AgentUserConfig, onStream: ChatStreamTextHandler | null): Promise => { - const { message, prompt, history } = params; - if (onStream !== null) { - console.warn('Stream mode is not supported'); - } - const mode = 'generateContent'; // onStream ? 'streamGenerateContent' : 'generateContent' - const url = `${context.GOOGLE_COMPLETIONS_API}${context.GOOGLE_COMPLETIONS_MODEL}:${mode}`; - - const contentsTemp = [...history || [], { role: 'user', content: message }]; - if (prompt) { - contentsTemp.unshift({ role: 'assistant', content: prompt }); - } - const contents: any[] = []; - // role必须是 model,user 而且不能连续两个一样 - for (const msg of contentsTemp) { - msg.role = Gemini.GEMINI_ROLE_MAP[msg.role]; - // 如果存在最后一个元素或role不一样则插入 - if (contents.length === 0 || contents[contents.length - 1].role !== msg.role) { - contents.push(this.render(msg)); - } else { - // 否则合并 - contents[contents.length - 1].parts[0].text += msg.content; - } - } - - const resp = await fetch(url, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-goog-api-key': context.GOOGLE_API_KEY, - } as Record, - body: JSON.stringify({ contents }), - }); - const data = await resp.json() as any; - try { - return data.candidates[0].content.parts[0].text; - } catch (e) { - console.error(e); - if (!data) { - throw new Error('Empty response'); - } - throw new Error(data?.error?.message || JSON.stringify(data)); - } + const body = { + messages: await renderOpenAIMessages(prompt, messages), + model: context.GOOGLE_COMPLETIONS_MODEL, + stream: onStream != null, + }; + return convertStringToResponseMessages(requestChatCompletions(url, header, body, onStream)); }; } diff --git a/src/agent/index.test.ts b/src/agent/index.test.ts index ffe7724f..1c82a067 100644 --- a/src/agent/index.test.ts +++ b/src/agent/index.test.ts @@ -10,8 +10,12 @@ import '../config/env.test'; }); const params: LLMChatParams = { prompt: 'You are a useful assistant.', - message: 'What is your name?', - history: [], + messages: [ + { + role: 'user', + content: 'What is your name?', + }, + ], }; console.log(agent?.name, agent?.model(ENV.USER_CONFIG)); agent?.request(params, ENV.USER_CONFIG, async (text) => { diff --git a/src/agent/index.ts b/src/agent/index.ts index ad0f1018..e7773d9d 100644 --- a/src/agent/index.ts +++ b/src/agent/index.ts @@ -52,4 +52,4 @@ export function loadImageGen(context: AgentUserConfig): ImageAgent | null { } } return null; -} +}; diff --git a/src/agent/mistralai.ts b/src/agent/mistralai.ts index 9e5dc8ea..2cc7632b 100644 --- a/src/agent/mistralai.ts +++ b/src/agent/mistralai.ts @@ -1,6 +1,8 @@ import type { AgentUserConfig } from '../config/env'; -import type { ChatAgent, ChatStreamTextHandler, HistoryItem, LLMChatParams } from './types'; +import type { ChatAgent, ChatStreamTextHandler, LLMChatParams, ResponseMessage } from './types'; +import { renderOpenAIMessages } from './openai'; import { requestChatCompletions } from './request'; +import { convertStringToResponseMessages } from './utils'; export class Mistral implements ChatAgent { readonly name = 'mistral'; @@ -14,32 +16,20 @@ export class Mistral implements ChatAgent { return ctx.MISTRAL_CHAT_MODEL; }; - private render = (item: HistoryItem): any => { - return { - role: item.role, - content: item.content, - }; - }; - - readonly request = async (params: LLMChatParams, context: AgentUserConfig, onStream: ChatStreamTextHandler | null): Promise => { - const { message, prompt, history } = params; + readonly request = async (params: LLMChatParams, context: AgentUserConfig, onStream: ChatStreamTextHandler | null): Promise => { + const { prompt, messages } = params; const url = `${context.MISTRAL_API_BASE}/chat/completions`; const header = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${context.MISTRAL_API_KEY}`, }; - const messages = [...(history || []), { role: 'user', content: message }]; - if (prompt) { - messages.unshift({ role: context.SYSTEM_INIT_MESSAGE_ROLE, content: prompt }); - } - const body = { model: context.MISTRAL_CHAT_MODEL, - messages: messages.map(this.render), + messages: await renderOpenAIMessages(prompt, messages), stream: onStream != null, }; - return requestChatCompletions(url, header, body, onStream); + return convertStringToResponseMessages(requestChatCompletions(url, header, body, onStream)); }; } diff --git a/src/agent/openai.ts b/src/agent/openai.ts index 844d997e..5f4fee3c 100644 --- a/src/agent/openai.ts +++ b/src/agent/openai.ts @@ -1,36 +1,50 @@ import type { AgentUserConfig } from '../config/env'; -import type { ChatAgent, ChatStreamTextHandler, HistoryItem, ImageAgent, LLMChatParams } from './types'; -import { ENV } from '../config/env'; -import { imageToBase64String, renderBase64DataURI } from '../utils/image'; +import type { ChatAgent, ChatStreamTextHandler, HistoryItem, ImageAgent, LLMChatParams, ResponseMessage } from './types'; import { requestChatCompletions } from './request'; +import { convertStringToResponseMessages, extractImageContent } from './utils'; -export async function renderOpenAIMessage(item: HistoryItem): Promise { +async function renderOpenAIMessage(item: HistoryItem, supportImage?: boolean): Promise { const res: any = { role: item.role, content: item.content, }; - if (item.images && item.images.length > 0) { - res.content = []; - if (item.content) { - res.content.push({ type: 'text', text: item.content }); - } - for (const image of item.images) { - switch (ENV.TELEGRAM_IMAGE_TRANSFER_MODE) { - case 'base64': - res.content.push({ type: 'image_url', image_url: { - url: renderBase64DataURI(await imageToBase64String(image)), - } }); + if (Array.isArray(item.content)) { + const contents = []; + for (const content of item.content) { + switch (content.type) { + case 'text': + contents.push({ type: 'text', text: content.text }); + break; + case 'image': + if (supportImage) { + const data = extractImageContent(content.image); + if (data.url) { + contents.push({ type: 'image_url', image_url: { url: data.url } }); + } else if (data.base64) { + contents.push({ type: 'image_url', image_url: { url: data.base64 } }); + } + } break; - case 'url': default: - res.content.push({ type: 'image_url', image_url: { url: image } }); break; } } + res.content = contents; } return res; } +export async function renderOpenAIMessages(prompt: string | undefined, items: HistoryItem[], supportImage?: boolean): Promise { + const messages = await Promise.all(items.map(r => renderOpenAIMessage(r, supportImage))); + if (prompt) { + if (messages.length > 0 && messages[0].role === 'system') { + messages.shift(); + } + messages.unshift({ role: 'system', content: prompt }); + } + return messages; +} + class OpenAIBase { readonly name = 'openai'; apikey = (context: AgentUserConfig): string => { @@ -54,27 +68,21 @@ export class OpenAI extends OpenAIBase implements ChatAgent { return renderOpenAIMessage(item); }; - readonly request = async (params: LLMChatParams, context: AgentUserConfig, onStream: ChatStreamTextHandler | null): Promise => { - const { message, images, prompt, history } = params; + readonly request = async (params: LLMChatParams, context: AgentUserConfig, onStream: ChatStreamTextHandler | null): Promise => { + const { prompt, messages } = params; const url = `${context.OPENAI_API_BASE}/chat/completions`; const header = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.apikey(context)}`, }; - - const messages = [...(history || []), { role: 'user', content: message, images }]; - if (prompt) { - messages.unshift({ role: context.SYSTEM_INIT_MESSAGE_ROLE, content: prompt }); - } - const body = { model: context.OPENAI_CHAT_MODEL, ...context.OPENAI_API_EXTRA_PARAMS, - messages: await Promise.all(messages.map(this.render)), + messages: await renderOpenAIMessages(prompt, messages, true), stream: onStream != null, }; - return requestChatCompletions(url, header, body, onStream); + return convertStringToResponseMessages(requestChatCompletions(url, header, body, onStream)); }; } diff --git a/src/agent/types.ts b/src/agent/types.ts index af17145a..724ac7f1 100644 --- a/src/agent/types.ts +++ b/src/agent/types.ts @@ -1,46 +1,41 @@ +import type { CoreAssistantMessage, CoreSystemMessage, CoreToolMessage, CoreUserMessage } from 'ai'; import type { AgentUserConfig } from '../config/env'; -export interface HistoryItem { - role: string; - content?: string | null; - images?: string[] | null; -} +export type ImageContent = string | Uint8Array | ArrayBuffer | Buffer | URL; +export type SystemMessageItem = CoreSystemMessage; +export type UserMessageItem = CoreUserMessage; +export type AssistantMessageItem = CoreAssistantMessage; +export type ToolMessageItem = CoreToolMessage; + +export type HistoryItem = SystemMessageItem | UserMessageItem | AssistantMessageItem | ToolMessageItem; export interface HistoryModifierResult { history: HistoryItem[]; - message: string | null; + message: UserMessageItem; } -export type HistoryModifier = (history: HistoryItem[], message: string | null) => HistoryModifierResult; +export type HistoryModifier = (history: HistoryItem[], message: UserMessageItem | null) => HistoryModifierResult; export type ChatStreamTextHandler = (text: string) => Promise; -export interface LLMChatRequestParams { - message?: string | null; - images?: string[]; +export interface LLMChatParams { + prompt?: string; + messages: HistoryItem[]; } -export interface LLMChatParams extends LLMChatRequestParams { - prompt?: string | null; - history?: HistoryItem[]; -} +export type ResponseMessage = AssistantMessageItem | ToolMessageItem; -export type ChatAgentRequest = (params: LLMChatParams, context: AgentUserConfig, onStream: ChatStreamTextHandler | null) => Promise; +export type ChatAgentRequest = (params: LLMChatParams, context: AgentUserConfig, onStream: ChatStreamTextHandler | null) => Promise; +export type ImageAgentRequest = (prompt: string, context: AgentUserConfig) => Promise; -export interface ChatAgent { +export interface Agent { name: string; modelKey: string; enable: (context: AgentUserConfig) => boolean; - request: ChatAgentRequest; + request: AgentRequest; model: (ctx: AgentUserConfig) => string; } -export type ImageAgentRequest = (prompt: string, context: AgentUserConfig) => Promise; +export type ChatAgent = Agent; -export interface ImageAgent { - name: string; - modelKey: string; - enable: (context: AgentUserConfig) => boolean; - request: ImageAgentRequest; - model: (ctx: AgentUserConfig) => string; -} +export type ImageAgent = Agent; diff --git a/src/agent/utils.ts b/src/agent/utils.ts new file mode 100644 index 00000000..f1a13da8 --- /dev/null +++ b/src/agent/utils.ts @@ -0,0 +1,49 @@ +import type { HistoryItem, ImageContent, ResponseMessage } from './types'; + +export interface ImageRealContent { + url?: string; + base64?: string; +} + +export function extractTextContent(history: HistoryItem): string { + if (typeof history.content === 'string') { + return history.content; + } + if (Array.isArray(history.content)) { + return history.content.map((item) => { + if (item.type === 'text') { + return item.text; + } + return ''; + }).join(''); + } + return ''; +} + +export function extractImageContent(imageData: ImageContent): ImageRealContent { + if (imageData instanceof URL) { + return { url: imageData.href }; + } + // 2. 判断 DataContent 的具体类型 + // 检查是否为字符串(包括 base64) + if (typeof imageData === 'string') { + if (imageData.startsWith('http')) { + return { url: imageData }; + } else { + return { base64: imageData }; + } + } + if (imageData instanceof Uint8Array) { + return { base64: Buffer.from(imageData).toString('base64') }; + } + if (Buffer.isBuffer(imageData)) { + return { base64: Buffer.from(imageData).toString('base64') }; + } + return {}; +} + +export function convertStringToResponseMessages(input: Promise): Promise { + return input.then((res) => { + return [{ role: 'assistant', content: res }]; + }); +} diff --git a/src/agent/workersai.ts b/src/agent/workersai.ts index 07b1522e..6a797f09 100644 --- a/src/agent/workersai.ts +++ b/src/agent/workersai.ts @@ -1,7 +1,9 @@ import type { AgentUserConfig } from '../config/env'; import type { SseChatCompatibleOptions } from './request'; -import type { ChatAgent, ChatStreamTextHandler, HistoryItem, ImageAgent, LLMChatParams } from './types'; +import type { ChatAgent, ChatStreamTextHandler, HistoryItem, ImageAgent, LLMChatParams, ResponseMessage } from './types'; +import { renderOpenAIMessages } from './openai'; import { isJsonResponse, requestChatCompletions } from './request'; +import { convertStringToResponseMessages } from './utils'; class WorkerBase { readonly name = 'workers'; @@ -35,8 +37,8 @@ export class WorkersChat extends WorkerBase implements ChatAgent { }; }; - readonly request = async (params: LLMChatParams, context: AgentUserConfig, onStream: ChatStreamTextHandler | null): Promise => { - const { message, prompt, history } = params; + readonly request = async (params: LLMChatParams, context: AgentUserConfig, onStream: ChatStreamTextHandler | null): Promise => { + const { prompt, messages } = params; const id = context.CLOUDFLARE_ACCOUNT_ID; const token = context.CLOUDFLARE_TOKEN; const model = context.WORKERS_CHAT_MODEL; @@ -44,14 +46,8 @@ export class WorkersChat extends WorkerBase implements ChatAgent { const header = { Authorization: `Bearer ${token}`, }; - - const messages = [...(history || []), { role: 'user', content: message }]; - if (prompt) { - messages.unshift({ role: context.SYSTEM_INIT_MESSAGE_ROLE, content: prompt }); - } - const body = { - messages: messages.map(this.render), + messages: await renderOpenAIMessages(prompt, messages), stream: onStream !== null, }; @@ -65,7 +61,7 @@ export class WorkersChat extends WorkerBase implements ChatAgent { options.errorExtractor = function (data: any) { return data?.errors?.[0]?.message; }; - return requestChatCompletions(url, header, body, onStream, null, options); + return convertStringToResponseMessages(requestChatCompletions(url, header, body, onStream, null, options)); }; } diff --git a/src/config/config.ts b/src/config/config.ts index 041f7d63..3e829b12 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -92,8 +92,8 @@ export class AgentShareConfig { AI_IMAGE_PROVIDER = 'auto'; // 全局默认初始化消息 SYSTEM_INIT_MESSAGE: string | null = null; - // 全局默认初始化消息角色 - SYSTEM_INIT_MESSAGE_ROLE = 'system'; + // DEPRECATED: 全局默认初始化消息角色, 废弃此选项 + // SYSTEM_INIT_MESSAGE_ROLE = 'system'; } // -- Open AI 配置 -- @@ -106,6 +106,8 @@ export class OpenAIConfig { OPENAI_API_BASE = 'https://api.openai.com/v1'; // OpenAI API Extra Params OPENAI_API_EXTRA_PARAMS: Record = {}; + // OpenAI Chat Models List + OPENAI_CHAT_MODELS_LIST = 'https://api.openai.com/v1/models'; } // -- DALLE 配置 -- @@ -130,6 +132,8 @@ export class AzureConfig { // Azure DallE API // https://RESOURCE_NAME.openai.azure.com/openai/deployments/MODEL_NAME/images/generations?api-version=VERSION_NAME AZURE_DALLE_API: string | null = null; + // Azure Chat Models List + AZURE_CHAT_MODELS_LIST = '[]'; } // -- Workers 配置 -- @@ -142,16 +146,20 @@ export class WorkersConfig { WORKERS_CHAT_MODEL = '@cf/mistral/mistral-7b-instruct-v0.1 '; // Text-to-Image Model WORKERS_IMAGE_MODEL = '@cf/stabilityai/stable-diffusion-xl-base-1.0'; + // Workers Chat Models List + WORKERS_CHAT_MODELS_LIST = 'https://api.cloudflare.com/client/v4/accounts/_YOUR_ACCOUNT_ID_/ai/models/search?task=Text%20Generation'; } // -- Gemini 配置 -- export class GeminiConfig { // Google Gemini API Key GOOGLE_API_KEY: string | null = null; - // Google Gemini API: Cloudflare AI gateway: https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_name}/google-ai-studio/v1/models - GOOGLE_COMPLETIONS_API = 'https://generativelanguage.googleapis.com/v1beta/models/'; + // Google Gemini API: https://ai.google.dev/gemini-api/docs/openai#rest + GOOGLE_API_BASE = 'https://generativelanguage.googleapis.com/v1beta'; // Google Gemini Model - GOOGLE_COMPLETIONS_MODEL = 'gemini-pro'; + GOOGLE_COMPLETIONS_MODEL = 'gemini-1.5-flash'; + // Google Chat Models List + GOOGLE_CHAT_MODELS_LIST = `["gemini-1.5-flash"]`; } // -- Mistral 配置 -- @@ -162,6 +170,8 @@ export class MistralConfig { MISTRAL_API_BASE = 'https://api.mistral.ai/v1'; // mistral api model MISTRAL_CHAT_MODEL = 'mistral-tiny'; + // mistral api chat models list + MISTRAL_CHAT_MODELS_LIST = 'https://api.mistral.ai/v1/models'; } // -- Cohere 配置 -- @@ -172,6 +182,8 @@ export class CohereConfig { COHERE_API_BASE = 'https://api.cohere.com/v2'; // cohere api model COHERE_CHAT_MODEL = 'command-r-plus'; + // cohere api chat models list + COHERE_CHAT_MODELS_LIST = 'https://api.cohere.com/v1/models'; } // -- Anthropic 配置 -- @@ -181,7 +193,9 @@ export class AnthropicConfig { // Anthropic api base ANTHROPIC_API_BASE = 'https://api.anthropic.com/v1'; // Anthropic api model - ANTHROPIC_CHAT_MODEL = 'claude-3-haiku-20240307'; + ANTHROPIC_CHAT_MODEL = 'claude-3-5-haiku-latest'; + // Anthropic api chat models list + ANTHROPIC_CHAT_MODELS_LIST = `["claude-3-5-sonnet-latest", "claude-3-5-haiku-latest"]`; } export class DefineKeys { diff --git a/src/config/version.ts b/src/config/version.ts index 4269dd2b..4d1c879a 100644 --- a/src/config/version.ts +++ b/src/config/version.ts @@ -1,2 +1,2 @@ -export const BUILD_TIMESTAMP = 1730790946; -export const BUILD_VERSION = '62b8147'; +export const BUILD_TIMESTAMP = 1731312843; +export const BUILD_VERSION = '08366a5'; diff --git a/src/telegram/command/system.ts b/src/telegram/command/system.ts index facae1d8..f39b11fd 100644 --- a/src/telegram/command/system.ts +++ b/src/telegram/command/system.ts @@ -1,5 +1,5 @@ import type * as Telegram from 'telegram-bot-api-types'; -import type { HistoryItem, HistoryModifierResult } from '../../agent/types'; +import type { HistoryItem, HistoryModifierResult, UserMessageItem } from '../../agent/types'; import type { WorkerContext } from '../../config/context'; import type { CommandHandler } from './types'; import { loadChatLLM, loadImageGen } from '../../agent'; @@ -307,8 +307,8 @@ export class RedoCommandHandler implements CommandHandler { command = '/redo'; scopes = ['all_private_chats', 'all_group_chats', 'all_chat_administrators']; handle = async (message: Telegram.Message, subcommand: string, context: WorkerContext): Promise => { - const mf = (history: HistoryItem[], text: string | null): HistoryModifierResult => { - let nextText = text; + const mf = (history: HistoryItem[], message: UserMessageItem | null): HistoryModifierResult => { + let nextMessage = message; if (!(history && Array.isArray(history) && history.length > 0)) { throw new Error('History not found'); } @@ -318,18 +318,22 @@ export class RedoCommandHandler implements CommandHandler { if (data === undefined || data === null) { break; } else if (data.role === 'user') { - if (text === '' || text === undefined || text === null) { - nextText = data.content || null; - } + nextMessage = data; break; } } if (subcommand) { - nextText = subcommand; + nextMessage = { + role: 'user', + content: subcommand, + }; } - return { history: historyCopy, message: nextText }; + if (nextMessage === null) { + throw new Error('Redo message not found'); + } + return { history: historyCopy, message: nextMessage }; }; - return chatWithLLM(message, { message: null }, context, mf); + return chatWithLLM(message, null, context, mf); }; } diff --git a/src/telegram/handler/chat.ts b/src/telegram/handler/chat.ts index df3703d0..a2422d2b 100644 --- a/src/telegram/handler/chat.ts +++ b/src/telegram/handler/chat.ts @@ -1,6 +1,6 @@ import type * as Telegram from 'telegram-bot-api-types'; import type { StreamResultHandler } from '../../agent/chat'; -import type { HistoryModifier, LLMChatRequestParams } from '../../agent/types'; +import type { HistoryModifier, UserMessageItem } from '../../agent/types'; import type { WorkerContext } from '../../config/context'; import type { MessageHandler } from './types'; import { loadChatLLM } from '../../agent'; @@ -9,7 +9,7 @@ import { ENV } from '../../config/env'; import { createTelegramBotAPI } from '../api'; import { MessageSender } from '../utils/send'; -export async function chatWithLLM(message: Telegram.Message, params: LLMChatRequestParams, context: WorkerContext, modifier: HistoryModifier | null): Promise { +export async function chatWithLLM(message: Telegram.Message, params: UserMessageItem | null, context: WorkerContext, modifier: HistoryModifier | null): Promise { const sender = MessageSender.from(context.SHARE_CONTEXT.botToken, message); try { try { @@ -89,17 +89,24 @@ function findPhotoFileID(photos: Telegram.PhotoSize[], offset: number): string { export class ChatHandler implements MessageHandler { handle = async (message: Telegram.Message, context: WorkerContext): Promise => { - const params: LLMChatRequestParams = { - message: message.text || message.caption || '', + const text = message.text || message.caption || ''; + const params: UserMessageItem = { + role: 'user', + content: text, }; - if (message.photo && message.photo.length > 0) { const id = findPhotoFileID(message.photo, ENV.TELEGRAM_PHOTO_SIZE_OFFSET); const api = createTelegramBotAPI(context.SHARE_CONTEXT.botToken); const file = await api.getFileWithReturns({ file_id: id }); - const url = file.result.file_path; - if (url) { - params.images = [url]; + const filePath = file.result.file_path; + if (filePath) { + const url = URL.parse(`${ENV.TELEGRAM_API_DOMAIN}/file/bot${context.SHARE_CONTEXT.botToken}/${filePath}`); + if (url) { + params.content = [ + { type: 'text', text }, + { type: 'image', image: url }, + ]; + } } } return chatWithLLM(message, params, context, null); diff --git a/tsconfig.json b/tsconfig.json index 08b0be76..7601f249 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,14 +1,16 @@ { "compilerOptions": { "target": "ESNext", + "module": "ESNext", + "moduleResolution": "bundler", + "jsx": "react", "lib": [ "ESNext", - "dom" + "dom", + "dom.iterable" ], "rootDir": ".", - "module": "ESNext", - "moduleResolution": "bundler", - "types": ["node"], + "types": ["node", "react"], "allowJs": true, "strict": true, "declaration": true, @@ -18,4 +20,4 @@ "esModuleInterop": true }, "include": ["src/**/*"] -} +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index fce75f59..1ca68940 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,70 @@ # yarn lockfile v1 +"@ai-sdk/provider-utils@1.0.22": + version "1.0.22" + resolved "https://registry.yarnpkg.com/@ai-sdk/provider-utils/-/provider-utils-1.0.22.tgz#5397a193587709796d012fc04e2df9903b70852f" + integrity sha512-YHK2rpj++wnLVc9vPGzGFP3Pjeld2MwhKinetA0zKXOoHAT/Jit5O8kZsxcSlJPu9wvcGT1UGZEjZrtO7PfFOQ== + dependencies: + "@ai-sdk/provider" "0.0.26" + eventsource-parser "^1.1.2" + nanoid "^3.3.7" + secure-json-parse "^2.7.0" + +"@ai-sdk/provider@0.0.26": + version "0.0.26" + resolved "https://registry.yarnpkg.com/@ai-sdk/provider/-/provider-0.0.26.tgz#52c3d5eb65cf7592c77c78decadf77cbec978934" + integrity sha512-dQkfBDs2lTYpKM8389oopPdQgIU007GQyCbuPPrV+K6MtSII3HBfE0stUIMXUb44L+LK1t6GXPP7wjSzjO6uKg== + dependencies: + json-schema "^0.4.0" + +"@ai-sdk/react@0.0.70": + version "0.0.70" + resolved "https://registry.yarnpkg.com/@ai-sdk/react/-/react-0.0.70.tgz#25dee1755c67da2ac0ed4f207102de93d7196f44" + integrity sha512-GnwbtjW4/4z7MleLiW+TOZC2M29eCg1tOUpuEiYFMmFNZK8mkrqM0PFZMo6UsYeUYMWqEOOcPOU9OQVJMJh7IQ== + dependencies: + "@ai-sdk/provider-utils" "1.0.22" + "@ai-sdk/ui-utils" "0.0.50" + swr "^2.2.5" + throttleit "2.1.0" + +"@ai-sdk/solid@0.0.54": + version "0.0.54" + resolved "https://registry.yarnpkg.com/@ai-sdk/solid/-/solid-0.0.54.tgz#60f2007d511f153159d9e5ddc1e8b800fb472c58" + integrity sha512-96KWTVK+opdFeRubqrgaJXoNiDP89gNxFRWUp0PJOotZW816AbhUf4EnDjBjXTLjXL1n0h8tGSE9sZsRkj9wQQ== + dependencies: + "@ai-sdk/provider-utils" "1.0.22" + "@ai-sdk/ui-utils" "0.0.50" + +"@ai-sdk/svelte@0.0.57": + version "0.0.57" + resolved "https://registry.yarnpkg.com/@ai-sdk/svelte/-/svelte-0.0.57.tgz#82e97db343f2d5f8e50da055e6897e03f03c2ee6" + integrity sha512-SyF9ItIR9ALP9yDNAD+2/5Vl1IT6kchgyDH8xkmhysfJI6WrvJbtO1wdQ0nylvPLcsPoYu+cAlz1krU4lFHcYw== + dependencies: + "@ai-sdk/provider-utils" "1.0.22" + "@ai-sdk/ui-utils" "0.0.50" + sswr "^2.1.0" + +"@ai-sdk/ui-utils@0.0.50": + version "0.0.50" + resolved "https://registry.yarnpkg.com/@ai-sdk/ui-utils/-/ui-utils-0.0.50.tgz#f396d24b5ac1e7a8090684a6d8de47282d0bad96" + integrity sha512-Z5QYJVW+5XpSaJ4jYCCAVG7zIAuKOOdikhgpksneNmKvx61ACFaf98pmOd+xnjahl0pIlc/QIe6O4yVaJ1sEaw== + dependencies: + "@ai-sdk/provider" "0.0.26" + "@ai-sdk/provider-utils" "1.0.22" + json-schema "^0.4.0" + secure-json-parse "^2.7.0" + zod-to-json-schema "^3.23.3" + +"@ai-sdk/vue@0.0.59": + version "0.0.59" + resolved "https://registry.yarnpkg.com/@ai-sdk/vue/-/vue-0.0.59.tgz#29190415a123e631bfe7cf08f6454b73b5585714" + integrity sha512-+ofYlnqdc8c4F6tM0IKF0+7NagZRAiqBJpGDJ+6EYhDW8FHLUP/JFBgu32SjxSxC6IKFZxEnl68ZoP/Z38EMlw== + dependencies: + "@ai-sdk/provider-utils" "1.0.22" + "@ai-sdk/ui-utils" "0.0.50" + swrv "^1.0.4" + "@antfu/eslint-config@^3.6.2": version "3.7.3" resolved "https://registry.yarnpkg.com/@antfu/eslint-config/-/eslint-config-3.7.3.tgz#74c12acd8a7b2480ce07fe91e34472d16af779dd" @@ -792,6 +856,11 @@ mkdirp "^1.0.4" rimraf "^3.0.2" +"@opentelemetry/api@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.9.0.tgz#d03eba68273dc0f7509e2a3d5cba21eae10379fe" + integrity sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg== + "@pkgr/core@^0.1.0": version "0.1.1" resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" @@ -1003,6 +1072,11 @@ dependencies: "@types/ms" "*" +"@types/diff-match-patch@^1.0.36": + version "1.0.36" + resolved "https://registry.yarnpkg.com/@types/diff-match-patch/-/diff-match-patch-1.0.36.tgz#dcef10a69d357fe9d43ac4ff2eca6b85dbf466af" + integrity sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg== + "@types/estree@1.0.6", "@types/estree@^1.0.0", "@types/estree@^1.0.6": version "1.0.6" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" @@ -1025,6 +1099,14 @@ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433" integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== +"@types/node-fetch@^2.6.4": + version "2.6.11" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.11.tgz#9b39b78665dae0e82a08f02f4967d62c66f95d24" + integrity sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g== + dependencies: + "@types/node" "*" + form-data "^4.0.0" + "@types/node-forge@^1.3.0": version "1.3.11" resolved "https://registry.yarnpkg.com/@types/node-forge/-/node-forge-1.3.11.tgz#0972ea538ddb0f4d9c2fa0ec5db5724773a604da" @@ -1044,11 +1126,31 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.11.tgz#cbb15c12ca7c16c85a72b6bdc4d4b01151bb3cae" integrity sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA== +"@types/node@^18.11.18": + version "18.19.64" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.64.tgz#122897fb79f2a9ec9c979bded01c11461b2b1478" + integrity sha512-955mDqvO2vFf/oL7V3WiUtiz+BugyX8uVbaT2H8oj3+8dRyH2FLiNdowe7eNqRM7IOIZvzDH76EoAT+gwm6aIQ== + dependencies: + undici-types "~5.26.4" + "@types/normalize-package-data@^2.4.0": version "2.4.4" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901" integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA== +"@types/prop-types@*": + version "15.7.13" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.13.tgz#2af91918ee12d9d32914feb13f5326658461b451" + integrity sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA== + +"@types/react@^18.3.11": + version "18.3.12" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.12.tgz#99419f182ccd69151813b7ee24b792fe08774f60" + integrity sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw== + dependencies: + "@types/prop-types" "*" + csstype "^3.0.2" + "@types/resolve@1.20.2": version "1.20.2" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975" @@ -1287,6 +1389,13 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + acorn-import-attributes@^1.9.5: version "1.9.5" resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" @@ -1316,7 +1425,7 @@ agent-base@6, agent-base@^6.0.2: dependencies: debug "4" -agentkeepalive@^4.1.3: +agentkeepalive@^4.1.3, agentkeepalive@^4.2.1: version "4.5.0" resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== @@ -1331,6 +1440,25 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" +ai@^3.4.33: + version "3.4.33" + resolved "https://registry.yarnpkg.com/ai/-/ai-3.4.33.tgz#b52ac6a7def6972bb5edaf1867ffc13526b8d51d" + integrity sha512-plBlrVZKwPoRTmM8+D1sJac9Bq8eaa2jiZlHLZIWekKWI1yMWYZvCCEezY9ASPwRhULYDJB2VhKOBUUeg3S5JQ== + dependencies: + "@ai-sdk/provider" "0.0.26" + "@ai-sdk/provider-utils" "1.0.22" + "@ai-sdk/react" "0.0.70" + "@ai-sdk/solid" "0.0.54" + "@ai-sdk/svelte" "0.0.57" + "@ai-sdk/ui-utils" "0.0.50" + "@ai-sdk/vue" "0.0.59" + "@opentelemetry/api" "1.9.0" + eventsource-parser "1.1.2" + json-schema "^0.4.0" + jsondiffpatch "0.6.0" + secure-json-parse "^2.7.0" + zod-to-json-schema "^3.23.3" + ajv-draft-04@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz#3b64761b268ba0b9e668f0b41ba53fce0ad77fc8" @@ -1492,6 +1620,11 @@ async-sema@^3.1.1: resolved "https://registry.yarnpkg.com/async-sema/-/async-sema-3.1.1.tgz#e527c08758a0f8f6f9f15f799a173ff3c40ea808" integrity sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg== +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -1642,6 +1775,11 @@ chalk@^4.0.0, chalk@^4.1.1: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" + integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== + character-entities@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.2.tgz#2d09c2e72cd9523076ccb21157dff66ad43fcc22" @@ -1694,6 +1832,11 @@ clean-stack@^2.0.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== +client-only@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" + integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== + cliui@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" @@ -1753,6 +1896,13 @@ color-support@^1.1.2, color-support@^1.1.3: resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + commander@^8.0.0: version "8.3.0" resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" @@ -1829,6 +1979,11 @@ cssesc@^3.0.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== +csstype@^3.0.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== + data-uri-to-buffer@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz#d296973d5a4897a5dbe31716d118211921f04770" @@ -1894,6 +2049,11 @@ defu@^6.1.4: resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.4.tgz#4e0c9cf9ff68fe5f3d7f2765cc1a012dfdcb0479" integrity sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg== +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" @@ -1921,6 +2081,11 @@ devlop@^1.0.0, devlop@^1.1.0: dependencies: dequal "^2.0.0" +diff-match-patch@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.5.tgz#abb584d5f10cd1196dfc55aa03701592ae3f7b37" + integrity sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw== + diff@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" @@ -2610,6 +2775,16 @@ etag@1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + +eventsource-parser@1.1.2, eventsource-parser@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/eventsource-parser/-/eventsource-parser-1.1.2.tgz#ed6154a4e3dbe7cda9278e5e35d2ffc58b309f89" + integrity sha512-v0eOBUbiaFojBu2s2NPBfYUoRR9GjcDNvCXVaqEf5vVfpIAh9f8RCo4vXTP8c63QRKCFwoLpMpTdPwwhEKVgzA== + exit-hook@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-2.2.1.tgz#007b2d92c6428eda2b76e7016a34351586934593" @@ -2716,6 +2891,28 @@ flatted@^3.2.9: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== +form-data-encoder@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-1.7.2.tgz#1f1ae3dccf58ed4690b86d87e4f57c654fbab040" + integrity sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A== + +form-data@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.1.tgz#ba1076daaaa5bfd7e99c1a6cb02aa0a5cff90d48" + integrity sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +formdata-node@^4.3.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/formdata-node/-/formdata-node-4.4.1.tgz#23f6a5cb9cb55315912cbec4ff7b0f59bbd191e2" + integrity sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ== + dependencies: + node-domexception "1.0.0" + web-streams-polyfill "4.0.0-beta.3" + fs-constants@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" @@ -3090,11 +3287,6 @@ is-path-inside@^3.0.3: resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== -is-unicode-supported@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz#d824984b616c292a2e198207d4a609983842f714" - integrity sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ== - isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -3114,7 +3306,7 @@ js-cleanup@^1.2.0: perf-regexes "^1.0.1" skip-regex "^1.0.2" -js-tokens@^4.0.0: +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== @@ -3174,6 +3366,11 @@ json-schema-traverse@^1.0.0: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== +json-schema@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== + json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" @@ -3189,6 +3386,15 @@ jsonc-eslint-parser@^2.0.4, jsonc-eslint-parser@^2.4.0: espree "^9.0.0" semver "^7.3.5" +jsondiffpatch@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/jsondiffpatch/-/jsondiffpatch-0.6.0.tgz#daa6a25bedf0830974c81545568d5f671c82551f" + integrity sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ== + dependencies: + "@types/diff-match-patch" "^1.0.36" + chalk "^5.3.0" + diff-match-patch "^1.0.5" + jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -3277,6 +3483,13 @@ longest-streak@^3.0.0: resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4" integrity sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g== +loose-envify@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -3745,6 +3958,18 @@ micromatch@^4.0.2, micromatch@^4.0.4: braces "^3.0.3" picomatch "^2.3.1" +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + mime@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" @@ -3945,6 +4170,11 @@ node-addon-api@^7.0.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558" integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ== +node-domexception@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" + integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== + node-fetch@2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6" @@ -4063,6 +4293,19 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" +openai@^4.68.1: + version "4.71.1" + resolved "https://registry.yarnpkg.com/openai/-/openai-4.71.1.tgz#f26bf5db00d75703676d80bf0ae7cb7674e41eac" + integrity sha512-C6JNMaQ1eijM0lrjiRUL3MgThVP5RdwNAghpbJFdW0t11LzmyqON8Eh8MuUuEZ+CeD6bgYl2Fkn2BoptVxv9Ug== + dependencies: + "@types/node" "^18.11.18" + "@types/node-fetch" "^2.6.4" + abort-controller "^3.0.0" + agentkeepalive "^4.2.1" + form-data-encoder "1.7.2" + formdata-node "^4.3.2" + node-fetch "^2.6.7" + optionator@^0.9.3: version "0.9.4" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" @@ -4339,6 +4582,14 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-dom@^18.3.1: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" + integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== + dependencies: + loose-envify "^1.1.0" + scheduler "^0.23.2" + read-pkg-up@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" @@ -4547,6 +4798,13 @@ safe-buffer@^5.0.1, safe-buffer@~5.2.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +scheduler@^0.23.2: + version "0.23.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" + integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== + dependencies: + loose-envify "^1.1.0" + scslre@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/scslre/-/scslre-0.3.0.tgz#c3211e9bfc5547fc86b1eabaa34ed1a657060155" @@ -4556,6 +4814,11 @@ scslre@^0.3.0: refa "^0.12.0" regexp-ast-analysis "^0.7.0" +secure-json-parse@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-2.7.0.tgz#5a5f9cd6ae47df23dba3151edd06855d47e09862" + integrity sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw== + selfsigned@^2.0.1: version "2.4.1" resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.4.1.tgz#560d90565442a3ed35b674034cec4e95dceb4ae0" @@ -4742,6 +5005,13 @@ ssri@^8.0.0, ssri@^8.0.1: dependencies: minipass "^3.1.1" +sswr@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/sswr/-/sswr-2.1.0.tgz#1eb64cd647cc9e11f871e7f43554abd8c64e1103" + integrity sha512-Cqc355SYlTAaUt8iDPaC/4DPPXK925PePLMxyBKuWd5kKc5mwsG3nT9+Mq2tyguL5s7b4Jg+IRMpTRsNTAfpSQ== + dependencies: + swrev "^4.0.0" + stable-hash@^0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/stable-hash/-/stable-hash-0.0.4.tgz#55ae7dadc13e4b3faed13601587cec41859b42f7" @@ -4836,6 +5106,24 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +swr@^2.2.5: + version "2.2.5" + resolved "https://registry.yarnpkg.com/swr/-/swr-2.2.5.tgz#063eea0e9939f947227d5ca760cc53696f46446b" + integrity sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg== + dependencies: + client-only "^0.0.1" + use-sync-external-store "^1.2.0" + +swrev@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/swrev/-/swrev-4.0.0.tgz#83da6983c7ef9d71ac984a9b169fc197cbf18ff8" + integrity sha512-LqVcOHSB4cPGgitD1riJ1Hh4vdmITOp+BkmfmXRh4hSF/t7EnS4iD+SOTmq7w5pPm/SiPeto4ADbKS6dHUDWFA== + +swrv@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/swrv/-/swrv-1.0.4.tgz#278b4811ed4acbb1ae46654972a482fd1847e480" + integrity sha512-zjEkcP8Ywmj+xOJW3lIT65ciY/4AL4e/Or7Gj0MzU3zBJNMdJiT8geVZhINavnlHRMMCcJLHhraLTAiDOTmQ9g== + synckit@^0.6.0: version "0.6.2" resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.6.2.tgz#e1540b97825f2855f7170b98276e8463167f33eb" @@ -4899,6 +5187,11 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +throttleit@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-2.1.0.tgz#a7e4aa0bf4845a5bd10daa39ea0c783f631a07b4" + integrity sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw== + time-span@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/time-span/-/time-span-4.0.0.tgz#fe74cd50a54e7998712f90ddfe47109040c985c4" @@ -5051,6 +5344,11 @@ ufo@^1.5.3, ufo@^1.5.4: resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.5.4.tgz#16d6949674ca0c9e0fbbae1fa20a71d7b1ded754" integrity sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ== +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + undici-types@~6.19.2: version "6.19.8" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" @@ -5148,6 +5446,11 @@ uri-js@^4.2.2, uri-js@^4.4.1: dependencies: punycode "^2.1.0" +use-sync-external-store@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz#c3b6390f3a30eba13200d2302dcdf1e7b57b2ef9" + integrity sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw== + util-deprecate@^1.0.1, util-deprecate@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -5269,6 +5572,11 @@ vue-eslint-parser@^9.4.3: lodash "^4.17.21" semver "^7.3.6" +web-streams-polyfill@4.0.0-beta.3: + version "4.0.0-beta.3" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz#2898486b74f5156095e473efe989dcf185047a38" + integrity sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug== + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" @@ -5427,6 +5735,11 @@ youch@^3.2.2: mustache "^4.2.0" stacktracey "^2.1.8" +zod-to-json-schema@^3.23.3: + version "3.23.5" + resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.23.5.tgz#ec23def47dcafe3a4d640eba6a346b34f9a693a5" + integrity sha512-5wlSS0bXfF/BrL4jPAbz9da5hDlDptdEppYfe+x4eIJ7jioqKG9uUxOwPzqof09u/XeVdrgFu29lZi+8XNDJtA== + zod@^3.22.3: version "3.23.8" resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d"