ai-world-sdk 1.0.16 → 1.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,6 +11,7 @@ TypeScript SDK for AI World Platform - 一个功能完整的 AI 应用开发 SDK
11
11
  - 🎨 **图像生成**: 支持豆包 Seedream 和 Google Gemini
12
12
  - 🎬 **视频生成**: 支持豆包 Seedance
13
13
  - 📥 **下载代理**: 支持流式下载和普通下载任意 URL 的二进制文件
14
+ - 🔐 **用户认证**: 支持获取当前登录用户信息
14
15
  - ⚙️ **全局配置**: 自动从浏览器环境获取配置,简化初始化
15
16
  - 🐛 **调试模式**: 支持详细的请求/响应日志
16
17
 
@@ -47,6 +48,8 @@ const geminiModel = new ChatGoogleGenerativeAI({
47
48
  modelName: 'gemini-2.5-flash-image',
48
49
  temperature: 0.7,
49
50
  provider: 'gemini', // 或 'aihubmix', 'api2img'
51
+ vertexai: false, // 可选:是否使用 VertexAI(仅当 provider 为 gemini 时有效)
52
+ jsonSchema: undefined, // 可选:结构化输出 JSON Schema
50
53
  });
51
54
 
52
55
  // GPT 模型(使用 aihubmix provider)
@@ -54,6 +57,7 @@ const gptModel = new ChatOpenAI({
54
57
  modelName: 'gpt-4o-mini',
55
58
  temperature: 0.7,
56
59
  provider: 'aihubmix', // 或 'api2img'
60
+ jsonSchema: undefined, // 可选:结构化输出 JSON Schema
57
61
  });
58
62
 
59
63
  // Claude 模型(使用 aihubmix provider)
@@ -132,7 +136,29 @@ if (result.status === 'succeeded') {
132
136
  }
133
137
  ```
134
138
 
135
- ### 5. 下载代理
139
+ ### 5. 用户认证
140
+
141
+ ```typescript
142
+ import { getCurrentUserInfo, AuthClient } from 'ai-world-sdk';
143
+
144
+ // 方式1: 使用便捷函数(推荐)
145
+ const userInfo = await getCurrentUserInfo();
146
+ console.log('用户信息:', userInfo);
147
+ console.log('用户ID:', userInfo.id);
148
+ console.log('用户名:', userInfo.full_name);
149
+ console.log('邮箱:', userInfo.email);
150
+
151
+ // 方式2: 使用 AuthClient 类
152
+ const authClient = new AuthClient({
153
+ baseUrl: 'http://localhost:8000', // 可选,默认使用全局配置
154
+ token: 'your-token', // 可选,默认使用全局配置
155
+ });
156
+
157
+ const userInfo2 = await authClient.getCurrentUserInfo();
158
+ console.log('用户信息:', userInfo2);
159
+ ```
160
+
161
+ ### 6. 下载代理
136
162
 
137
163
  ```typescript
138
164
  import { DownloadClient } from 'ai-world-sdk';
@@ -224,6 +250,9 @@ const model = createChatModel('gemini-2.5-flash-image', {
224
250
  - `provider: 'gemini'` - 直接使用 Google Gemini API
225
251
  - `provider: 'doubao'` - 使用豆包服务
226
252
 
253
+ **结构化输出参数:**
254
+ - `jsonSchema?: Record<string, any>` - JSON Schema 定义,用于结构化输出(使用 `with_structured_output`)
255
+
227
256
  ### 图像生成
228
257
 
229
258
  #### DoubaoImageGenerationClient
@@ -694,6 +723,101 @@ const response2 = await model.invoke([
694
723
  ]);
695
724
  ```
696
725
 
726
+ ### 结构化输出(JSON Schema)
727
+
728
+ 使用 `jsonSchema` 参数可以让模型返回结构化的 JSON 数据,而不是自由文本。
729
+
730
+ ```typescript
731
+ import { ChatOpenAI, ChatGoogleGenerativeAI, HumanMessage, createChatModel } from 'ai-world-sdk';
732
+
733
+ // 使用 ChatOpenAI 进行结构化输出
734
+ const openaiModel = new ChatOpenAI({
735
+ modelName: 'gpt-4o-mini',
736
+ temperature: 0.7,
737
+ provider: 'aihubmix',
738
+ jsonSchema: {
739
+ type: 'object',
740
+ properties: {
741
+ name: { type: 'string', description: '用户姓名' },
742
+ age: { type: 'integer', description: '用户年龄' },
743
+ email: { type: 'string', description: '用户邮箱' },
744
+ },
745
+ required: ['name', 'age'],
746
+ },
747
+ });
748
+
749
+ const response = await openaiModel.invoke([
750
+ new HumanMessage('请提取以下信息:张三,25岁,邮箱是zhangsan@example.com'),
751
+ ]);
752
+
753
+ // 响应内容将是结构化的 JSON 对象
754
+ console.log(response.content); // { name: '张三', age: 25, email: 'zhangsan@example.com' }
755
+ ```
756
+
757
+ **使用 Gemini 模型的结构化输出:**
758
+
759
+ ```typescript
760
+ const geminiModel = new ChatGoogleGenerativeAI({
761
+ modelName: 'gemini-2.5-flash',
762
+ temperature: 0.7,
763
+ provider: 'gemini',
764
+ jsonSchema: {
765
+ type: 'object',
766
+ properties: {
767
+ summary: { type: 'string', description: '摘要' },
768
+ keywords: {
769
+ type: 'array',
770
+ items: { type: 'string' },
771
+ description: '关键词列表',
772
+ },
773
+ sentiment: {
774
+ type: 'string',
775
+ enum: ['positive', 'neutral', 'negative'],
776
+ description: '情感倾向',
777
+ },
778
+ },
779
+ required: ['summary', 'keywords'],
780
+ },
781
+ });
782
+
783
+ const response = await geminiModel.invoke([
784
+ new HumanMessage("分析这句话的情感:'今天天气真好,心情很愉快!'"),
785
+ ]);
786
+ ```
787
+
788
+ **使用 createChatModel 工厂函数:**
789
+
790
+ ```typescript
791
+ const model = createChatModel('gpt-4o-mini', {
792
+ temperature: 0.7,
793
+ provider: 'aihubmix',
794
+ jsonSchema: {
795
+ type: 'object',
796
+ properties: {
797
+ title: { type: 'string', description: '文章标题' },
798
+ content: { type: 'string', description: '文章内容' },
799
+ tags: {
800
+ type: 'array',
801
+ items: { type: 'string' },
802
+ description: '标签列表',
803
+ },
804
+ },
805
+ required: ['title', 'content'],
806
+ },
807
+ });
808
+
809
+ const response = await model.invoke([
810
+ new HumanMessage('生成一篇关于人工智能的短文,包含标题、内容和标签'),
811
+ ]);
812
+ ```
813
+
814
+ **注意事项:**
815
+ - `jsonSchema` 必须符合 [JSON Schema](https://json-schema.org/) 规范
816
+ - 对于 OpenAI 兼容的模型(如 GPT、Doubao),JSON Schema 会自动添加 `title` 和 `description`(如果缺失)
817
+ - 对于 Gemini 和 Anthropic 模型,直接使用提供的 JSON Schema
818
+ - 结构化输出的响应内容可能是 JSON 字符串或对象,需要根据实际情况解析
819
+ - 结构化输出使用 LangChain 的 `with_structured_output` 方法,底层通过 `method="json_schema"` 实现
820
+
697
821
  ### 流式响应
698
822
 
699
823
  ```typescript
@@ -897,6 +1021,47 @@ const result4 = await client.generate({
897
1021
  console.log('4K 图像:', result4.data[0]?.b64_json ? 'Base64 编码' : result4.data[0]?.url);
898
1022
  ```
899
1023
 
1024
+ ### 用户认证工作流
1025
+
1026
+ ```typescript
1027
+ import { getCurrentUserInfo, AuthClient } from 'ai-world-sdk';
1028
+
1029
+ // 1. 获取当前用户信息(使用便捷函数)
1030
+ try {
1031
+ const userInfo = await getCurrentUserInfo();
1032
+ console.log('用户ID:', userInfo.id);
1033
+ console.log('用户名:', userInfo.full_name);
1034
+ console.log('邮箱:', userInfo.email);
1035
+ console.log('是否超级用户:', userInfo.is_superuser);
1036
+ } catch (error) {
1037
+ console.error('获取用户信息失败:', error);
1038
+ // 可能需要重新登录
1039
+ }
1040
+
1041
+ // 2. 使用 AuthClient 类(需要自定义配置时)
1042
+ const authClient = new AuthClient({
1043
+ baseUrl: 'http://localhost:8000',
1044
+ token: 'your-jwt-token',
1045
+ });
1046
+
1047
+ const userInfo = await authClient.getCurrentUserInfo();
1048
+
1049
+ // 3. 检查用户权限
1050
+ if (userInfo.is_superuser) {
1051
+ console.log('用户是超级管理员');
1052
+ }
1053
+
1054
+ if (userInfo.is_active) {
1055
+ console.log('用户账户已激活');
1056
+ }
1057
+
1058
+ // 4. 显示用户信息
1059
+ console.log(`欢迎, ${userInfo.full_name || userInfo.email || '用户'}`);
1060
+ if (userInfo.avatar_url) {
1061
+ console.log('头像:', userInfo.avatar_url);
1062
+ }
1063
+ ```
1064
+
900
1065
  ### 视频生成工作流
901
1066
 
902
1067
  ```typescript
@@ -928,6 +1093,47 @@ if (result.status === 'succeeded') {
928
1093
  }
929
1094
  ```
930
1095
 
1096
+ ### 用户认证工作流
1097
+
1098
+ ```typescript
1099
+ import { getCurrentUserInfo, AuthClient } from 'ai-world-sdk';
1100
+
1101
+ // 1. 获取当前用户信息(使用便捷函数)
1102
+ try {
1103
+ const userInfo = await getCurrentUserInfo();
1104
+ console.log('用户ID:', userInfo.id);
1105
+ console.log('用户名:', userInfo.full_name);
1106
+ console.log('邮箱:', userInfo.email);
1107
+ console.log('是否超级用户:', userInfo.is_superuser);
1108
+ } catch (error) {
1109
+ console.error('获取用户信息失败:', error);
1110
+ // 可能需要重新登录
1111
+ }
1112
+
1113
+ // 2. 使用 AuthClient 类(需要自定义配置时)
1114
+ const authClient = new AuthClient({
1115
+ baseUrl: 'http://localhost:8000',
1116
+ token: 'your-jwt-token',
1117
+ });
1118
+
1119
+ const userInfo = await authClient.getCurrentUserInfo();
1120
+
1121
+ // 3. 检查用户权限
1122
+ if (userInfo.is_superuser) {
1123
+ console.log('用户是超级管理员');
1124
+ }
1125
+
1126
+ if (userInfo.is_active) {
1127
+ console.log('用户账户已激活');
1128
+ }
1129
+
1130
+ // 4. 显示用户信息
1131
+ console.log(`欢迎, ${userInfo.full_name || userInfo.email || '用户'}`);
1132
+ if (userInfo.avatar_url) {
1133
+ console.log('头像:', userInfo.avatar_url);
1134
+ }
1135
+ ```
1136
+
931
1137
  ### 下载代理工作流
932
1138
 
933
1139
  ```typescript
@@ -39,10 +39,12 @@ var __importStar = (this && this.__importStar) || (function () {
39
39
  Object.defineProperty(exports, "__esModule", { value: true });
40
40
  const dotenv = __importStar(require("dotenv"));
41
41
  const index_1 = require("../index");
42
+ const fs_1 = require("fs");
42
43
  // Load environment variables from .env file
43
44
  dotenv.config();
44
45
  index_1.sdkConfig.setBaseUrl("http://localhost:8000");
45
46
  index_1.sdkConfig.setToken(process.env.AUTH_TOKEN || process.env.TOKEN || "");
47
+ // sdkConfig.setDebug(true);
46
48
  function extractTextFromChunk(chunk) {
47
49
  if (typeof chunk.content === "string") {
48
50
  return chunk.content;
@@ -610,33 +612,18 @@ describe("Langchain SDK Tests", () => {
610
612
  }, 120000);
611
613
  test("GeminiImageGenerationClient - 多图输入图像生成", async () => {
612
614
  const imageClient = new index_1.GeminiImageGenerationClient({});
613
- // 先生成两张基础图片
614
- const baseResult1 = await imageClient.generate({
615
- prompt: 'A professional headshot of a woman with brown hair and blue eyes',
616
- model: 'gemini-2.5-flash-image',
617
- aspect_ratio: '1:1',
618
- response_modalities: ['IMAGE'],
619
- });
620
- const baseResult2 = await imageClient.generate({
621
- prompt: 'A simple, modern logo with the letters G and A in a white circle',
622
- model: 'gemini-2.5-flash-image',
623
- aspect_ratio: '1:1',
624
- response_modalities: ['IMAGE'],
625
- });
626
- expect(baseResult1.data.length).toBeGreaterThan(0);
627
- expect(baseResult2.data.length).toBeGreaterThan(0);
628
- const image1 = baseResult1.data[0]?.b64_json || baseResult1.data[0]?.url;
629
- const image2 = baseResult2.data[0]?.b64_json || baseResult2.data[0]?.url;
630
- expect(image1).toBeDefined();
631
- expect(image2).toBeDefined();
632
- // 使用多张图片作为输入(gemini-2.5-flash-image 最多支持 3 张)
615
+ const image1 = "data:image/png;base64,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";
616
+ const image2 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAJCAIAAACAMfp5AAAACXBIWXMAAAsTAAALEwEAmpwYAAAFgmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4xLWMwMDIgNzkuZGJhM2RhM2I1LCAyMDIzLzEyLzE1LTEwOjQyOjM3ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyIgeG1sbnM6ZXhpZj0iaHR0cDovL25zLmFkb2JlLmNvbS9leGlmLzEuMC8iIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIiB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIiB0aWZmOk9yaWVudGF0aW9uPSIxIiBleGlmOkNvbG9yU3BhY2U9IjEiIGV4aWY6UGl4ZWxYRGltZW5zaW9uPSI4IiBleGlmOlBpeGVsWURpbWVuc2lvbj0iOSIgeG1wOkNyZWF0ZURhdGU9IjIwMjUtMTItMTlUMTI6MDY6MDMrMDg6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI1LTEyLTE5VDEyOjA2OjM1KzA4OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI1LTEyLTE5VDEyOjA2OjM1KzA4OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo5Y2IwNmRjYi04MmI0LTQ3ODctYmQ1Ny1lYWI5MzE5MzkyYzUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OWNiMDZkY2ItODJiNC00Nzg3LWJkNTctZWFiOTMxOTM5MmM1IiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6OWNiMDZkY2ItODJiNC00Nzg3LWJkNTctZWFiOTMxOTM5MmM1Ij4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6OWNiMDZkY2ItODJiNC00Nzg3LWJkNTctZWFiOTMxOTM5MmM1IiBzdEV2dDp3aGVuPSIyMDI1LTEyLTE5VDEyOjA2OjM1KzA4OjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgMjUuNiAoTWFjaW50b3NoKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6KNh+8AAAAEElEQVQIHWNgYPiPAw0PCQA/Vke5jW7wRQAAAABJRU5ErkJggg==";
617
+ const image3 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAJCAIAAACAMfp5AAAACXBIWXMAAAsTAAALEwEAmpwYAAAGUWlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4xLWMwMDIgNzkuZGJhM2RhM2I1LCAyMDIzLzEyLzE1LTEwOjQyOjM3ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIiB4bXA6Q3JlYXRlRGF0ZT0iMjAyNS0xMi0xOVQxMjowNjowMyswODowMCIgeG1wOk1vZGlmeURhdGU9IjIwMjUtMTItMTlUMTI6MDY6NTUrMDg6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMjUtMTItMTlUMTI6MDY6NTUrMDg6MDAiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjkxMDMwZWU4LWVmNDQtNDE3My1iNjI4LTRiZTAzODg0YTkxNiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo5Y2IwNmRjYi04MmI0LTQ3ODctYmQ1Ny1lYWI5MzE5MzkyYzUiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo5Y2IwNmRjYi04MmI0LTQ3ODctYmQ1Ny1lYWI5MzE5MzkyYzUiIHRpZmY6T3JpZW50YXRpb249IjEiIGV4aWY6Q29sb3JTcGFjZT0iMSIgZXhpZjpQaXhlbFhEaW1lbnNpb249IjgiIGV4aWY6UGl4ZWxZRGltZW5zaW9uPSI5Ij4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6OWNiMDZkY2ItODJiNC00Nzg3LWJkNTctZWFiOTMxOTM5MmM1IiBzdEV2dDp3aGVuPSIyMDI1LTEyLTE5VDEyOjA2OjM1KzA4OjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgMjUuNiAoTWFjaW50b3NoKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6OTEwMzBlZTgtZWY0NC00MTczLWI2MjgtNGJlMDM4ODRhOTE2IiBzdEV2dDp3aGVuPSIyMDI1LTEyLTE5VDEyOjA2OjU1KzA4OjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgMjUuNiAoTWFjaW50b3NoKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6l1N8jAAAAEElEQVQIHWP8z4AdMA4TCQBdJgkB37cJ2wAAAABJRU5ErkJggg==";
618
+ // 使用多张图片作为输入
633
619
  const result = await imageClient.generate({
634
- prompt: 'Take the first image of the woman and add the logo from the second image onto her black t-shirt',
635
- image: [image1, image2],
636
- model: 'gemini-2.5-flash-image',
620
+ prompt: '将图1上半部分换成图3颜色,下半部分换成图2颜色',
621
+ image: [image1, image2, image3],
622
+ model: 'gemini-3-pro-image-preview',
637
623
  aspect_ratio: '1:1',
638
624
  response_modalities: ['IMAGE'],
639
625
  });
626
+ (0, fs_1.writeFileSync)(__dirname + "/test_1.json", JSON.stringify(result.data));
640
627
  expect(result).toBeDefined();
641
628
  expect(result.data).toBeDefined();
642
629
  expect(result.data.length).toBeGreaterThan(0);
@@ -648,10 +635,10 @@ describe("Langchain SDK Tests", () => {
648
635
  });
649
636
  const result = await imageClient.generate({
650
637
  prompt: 'A beautiful sunset over the ocean',
651
- model: 'gemini-3-pro-image-preview',
638
+ model: 'gemini-2.5-flash-image',
652
639
  aspect_ratio: '16:9',
653
640
  image_size: '1K',
654
- response_modalities: ['IMAGE'], // 仅返回图片
641
+ response_modalities: ['IMAGE', 'TEXT'],
655
642
  });
656
643
  expect(result).toBeDefined();
657
644
  expect(result.created).toBeDefined();
@@ -713,7 +700,7 @@ describe("Langchain SDK Tests", () => {
713
700
  model: 'gemini-3-pro-image-preview',
714
701
  aspect_ratio: '16:9',
715
702
  image_size: '1K',
716
- response_modalities: ['IMAGE'], // 仅返回图片
703
+ response_modalities: ['IMAGE', 'TEXT'], // 仅返回图片
717
704
  });
718
705
  expect(result).toBeDefined();
719
706
  expect(result.created).toBeDefined();
@@ -1010,4 +997,160 @@ describe("Langchain SDK Tests", () => {
1010
997
  }).toThrow("Unsupported model");
1011
998
  console.log("✅ createChatModel 错误处理测试成功");
1012
999
  });
1000
+ test("ChatOpenAI - 结构化输出测试", async () => {
1001
+ const openai = new index_1.ChatOpenAI({
1002
+ modelName: "gpt-5.1",
1003
+ temperature: 0.7,
1004
+ provider: "aihubmix",
1005
+ jsonSchema: {
1006
+ type: "object",
1007
+ properties: {
1008
+ name: { type: "string", description: "用户姓名" },
1009
+ age: { type: "integer", description: "用户年龄" },
1010
+ email: { type: "string", description: "用户邮箱" },
1011
+ },
1012
+ required: ["name", "age"],
1013
+ },
1014
+ });
1015
+ const response = await openai.invoke([
1016
+ new index_1.HumanMessage("请提取以下信息:张三,25岁,邮箱是zhangsan@example.com"),
1017
+ ]);
1018
+ expect(response).toBeDefined();
1019
+ expect(response.content).toBeDefined();
1020
+ // 结构化输出应该返回一个对象
1021
+ const content = response.content;
1022
+ if (typeof content === "string") {
1023
+ // 如果是字符串,尝试解析为 JSON
1024
+ try {
1025
+ const parsed = JSON.parse(content);
1026
+ expect(parsed).toHaveProperty("name");
1027
+ expect(parsed).toHaveProperty("age");
1028
+ expect(typeof parsed.name).toBe("string");
1029
+ expect(typeof parsed.age).toBe("number");
1030
+ console.log("✅ ChatOpenAI 结构化输出测试成功(字符串格式)");
1031
+ console.log("结构化数据:", parsed);
1032
+ }
1033
+ catch (e) {
1034
+ // 如果不是 JSON,至少验证有内容
1035
+ expect(content.length).toBeGreaterThan(0);
1036
+ console.log("✅ ChatOpenAI 结构化输出测试成功(文本格式)");
1037
+ console.log("响应内容:", content);
1038
+ }
1039
+ }
1040
+ else if (typeof content === "object") {
1041
+ // 如果直接是对象
1042
+ expect(content).toHaveProperty("name");
1043
+ expect(content).toHaveProperty("age");
1044
+ console.log("✅ ChatOpenAI 结构化输出测试成功(对象格式)");
1045
+ console.log("结构化数据:", content);
1046
+ }
1047
+ else {
1048
+ console.log("✅ ChatOpenAI 结构化输出测试成功(其他格式)");
1049
+ console.log("响应内容:", content);
1050
+ }
1051
+ }, 30000);
1052
+ test("ChatGoogleGenerativeAI - 结构化输出测试", async () => {
1053
+ const gemini = new index_1.ChatGoogleGenerativeAI({
1054
+ modelName: "gemini-2.5-flash",
1055
+ temperature: 0.7,
1056
+ provider: "gemini",
1057
+ jsonSchema: {
1058
+ type: "object",
1059
+ properties: {
1060
+ summary: { type: "string", description: "摘要" },
1061
+ keywords: {
1062
+ type: "array",
1063
+ items: { type: "string" },
1064
+ description: "关键词列表",
1065
+ },
1066
+ sentiment: {
1067
+ type: "string",
1068
+ enum: ["positive", "neutral", "negative"],
1069
+ description: "情感倾向",
1070
+ },
1071
+ },
1072
+ required: ["summary", "keywords"],
1073
+ },
1074
+ });
1075
+ const response = await gemini.invoke([
1076
+ new index_1.HumanMessage("分析这句话的情感:'今天天气真好,心情很愉快!'"),
1077
+ ]);
1078
+ expect(response).toBeDefined();
1079
+ expect(response.content).toBeDefined();
1080
+ const content = response.content;
1081
+ if (typeof content === "string") {
1082
+ try {
1083
+ const parsed = JSON.parse(content);
1084
+ expect(parsed).toHaveProperty("summary");
1085
+ expect(parsed).toHaveProperty("keywords");
1086
+ expect(Array.isArray(parsed.keywords)).toBe(true);
1087
+ console.log("✅ ChatGoogleGenerativeAI 结构化输出测试成功(字符串格式)");
1088
+ console.log("结构化数据:", parsed);
1089
+ }
1090
+ catch (e) {
1091
+ expect(content.length).toBeGreaterThan(0);
1092
+ console.log("✅ ChatGoogleGenerativeAI 结构化输出测试成功(文本格式)");
1093
+ console.log("响应内容:", content);
1094
+ }
1095
+ }
1096
+ else if (typeof content === "object") {
1097
+ expect(content).toHaveProperty("summary");
1098
+ expect(content).toHaveProperty("keywords");
1099
+ console.log("✅ ChatGoogleGenerativeAI 结构化输出测试成功(对象格式)");
1100
+ console.log("结构化数据:", content);
1101
+ }
1102
+ else {
1103
+ console.log("✅ ChatGoogleGenerativeAI 结构化输出测试成功(其他格式)");
1104
+ console.log("响应内容:", content);
1105
+ }
1106
+ }, 30000);
1107
+ test("createChatModel - 结构化输出测试", async () => {
1108
+ const model = (0, index_1.createChatModel)("gpt-5.1", {
1109
+ temperature: 0.7,
1110
+ provider: "aihubmix",
1111
+ jsonSchema: {
1112
+ type: "object",
1113
+ properties: {
1114
+ title: { type: "string", description: "文章标题" },
1115
+ content: { type: "string", description: "文章内容" },
1116
+ tags: {
1117
+ type: "array",
1118
+ items: { type: "string" },
1119
+ description: "标签列表",
1120
+ },
1121
+ },
1122
+ required: ["title", "content"],
1123
+ },
1124
+ });
1125
+ const response = await model.invoke([
1126
+ new index_1.HumanMessage("生成一篇关于人工智能的短文,包含标题、内容和标签"),
1127
+ ]);
1128
+ expect(response).toBeDefined();
1129
+ expect(response.content).toBeDefined();
1130
+ const content = response.content;
1131
+ if (typeof content === "string") {
1132
+ try {
1133
+ const parsed = JSON.parse(content);
1134
+ expect(parsed).toHaveProperty("title");
1135
+ expect(parsed).toHaveProperty("content");
1136
+ console.log("✅ createChatModel 结构化输出测试成功(字符串格式)");
1137
+ console.log("结构化数据:", parsed);
1138
+ }
1139
+ catch (e) {
1140
+ expect(content.length).toBeGreaterThan(0);
1141
+ console.log("✅ createChatModel 结构化输出测试成功(文本格式)");
1142
+ console.log("响应内容:", content);
1143
+ }
1144
+ }
1145
+ else if (typeof content === "object") {
1146
+ expect(content).toHaveProperty("title");
1147
+ expect(content).toHaveProperty("content");
1148
+ console.log("✅ createChatModel 结构化输出测试成功(对象格式)");
1149
+ console.log("结构化数据:", content);
1150
+ }
1151
+ else {
1152
+ console.log("✅ createChatModel 结构化输出测试成功(其他格式)");
1153
+ console.log("响应内容:", content);
1154
+ }
1155
+ }, 30000);
1013
1156
  });
package/dist/auth.d.ts ADDED
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Auth Client
3
+ * 认证客户端
4
+ * 提供用户认证相关的 API
5
+ */
6
+ export interface AuthConfig {
7
+ baseUrl?: string;
8
+ token?: string;
9
+ headers?: Record<string, string>;
10
+ }
11
+ /**
12
+ * User information interface
13
+ * 用户信息接口
14
+ */
15
+ export interface UserInfo {
16
+ id: number;
17
+ email?: string;
18
+ full_name?: string;
19
+ avatar_url?: string;
20
+ feishu_user_id: string;
21
+ is_active: boolean;
22
+ is_superuser: boolean;
23
+ created_at: string;
24
+ }
25
+ /**
26
+ * Auth Client
27
+ * 认证客户端类
28
+ */
29
+ export declare class AuthClient {
30
+ private baseUrl;
31
+ private headers;
32
+ constructor(config?: AuthConfig);
33
+ /**
34
+ * Get current user information
35
+ * 获取当前用户信息
36
+ *
37
+ * @returns Promise that resolves to UserInfo
38
+ */
39
+ getCurrentUserInfo(): Promise<UserInfo>;
40
+ }
41
+ /**
42
+ * Get current user information (convenience function)
43
+ * 获取当前用户信息(便捷函数)
44
+ *
45
+ * @param config - Optional auth configuration
46
+ * @returns Promise that resolves to UserInfo
47
+ */
48
+ export declare function getCurrentUserInfo(config?: AuthConfig): Promise<UserInfo>;
package/dist/auth.js ADDED
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ /**
3
+ * Auth Client
4
+ * 认证客户端
5
+ * 提供用户认证相关的 API
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.AuthClient = void 0;
9
+ exports.getCurrentUserInfo = getCurrentUserInfo;
10
+ const config_1 = require("./config");
11
+ const log_1 = require("./log");
12
+ /**
13
+ * Auth Client
14
+ * 认证客户端类
15
+ */
16
+ class AuthClient {
17
+ constructor(config = {}) {
18
+ // 使用配置的 baseUrl 或全局配置
19
+ this.baseUrl =
20
+ config.baseUrl ||
21
+ config_1.sdkConfig.getServerUrl() ||
22
+ (typeof window !== "undefined" ? window.location.origin : "");
23
+ // 合并 headers
24
+ const globalHeaders = config_1.sdkConfig.getHeaders();
25
+ const globalToken = config_1.sdkConfig.getToken() || config.token;
26
+ this.headers = {
27
+ "Content-Type": "application/json",
28
+ ...globalHeaders,
29
+ ...config.headers,
30
+ };
31
+ // 如果有 token,添加到 Authorization header
32
+ if (globalToken) {
33
+ this.headers["Authorization"] = `Bearer ${globalToken}`;
34
+ }
35
+ else if (config.token) {
36
+ this.headers["Authorization"] = `Bearer ${config.token}`;
37
+ }
38
+ }
39
+ /**
40
+ * Get current user information
41
+ * 获取当前用户信息
42
+ *
43
+ * @returns Promise that resolves to UserInfo
44
+ */
45
+ async getCurrentUserInfo() {
46
+ const url = `${this.baseUrl}/api/auth/me`;
47
+ (0, log_1.debugLog)("Get current user info request:", { url });
48
+ (0, log_1.logRequest)("GET", url, this.headers);
49
+ try {
50
+ const response = await fetch(url, {
51
+ method: "GET",
52
+ headers: this.headers,
53
+ });
54
+ if (!response.ok) {
55
+ const errorText = await response.text();
56
+ let errorMessage = `Get user info failed: ${response.status} ${response.statusText}`;
57
+ try {
58
+ const errorJson = JSON.parse(errorText);
59
+ errorMessage = errorJson.detail || errorMessage;
60
+ }
61
+ catch {
62
+ errorMessage = errorText || errorMessage;
63
+ }
64
+ throw new Error(errorMessage);
65
+ }
66
+ const data = (await response.json());
67
+ (0, log_1.logResponse)(response.status, response.statusText, response.headers, data);
68
+ return data;
69
+ }
70
+ catch (error) {
71
+ (0, log_1.debugLog)("Get current user info error:", error);
72
+ throw error;
73
+ }
74
+ }
75
+ }
76
+ exports.AuthClient = AuthClient;
77
+ /**
78
+ * Get current user information (convenience function)
79
+ * 获取当前用户信息(便捷函数)
80
+ *
81
+ * @param config - Optional auth configuration
82
+ * @returns Promise that resolves to UserInfo
83
+ */
84
+ async function getCurrentUserInfo(config) {
85
+ const client = new AuthClient(config);
86
+ return client.getCurrentUserInfo();
87
+ }
package/dist/base.d.ts CHANGED
@@ -13,6 +13,8 @@ export interface BaseChatModelParams {
13
13
  topP?: number;
14
14
  modelName?: string;
15
15
  apiKey?: string;
16
+ vertexai?: boolean;
17
+ jsonSchema?: Record<string, any>;
16
18
  }
17
19
  export interface ChatResult {
18
20
  content: string;
@@ -47,6 +49,8 @@ export declare abstract class BaseChatModel {
47
49
  protected boundOptions?: BindOptions;
48
50
  protected provider: string;
49
51
  protected apiKey?: string;
52
+ protected vertexai?: boolean;
53
+ protected jsonSchema?: Record<string, any>;
50
54
  constructor(config: {
51
55
  baseUrl?: string;
52
56
  headers?: Record<string, string>;
@@ -56,6 +60,8 @@ export declare abstract class BaseChatModel {
56
60
  modelName: string;
57
61
  provider: AIModelProvider;
58
62
  apiKey?: string;
63
+ vertexai?: boolean;
64
+ jsonSchema?: Record<string, any>;
59
65
  });
60
66
  /**
61
67
  * Invoke the model with messages (non-streaming)
package/dist/base.js CHANGED
@@ -14,13 +14,15 @@ class BaseChatModel {
14
14
  const globalHeaders = config_1.sdkConfig.getHeaders();
15
15
  this.headers = {
16
16
  "Content-Type": "application/json",
17
- "Authorization": `Bearer ${config_1.sdkConfig.getToken()}`,
17
+ Authorization: `Bearer ${config_1.sdkConfig.getToken()}`,
18
18
  "X-Base-Url": config.baseUrl || "",
19
19
  ...globalHeaders,
20
20
  ...config.headers,
21
21
  };
22
22
  this.provider = config.provider;
23
23
  this.apiKey = config.apiKey;
24
+ this.vertexai = config.vertexai;
25
+ this.jsonSchema = config.jsonSchema;
24
26
  this.temperature = config.temperature ?? 0.7;
25
27
  this.maxTokens = config.maxTokens;
26
28
  this.topP = config.topP;
@@ -45,6 +47,14 @@ class BaseChatModel {
45
47
  provider: this.provider,
46
48
  api_key_env: this.apiKey,
47
49
  };
50
+ // 添加 vertexai 参数(仅当 provider 为 gemini 时有效)
51
+ if (this.provider === "gemini" && this.vertexai !== undefined) {
52
+ requestBody.vertexai = this.vertexai;
53
+ }
54
+ // 添加 response_schema 参数
55
+ if (this.jsonSchema) {
56
+ requestBody.response_schema = this.jsonSchema;
57
+ }
48
58
  const url = `${config_1.sdkConfig.getServerUrl()}/api/langchain-proxy/invoke`;
49
59
  (0, log_1.logRequest)("POST", url, this.headers, requestBody);
50
60
  const response = await fetch(url, {
@@ -60,6 +70,9 @@ class BaseChatModel {
60
70
  // 返回标准 AIMessage 格式(从 message_to_dict 序列化)
61
71
  const data = (await response.json());
62
72
  (0, log_1.logResponse)(response.status, response.statusText, response.headers, data);
73
+ if (this.jsonSchema) {
74
+ return new messages_1.AIMessage(data);
75
+ }
63
76
  // 从标准 AIMessage 格式创建 AIMessage 对象
64
77
  const content = data.content || "";
65
78
  return new messages_1.AIMessage(content);
@@ -83,6 +96,14 @@ class BaseChatModel {
83
96
  provider: this.provider,
84
97
  api_key_env: this.apiKey,
85
98
  };
99
+ // 添加 vertexai 参数(仅当 provider 为 gemini 时有效)
100
+ if (this.provider === "gemini" && this.vertexai !== undefined) {
101
+ requestBody.vertexai = this.vertexai;
102
+ }
103
+ // 添加 response_schema 参数
104
+ if (this.jsonSchema) {
105
+ requestBody.response_schema = this.jsonSchema;
106
+ }
86
107
  const url = `${config_1.sdkConfig.getServerUrl()}/api/langchain-proxy/stream`;
87
108
  const streamHeaders = {
88
109
  ...this.headers,
@@ -143,6 +164,14 @@ class BaseChatModel {
143
164
  provider: this.provider,
144
165
  api_key_env: this.apiKey,
145
166
  };
167
+ // 添加 vertexai 参数(仅当 provider 为 gemini 时有效)
168
+ if (this.provider === "gemini" && this.vertexai !== undefined) {
169
+ requestBody.vertexai = this.vertexai;
170
+ }
171
+ // 添加 response_schema 参数
172
+ if (this.jsonSchema) {
173
+ requestBody.response_schema = this.jsonSchema;
174
+ }
146
175
  const url = `${config_1.sdkConfig.getServerUrl()}/api/langchain-proxy/batch`;
147
176
  (0, log_1.logRequest)("POST", url, this.headers, requestBody);
148
177
  const response = await fetch(url, {
@@ -7,11 +7,13 @@ export interface GeminiImageGenerationConfig {
7
7
  provider?: GeminiImageGenerationProvider;
8
8
  baseUrl?: string;
9
9
  headers?: Record<string, string>;
10
+ vertexai?: boolean;
10
11
  }
11
12
  export interface GeminiImageGenerationRequest {
12
13
  prompt: string;
13
14
  model?: string;
14
15
  image?: string | string[];
16
+ vertexai?: boolean;
15
17
  aspect_ratio?: "1:1" | "2:3" | "3:2" | "3:4" | "4:3" | "4:5" | "5:4" | "9:16" | "16:9" | "21:9";
16
18
  image_size?: "1K" | "2K" | "4K";
17
19
  temperature?: number;
@@ -34,6 +36,7 @@ export interface GeminiImageChatRequest {
34
36
  chat_id?: string;
35
37
  model?: string;
36
38
  provider?: GeminiImageGenerationProvider;
39
+ vertexai?: boolean;
37
40
  aspect_ratio?: "1:1" | "2:3" | "3:2" | "3:4" | "4:3" | "4:5" | "5:4" | "9:16" | "16:9" | "21:9";
38
41
  image_size?: "1K" | "2K" | "4K";
39
42
  response_modalities?: ("TEXT" | "IMAGE")[];
@@ -48,6 +51,7 @@ export interface GeminiImageChatResponse {
48
51
  export declare class GeminiImageGenerationClient {
49
52
  private headers;
50
53
  private provider;
54
+ private vertexai?;
51
55
  constructor(config?: GeminiImageGenerationConfig);
52
56
  /**
53
57
  * Generate images
@@ -11,6 +11,7 @@ class GeminiImageGenerationClient {
11
11
  constructor(config) {
12
12
  // 确定 provider(默认为 gemini)
13
13
  this.provider = config?.provider || "gemini";
14
+ this.vertexai = config?.vertexai;
14
15
  // 合并全局 headers 和配置 headers
15
16
  const globalHeaders = config_1.sdkConfig.getHeaders();
16
17
  this.headers = {
@@ -62,6 +63,12 @@ class GeminiImageGenerationClient {
62
63
  if (request.user) {
63
64
  requestBody.user = request.user;
64
65
  }
66
+ if (request.vertexai !== undefined && this.provider === "gemini") {
67
+ requestBody.vertexai = request.vertexai;
68
+ }
69
+ else if (this.vertexai !== undefined && this.provider === "gemini") {
70
+ requestBody.vertexai = this.vertexai;
71
+ }
65
72
  const url = `${config_1.sdkConfig.getServerUrl()}/api/gemini-image-proxy/generate`;
66
73
  (0, log_1.logRequest)("POST", url, this.headers, requestBody);
67
74
  const response = await fetch(url, {
@@ -129,6 +136,12 @@ class GeminiImageGenerationClient {
129
136
  if (request.provider) {
130
137
  requestBody.provider = request.provider;
131
138
  }
139
+ if (request.vertexai !== undefined && (request.provider === "gemini" || this.provider === "gemini")) {
140
+ requestBody.vertexai = request.vertexai;
141
+ }
142
+ else if (this.vertexai !== undefined && this.provider === "gemini") {
143
+ requestBody.vertexai = this.vertexai;
144
+ }
132
145
  const url = `${config_1.sdkConfig.getServerUrl()}/api/gemini-image-proxy/chat`;
133
146
  (0, log_1.logRequest)("POST", url, this.headers, requestBody);
134
147
  const response = await fetch(url, {
package/dist/index.d.ts CHANGED
@@ -9,6 +9,7 @@ import { DoubaoImageGenerationClient, DoubaoImageSize, type DoubaoImageGeneratio
9
9
  import { GeminiImageGenerationClient, type GeminiImageGenerationConfig, type GeminiImageGenerationRequest, type GeminiImageGenerationResponse } from "./gemini-image-generation";
10
10
  import { VideoGenerationClient, type VideoGenerationConfig, type VideoGenerationRequest, type ContentGenerationTaskID, type ContentGenerationTask } from "./video_generation";
11
11
  import { DownloadClient, type DownloadConfig, type DownloadOptions, type StreamDownloadOptions } from "./download";
12
+ import { AuthClient, getCurrentUserInfo, type AuthConfig, type UserInfo } from "./auth";
12
13
  import { sdkConfig } from "./config";
13
14
  export { BaseMessage, HumanMessage, AIMessage, SystemMessage, AIMessageChunk, type MessageContent, type AIMessageChunkData, } from "./messages";
14
15
  export { BaseChatModel, type BaseChatModelParams, type AIModelProvider, type ToolDefinition, type BindOptions, } from "./base";
@@ -24,6 +25,7 @@ export { DoubaoImageGenerationClient, type DoubaoImageGenerationConfig, type Dou
24
25
  export { GeminiImageGenerationClient, type GeminiImageGenerationConfig, type GeminiImageGenerationRequest, type GeminiImageGenerationResponse, };
25
26
  export { VideoGenerationClient, type VideoGenerationConfig, type VideoGenerationRequest, type ContentGenerationTaskID, type ContentGenerationTask, };
26
27
  export { DownloadClient, type DownloadConfig, type DownloadOptions, type StreamDownloadOptions, };
28
+ export { AuthClient, getCurrentUserInfo, type AuthConfig, type UserInfo, };
27
29
  export { sdkConfig };
28
30
  /**
29
31
  * Create a chat model instance based on model name
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@
6
6
  * @see https://github.com/langchain-ai/langchainjs
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.sdkConfig = exports.DownloadClient = exports.VideoGenerationClient = exports.GeminiImageGenerationClient = exports.DoubaoImageGenerationClient = exports.ChatAnthropic = exports.ChatGoogleGenerativeAI = exports.ChatOpenAI = exports.BaseChatModel = exports.AIMessageChunk = exports.SystemMessage = exports.AIMessage = exports.HumanMessage = void 0;
9
+ exports.sdkConfig = exports.getCurrentUserInfo = exports.AuthClient = exports.DownloadClient = exports.VideoGenerationClient = exports.GeminiImageGenerationClient = exports.DoubaoImageGenerationClient = exports.ChatAnthropic = exports.ChatGoogleGenerativeAI = exports.ChatOpenAI = exports.BaseChatModel = exports.AIMessageChunk = exports.SystemMessage = exports.AIMessage = exports.HumanMessage = void 0;
10
10
  exports.createChatModel = createChatModel;
11
11
  const openai_1 = require("./chat_models/openai");
12
12
  const google_1 = require("./chat_models/google");
@@ -18,6 +18,9 @@ const video_generation_1 = require("./video_generation");
18
18
  Object.defineProperty(exports, "VideoGenerationClient", { enumerable: true, get: function () { return video_generation_1.VideoGenerationClient; } });
19
19
  const download_1 = require("./download");
20
20
  Object.defineProperty(exports, "DownloadClient", { enumerable: true, get: function () { return download_1.DownloadClient; } });
21
+ const auth_1 = require("./auth");
22
+ Object.defineProperty(exports, "AuthClient", { enumerable: true, get: function () { return auth_1.AuthClient; } });
23
+ Object.defineProperty(exports, "getCurrentUserInfo", { enumerable: true, get: function () { return auth_1.getCurrentUserInfo; } });
21
24
  const config_1 = require("./config");
22
25
  Object.defineProperty(exports, "sdkConfig", { enumerable: true, get: function () { return config_1.sdkConfig; } });
23
26
  // Re-export types and classes
@@ -8,7 +8,7 @@ export interface MessageContent {
8
8
  image_url?: string;
9
9
  }
10
10
  export interface BaseMessage {
11
- content: string | MessageContent[];
11
+ content: string | MessageContent[] | Record<string, any>;
12
12
  role?: "user" | "assistant" | "system";
13
13
  }
14
14
  export declare class HumanMessage implements BaseMessage {
@@ -17,9 +17,9 @@ export declare class HumanMessage implements BaseMessage {
17
17
  constructor(content: string | MessageContent[]);
18
18
  }
19
19
  export declare class AIMessage implements BaseMessage {
20
- content: string | MessageContent[];
20
+ content: string | MessageContent[] | Record<string, any>;
21
21
  role: "assistant";
22
- constructor(content: string | MessageContent[]);
22
+ constructor(content: string | MessageContent[] | Record<string, any>);
23
23
  }
24
24
  export declare class SystemMessage implements BaseMessage {
25
25
  content: string | MessageContent[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-world-sdk",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "description": "TypeScript SDK for AI World Platform - Chat Models, Image Generation, and Video Generation",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",