@ray-js/t-agent 0.2.7-beta.1 → 0.2.7-beta.10
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-zh_CN.md +70 -3
- package/README.md +61 -3
- package/dist/chat/ChatAgent.js +6 -3
- package/dist/chat/ChatBubbleTile.js +4 -3
- package/dist/chat/ChatMessage.js +10 -5
- package/dist/chat/ChatSession.js +36 -19
- package/dist/chat/ChatTile.js +4 -3
- package/dist/chat/createChatAgent.js +4 -9
- package/dist/chat/index.d.ts +3 -2
- package/dist/chat/index.js +4 -3
- package/dist/chat/json.d.ts +7 -0
- package/dist/chat/json.js +540 -0
- package/dist/chat/utils.d.ts +0 -1
- package/dist/chat/utils.js +0 -13
- package/dist/plugins/ui.d.ts +1 -1
- package/dist/plugins/ui.js +2 -2
- package/package.json +2 -2
package/README-zh_CN.md
CHANGED
|
@@ -22,12 +22,21 @@ yarn add @ray-js/t-agent @ray-js/t-agent-plugin-aistream @ray-js/t-agent-ui-ray
|
|
|
22
22
|
"DeviceKit": "4.6.1",
|
|
23
23
|
"HomeKit": "3.4.0",
|
|
24
24
|
"MiniKit": "3.12.1",
|
|
25
|
-
"AIStreamKit": "1.
|
|
25
|
+
"AIStreamKit": "1.3.2"
|
|
26
26
|
},
|
|
27
27
|
"baseversion": "2.21.10"
|
|
28
28
|
}
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
### 小程序 kit 与功能对应表
|
|
32
|
+
|
|
33
|
+
部分功能对 App 的 kit 有依赖要求,需要配置 AIStreamKit 最低才能使用这些功能
|
|
34
|
+
|
|
35
|
+
| 功能 | AIStreamKit 最低版本 | 相关 API |
|
|
36
|
+
| ---------- | -------------------- | ------------------------------------- |
|
|
37
|
+
| 对话分组 | 1.3.2 | agent.plugins.aiStream.getChatId |
|
|
38
|
+
| 自定义参数 | 2.1.0 | agent.plugins.aiStream.onUserDataRead |
|
|
39
|
+
|
|
31
40
|
## package.json 依赖要求
|
|
32
41
|
|
|
33
42
|
```json
|
|
@@ -771,6 +780,7 @@ const createAgent = () => {
|
|
|
771
780
|
- `indexId` 索引 ID,默认为 'default'
|
|
772
781
|
- `homeId` 家庭 ID,不填默认当前家庭
|
|
773
782
|
- `earlyStart` 是否在 onAgentStart 阶段就建立连接
|
|
783
|
+
- `eventIdPrefix` eventId 前缀,用于方便云端调试和日志追踪
|
|
774
784
|
- `tokenOptions` 获取 agent token 的参数
|
|
775
785
|
- `api` API 接口名
|
|
776
786
|
- `version` 接口版本
|
|
@@ -779,14 +789,30 @@ const createAgent = () => {
|
|
|
779
789
|
|
|
780
790
|
方法:
|
|
781
791
|
|
|
782
|
-
- `agent.plugins.aiStream.send` 向智能体发送一条消息
|
|
783
|
-
- `
|
|
792
|
+
- `agent.plugins.aiStream.send(blocks, signal, userData)` 向智能体发送一条消息
|
|
793
|
+
- `blocks` 输入块数组
|
|
794
|
+
- `signal` 可选的 AbortSignal,用于中断请求
|
|
795
|
+
- `userData` 可选的用户数据,会附带在发送的消息中
|
|
796
|
+
- `agent.plugins.aiStream.chat(blocks, signal, options)` 向智能体发送一条消息,并生成提问 ChatMessage 对象和 AI 回答 ChatMessage 对象,流式更新
|
|
797
|
+
- `blocks` 输入块数组
|
|
798
|
+
- `signal` 可选的 AbortSignal
|
|
799
|
+
- `options.sendBy` 发送者角色,默认为 'user'
|
|
800
|
+
- `options.responseBy` 响应者角色,默认为 'assistant'
|
|
801
|
+
- `options.userData` 可选的用户数据
|
|
802
|
+
- `agent.plugins.aiStream.getChatId()` 获取当前会话的 chatId,返回 Promise<string>
|
|
784
803
|
|
|
785
804
|
Hooks:
|
|
786
805
|
|
|
787
806
|
- `onMessageParse` 当读取历史消息,解析消息时触发,可以在这个 Hook 里修改消息
|
|
788
807
|
- `msgItem` 存储的消息对象
|
|
789
808
|
- `result.messages` 解析后的消息列表
|
|
809
|
+
- `onChatMessageSent` 当用户消息和响应消息创建后触发
|
|
810
|
+
- `userMessage` 用户发送的消息
|
|
811
|
+
- `respMessage` AI 的响应消息
|
|
812
|
+
- `onTextCompose` 当收到文本数据时触发,用于处理文本的渲染
|
|
813
|
+
- `respMsg` 响应消息
|
|
814
|
+
- `status` 消息状态
|
|
815
|
+
- `result.text` 文本内容,可以修改
|
|
790
816
|
- `onSkillCompose` 当收到技能数据时触发,用于处理技能的渲染
|
|
791
817
|
- `skill` 技能数据数组 (ReceivedTextSkillPacketBody[])
|
|
792
818
|
- `respMsg` 响应消息
|
|
@@ -801,6 +827,47 @@ Hooks:
|
|
|
801
827
|
- `onCardsReceived` 当收到卡片数据时触发
|
|
802
828
|
- `skills` 技能数据列表 (ReceivedTextSkillPacketBody[])
|
|
803
829
|
- `result.cards` 卡片列表
|
|
830
|
+
- `onUserDataRead` **(0.2.x 新增)** 当需要读取用户自定义数据时触发,用于向 AI 平台传递额外的上下文信息
|
|
831
|
+
- `type` 触发类型,可以是 'create-session' 或 'start-event'
|
|
832
|
+
- `'create-session'` 创建会话时触发,只触发一次
|
|
833
|
+
- `'start-event'` 每次发送消息时触发
|
|
834
|
+
- `data` 上下文数据
|
|
835
|
+
- `data.blocks` 当 type 为 'start-event' 时,包含本次发送的输入块
|
|
836
|
+
- `result.userData` 返回的用户数据对象,会被合并后发送给 AI 平台
|
|
837
|
+
|
|
838
|
+
**使用示例**:
|
|
839
|
+
|
|
840
|
+
```tsx
|
|
841
|
+
const agent = createChatAgent(
|
|
842
|
+
withUI(),
|
|
843
|
+
withAIStream({
|
|
844
|
+
agentId: 'your-agent-id',
|
|
845
|
+
})
|
|
846
|
+
);
|
|
847
|
+
|
|
848
|
+
agent.plugins.aiStream.onUserDataRead((type, data, result) => {
|
|
849
|
+
// 在创建会话时传递用户信息
|
|
850
|
+
if (type === 'create-session') {
|
|
851
|
+
result.sessionAttributes = {
|
|
852
|
+
'custom.param': {
|
|
853
|
+
userName: { value: 'John' },
|
|
854
|
+
userLevel: { value: 'Plus' },
|
|
855
|
+
},
|
|
856
|
+
};
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
// 在每次发送消息时传递动态上下文
|
|
860
|
+
if (type === 'start-event') {
|
|
861
|
+
result.eventAttributes = {
|
|
862
|
+
'custom.param': {
|
|
863
|
+
timestamp: { value: Date.now() },
|
|
864
|
+
pid: { value: '123456' },
|
|
865
|
+
},
|
|
866
|
+
};
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
});
|
|
870
|
+
```
|
|
804
871
|
|
|
805
872
|
### withBuildIn 插件
|
|
806
873
|
|
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ yarn add @ray-js/t-agent @ray-js/t-agent-plugin-aistream @ray-js/t-agent-ui-ray
|
|
|
22
22
|
"DeviceKit": "4.6.1",
|
|
23
23
|
"HomeKit": "3.4.0",
|
|
24
24
|
"MiniKit": "3.12.1",
|
|
25
|
-
"AIStreamKit": "1.
|
|
25
|
+
"AIStreamKit": "1.3.2"
|
|
26
26
|
},
|
|
27
27
|
"baseversion": "2.21.10"
|
|
28
28
|
}
|
|
@@ -766,6 +766,7 @@ Parameters:
|
|
|
766
766
|
- `indexId` Index ID, defaults to 'default'
|
|
767
767
|
- `homeId` Home ID, defaults to current home if not provided
|
|
768
768
|
- `earlyStart` Whether to establish connection during onAgentStart phase
|
|
769
|
+
- `eventIdPrefix` Event ID prefix for cloud debugging and log tracing
|
|
769
770
|
- `tokenOptions` Parameters for getting agent token
|
|
770
771
|
- `api` API interface name
|
|
771
772
|
- `version` Interface version
|
|
@@ -774,14 +775,30 @@ Parameters:
|
|
|
774
775
|
|
|
775
776
|
Methods:
|
|
776
777
|
|
|
777
|
-
- `agent.plugins.aiStream.send
|
|
778
|
-
- `
|
|
778
|
+
- `agent.plugins.aiStream.send(blocks, signal, userData)` Send a message to the agent
|
|
779
|
+
- `blocks` Input block array
|
|
780
|
+
- `signal` Optional AbortSignal for interrupting requests
|
|
781
|
+
- `userData` Optional user data to be included with the message
|
|
782
|
+
- `agent.plugins.aiStream.chat(blocks, signal, options)` Send a message to the agent while generating a ChatMessage object for the question and the AI's answer, updating in a streaming manner
|
|
783
|
+
- `blocks` Input block array
|
|
784
|
+
- `signal` Optional AbortSignal
|
|
785
|
+
- `options.sendBy` Sender role, defaults to 'user'
|
|
786
|
+
- `options.responseBy` Responder role, defaults to 'assistant'
|
|
787
|
+
- `options.userData` Optional user data
|
|
788
|
+
- `agent.plugins.aiStream.getChatId()` Get the current session's chatId, returns Promise<string>
|
|
779
789
|
|
|
780
790
|
Hooks:
|
|
781
791
|
|
|
782
792
|
- `onMessageParse` Triggered when reading history messages and parsing them, allowing for message modification in this Hook
|
|
783
793
|
- `msgItem` Stored message object
|
|
784
794
|
- `result.messages` Parsed message list
|
|
795
|
+
- `onChatMessageSent` Triggered after user message and response message are created
|
|
796
|
+
- `userMessage` User's sent message
|
|
797
|
+
- `respMessage` AI's response message
|
|
798
|
+
- `onTextCompose` Triggered when receiving text data, used for handling text rendering
|
|
799
|
+
- `respMsg` Response message
|
|
800
|
+
- `status` Message status
|
|
801
|
+
- `result.text` Text content, can be modified
|
|
785
802
|
- `onSkillCompose` Triggered when receiving skill data, used for handling skill rendering
|
|
786
803
|
- `skill` Skill data array (ReceivedTextSkillPacketBody[])
|
|
787
804
|
- `respMsg` Response message
|
|
@@ -796,6 +813,47 @@ Hooks:
|
|
|
796
813
|
- `onCardsReceived` Triggered when receiving card data
|
|
797
814
|
- `skills` Skill data list (ReceivedTextSkillPacketBody[])
|
|
798
815
|
- `result.cards` Card list
|
|
816
|
+
- `onUserDataRead` **(0.2.x New)** Triggered when user custom data needs to be read, used to pass additional context information to the AI platform
|
|
817
|
+
- `type` Trigger type, can be 'create-session' or 'start-event'
|
|
818
|
+
- `'create-session'` Triggered when creating a session, only once
|
|
819
|
+
- `'start-event'` Triggered each time a message is sent
|
|
820
|
+
- `data` Context data
|
|
821
|
+
- `data.blocks` When type is 'start-event', contains the input blocks for this send
|
|
822
|
+
- `result.userData` Returned user data object, will be merged and sent to the AI platform
|
|
823
|
+
|
|
824
|
+
**Usage Example**:
|
|
825
|
+
|
|
826
|
+
```tsx
|
|
827
|
+
const agent = createChatAgent(
|
|
828
|
+
withUI(),
|
|
829
|
+
withAIStream({
|
|
830
|
+
agentId: 'your-agent-id',
|
|
831
|
+
})
|
|
832
|
+
);
|
|
833
|
+
|
|
834
|
+
agent.plugins.aiStream.onUserDataRead((type, data, result) => {
|
|
835
|
+
// Pass user information when creating a session
|
|
836
|
+
if (type === 'create-session') {
|
|
837
|
+
result.sessionAttributes = {
|
|
838
|
+
'custom.param': {
|
|
839
|
+
userName: { value: 'John' },
|
|
840
|
+
userLevel: { value: 'Plus' },
|
|
841
|
+
},
|
|
842
|
+
};
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
// Pass dynamic context each time a message is sent
|
|
846
|
+
if (type === 'start-event') {
|
|
847
|
+
result.eventAttributes = {
|
|
848
|
+
'custom.param': {
|
|
849
|
+
timestamp: { value: Date.now() },
|
|
850
|
+
pid: { value: '123456' },
|
|
851
|
+
},
|
|
852
|
+
};
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
});
|
|
856
|
+
```
|
|
799
857
|
|
|
800
858
|
### withBuildIn Plugin
|
|
801
859
|
|
package/dist/chat/ChatAgent.js
CHANGED
|
@@ -107,7 +107,8 @@ export default class ChatAgent {
|
|
|
107
107
|
await this.hooks.callHook('onAgentDispose');
|
|
108
108
|
await this.session.dispose();
|
|
109
109
|
this.started = false;
|
|
110
|
-
for (
|
|
110
|
+
for (let i = 0; i < this.pluginHooks.length; i++) {
|
|
111
|
+
const hook = this.pluginHooks[i];
|
|
111
112
|
hook.removeAllHooks();
|
|
112
113
|
}
|
|
113
114
|
await this.hooks.callHook('onAgentDispose:after');
|
|
@@ -216,7 +217,8 @@ export default class ChatAgent {
|
|
|
216
217
|
}).bubble.setText(text).update();
|
|
217
218
|
} else if (part.type === 'attachment' && attachmentCompose) {
|
|
218
219
|
const list = (await attachmentCompose(message, part)) || [];
|
|
219
|
-
for (
|
|
220
|
+
for (let i = 0; i < list.length; i++) {
|
|
221
|
+
const m = list[i];
|
|
220
222
|
m.set({
|
|
221
223
|
status: ChatMessageStatus.FINISH
|
|
222
224
|
});
|
|
@@ -283,7 +285,8 @@ export default class ChatAgent {
|
|
|
283
285
|
});
|
|
284
286
|
this.hooks = createHooks();
|
|
285
287
|
const _hooks = ['onAgentStart', 'onChatStart', 'onChatResume', 'onMessageListInit', 'onInputBlocksPush', 'onMessageChange', 'onMessagePersist', 'onTileEvent', 'onAgentDispose', 'onUserAbort', 'onError'];
|
|
286
|
-
for (
|
|
288
|
+
for (let i = 0; i < _hooks.length; i++) {
|
|
289
|
+
const hook = _hooks[i];
|
|
287
290
|
this[hook] = (fn, type) => {
|
|
288
291
|
if (type === 'before') {
|
|
289
292
|
return this.hooks.hook("".concat(hook, ":before"), fn);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
2
|
-
import "core-js/modules/web.dom-collections.iterator.js";
|
|
3
2
|
import ChatTile from './ChatTile';
|
|
4
3
|
import { BubbleTileStatus } from './types';
|
|
5
4
|
import { generateId } from './utils';
|
|
@@ -56,7 +55,8 @@ export default class ChatBubbleTile extends ChatTile {
|
|
|
56
55
|
}
|
|
57
56
|
ensureTextTile() {
|
|
58
57
|
if (!this.textTile) {
|
|
59
|
-
for (
|
|
58
|
+
for (let i = 0; i < this.children.length; i++) {
|
|
59
|
+
const child = this.children[i];
|
|
60
60
|
if (child.type === 'text') {
|
|
61
61
|
this.textTile = child;
|
|
62
62
|
break;
|
|
@@ -78,7 +78,8 @@ export default class ChatBubbleTile extends ChatTile {
|
|
|
78
78
|
initWithInputBlocks(blocks) {
|
|
79
79
|
this.textTile = null;
|
|
80
80
|
this.children = [];
|
|
81
|
-
for (
|
|
81
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
82
|
+
const block = blocks[i];
|
|
82
83
|
if (block.type === 'text') {
|
|
83
84
|
if (!this.textTile) {
|
|
84
85
|
this.textTile = new ChatTile(this.message, 'text', {
|
package/dist/chat/ChatMessage.js
CHANGED
|
@@ -17,7 +17,8 @@ export default class ChatMessage {
|
|
|
17
17
|
}
|
|
18
18
|
get bubble() {
|
|
19
19
|
if (!this._bubble) {
|
|
20
|
-
for (
|
|
20
|
+
for (let i = 0; i < this.tiles.length; i++) {
|
|
21
|
+
const tile = this.tiles[i];
|
|
21
22
|
if (tile.type === 'bubble') {
|
|
22
23
|
this._bubble = tile;
|
|
23
24
|
break;
|
|
@@ -47,7 +48,8 @@ export default class ChatMessage {
|
|
|
47
48
|
this.initTiles(null, tiles || []);
|
|
48
49
|
}
|
|
49
50
|
initTiles(root, tiles) {
|
|
50
|
-
for (
|
|
51
|
+
for (let i = 0; i < tiles.length; i++) {
|
|
52
|
+
const tile = tiles[i];
|
|
51
53
|
let r;
|
|
52
54
|
if (root) {
|
|
53
55
|
r = root.addTile(tile.type, tile.data, tile.id);
|
|
@@ -81,7 +83,8 @@ export default class ChatMessage {
|
|
|
81
83
|
}
|
|
82
84
|
await this.agent.hooks.callHook('onMessageChange:before', 'update', this);
|
|
83
85
|
await this.agent.hooks.callHook('onMessageChange', 'update', this);
|
|
84
|
-
for (
|
|
86
|
+
for (let i = 0; i < this.tiles.length; i++) {
|
|
87
|
+
const tile = this.tiles[i];
|
|
85
88
|
this.agent.session.bindTile(tile);
|
|
86
89
|
}
|
|
87
90
|
await this.agent.hooks.callHook('onMessageChange:after', 'update', this);
|
|
@@ -111,7 +114,8 @@ export default class ChatMessage {
|
|
|
111
114
|
});
|
|
112
115
|
}
|
|
113
116
|
setTilesLocked(locked) {
|
|
114
|
-
for (
|
|
117
|
+
for (let i = 0; i < this.tiles.length; i++) {
|
|
118
|
+
const tile = this.tiles[i];
|
|
115
119
|
tile.setLocked(locked);
|
|
116
120
|
}
|
|
117
121
|
return this;
|
|
@@ -153,7 +157,8 @@ export default class ChatMessage {
|
|
|
153
157
|
findTileByType(type) {
|
|
154
158
|
const ret = [];
|
|
155
159
|
const tiles = this.tiles;
|
|
156
|
-
for (
|
|
160
|
+
for (let i = 0; i < tiles.length; i++) {
|
|
161
|
+
const tile = tiles[i];
|
|
157
162
|
if (tile.type === type) {
|
|
158
163
|
ret.push(tile);
|
|
159
164
|
}
|
package/dist/chat/ChatSession.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
|
2
|
-
import "core-js/modules/esnext.iterator.constructor.js";
|
|
3
|
-
import "core-js/modules/esnext.iterator.for-each.js";
|
|
4
2
|
import "core-js/modules/web.dom-collections.iterator.js";
|
|
5
3
|
import { ChatMessageStatus } from './types';
|
|
6
4
|
import { createHooks } from 'hookable';
|
|
@@ -36,41 +34,59 @@ export default class ChatSession {
|
|
|
36
34
|
return ret;
|
|
37
35
|
});
|
|
38
36
|
_defineProperty(this, "initMessages", messages => {
|
|
39
|
-
for (
|
|
37
|
+
for (let i = 0; i < messages.length; i++) {
|
|
38
|
+
const message = messages[i];
|
|
40
39
|
this.bindMessage(message);
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
// Optimization: Direct assignment to avoid object allocation and excess function calls
|
|
41
|
+
message.status = ChatMessageStatus.FINISH;
|
|
42
|
+
message._setIsShow();
|
|
44
43
|
}
|
|
45
44
|
});
|
|
46
45
|
_defineProperty(this, "getTileById", id => {
|
|
47
46
|
return this.tileIdIndex.get(id);
|
|
48
47
|
});
|
|
49
48
|
_defineProperty(this, "bindTile", tile => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
// Iterative approach to avoid recursion overhead
|
|
50
|
+
const stack = [tile];
|
|
51
|
+
while (stack.length > 0) {
|
|
52
|
+
const current = stack.pop();
|
|
53
|
+
this.tileIdIndex.set(current.id, current);
|
|
54
|
+
|
|
55
|
+
// Push children to stack
|
|
56
|
+
if (current.children && current.children.length > 0) {
|
|
57
|
+
for (let i = current.children.length - 1; i >= 0; i--) {
|
|
58
|
+
stack.push(current.children[i]);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
53
61
|
}
|
|
54
62
|
});
|
|
55
63
|
_defineProperty(this, "unbindTile", tile => {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
64
|
+
// Iterative approach
|
|
65
|
+
const stack = [tile];
|
|
66
|
+
while (stack.length > 0) {
|
|
67
|
+
const current = stack.pop();
|
|
68
|
+
this.tileIdIndex.delete(current.id);
|
|
69
|
+
if (current.children && current.children.length > 0) {
|
|
70
|
+
for (let i = current.children.length - 1; i >= 0; i--) {
|
|
71
|
+
stack.push(current.children[i]);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
59
74
|
}
|
|
60
75
|
});
|
|
61
76
|
_defineProperty(this, "bindMessage", message => {
|
|
62
77
|
this.messages.set(message.id, message);
|
|
63
|
-
for (
|
|
78
|
+
for (let i = 0; i < message.tiles.length; i++) {
|
|
79
|
+
const tile = message.tiles[i];
|
|
64
80
|
this.bindTile(tile);
|
|
65
81
|
}
|
|
66
82
|
});
|
|
67
83
|
_defineProperty(this, "unbindMessage", message => {
|
|
68
84
|
this.messages.delete(message.id);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
85
|
+
// Optimization: Instead of full scan, just unbind tiles known to be in the message
|
|
86
|
+
for (let i = 0; i < message.tiles.length; i++) {
|
|
87
|
+
const tile = message.tiles[i];
|
|
88
|
+
this.unbindTile(tile);
|
|
89
|
+
}
|
|
74
90
|
});
|
|
75
91
|
_defineProperty(this, "onChange", fn => this.hooks.hook('onChange', fn));
|
|
76
92
|
_defineProperty(this, "getLatestMessage", () => {
|
|
@@ -85,7 +101,8 @@ export default class ChatSession {
|
|
|
85
101
|
this.agent = agent;
|
|
86
102
|
this.hooks = createHooks();
|
|
87
103
|
const hooks = ['onChange'];
|
|
88
|
-
for (
|
|
104
|
+
for (let i = 0; i < hooks.length; i++) {
|
|
105
|
+
const hook = hooks[i];
|
|
89
106
|
this[hook] = fn => this.hooks.hook(hook, fn);
|
|
90
107
|
}
|
|
91
108
|
}
|
package/dist/chat/ChatTile.js
CHANGED
|
@@ -2,7 +2,6 @@ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
|
2
2
|
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
|
3
3
|
import "core-js/modules/esnext.iterator.constructor.js";
|
|
4
4
|
import "core-js/modules/esnext.iterator.map.js";
|
|
5
|
-
import "core-js/modules/web.dom-collections.iterator.js";
|
|
6
5
|
import { generateId } from './utils';
|
|
7
6
|
export default class ChatTile {
|
|
8
7
|
constructor(message, type) {
|
|
@@ -20,7 +19,8 @@ export default class ChatTile {
|
|
|
20
19
|
setLocked(value) {
|
|
21
20
|
this.locked = value;
|
|
22
21
|
// 递归锁定
|
|
23
|
-
for (
|
|
22
|
+
for (let i = 0; i < this.children.length; i++) {
|
|
23
|
+
const child = this.children[i];
|
|
24
24
|
child.setLocked(value);
|
|
25
25
|
}
|
|
26
26
|
return this;
|
|
@@ -61,7 +61,8 @@ export default class ChatTile {
|
|
|
61
61
|
}
|
|
62
62
|
findByType(type) {
|
|
63
63
|
let ret = [];
|
|
64
|
-
for (
|
|
64
|
+
for (let i = 0; i < this.children.length; i++) {
|
|
65
|
+
const tile = this.children[i];
|
|
65
66
|
if (tile.type === type) {
|
|
66
67
|
ret.push(tile);
|
|
67
68
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import "core-js/modules/web.dom-collections.iterator.js";
|
|
2
1
|
import ChatAgent from './ChatAgent';
|
|
3
2
|
|
|
4
3
|
// 提取单个插件的返回类型(排除 hooks)
|
|
@@ -7,19 +6,15 @@ import ChatAgent from './ChatAgent';
|
|
|
7
6
|
|
|
8
7
|
export function createChatAgent() {
|
|
9
8
|
const agent = new ChatAgent();
|
|
10
|
-
for (
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
for (const plugin of plugins) {
|
|
9
|
+
for (let i = 0; i < arguments.length; i++) {
|
|
10
|
+
const plugin = i < 0 || arguments.length <= i ? undefined : arguments[i];
|
|
14
11
|
agent.applyPlugin(plugin);
|
|
15
12
|
}
|
|
16
13
|
return agent;
|
|
17
14
|
}
|
|
18
15
|
export function applyChatAgentPlugins(agent) {
|
|
19
|
-
for (
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
for (const plugin of plugins) {
|
|
16
|
+
for (let i = 0; i < (arguments.length <= 1 ? 0 : arguments.length - 1); i++) {
|
|
17
|
+
const plugin = i + 1 < 1 || arguments.length <= i + 1 ? undefined : arguments[i + 1];
|
|
23
18
|
agent.applyPlugin(plugin);
|
|
24
19
|
}
|
|
25
20
|
return agent;
|
package/dist/chat/index.d.ts
CHANGED
|
@@ -4,10 +4,11 @@ import StreamResponse from './StreamResponse';
|
|
|
4
4
|
import ChatTile from './ChatTile';
|
|
5
5
|
import ChatBubbleTile from './ChatBubbleTile';
|
|
6
6
|
import ChatMessage from './ChatMessage';
|
|
7
|
-
import { generateId,
|
|
7
|
+
import { generateId, isAbortError, shuffleWithSeed } from './utils';
|
|
8
8
|
import Logger, { getLogger } from './Logger';
|
|
9
9
|
import { Emitter, EmitterEvent } from './Emitter';
|
|
10
10
|
export { createHooks, Hookable } from 'hookable';
|
|
11
|
-
export { ChatAgent, ChatSession, StreamResponse, ChatTile, ChatBubbleTile, ChatMessage, generateId,
|
|
11
|
+
export { ChatAgent, ChatSession, StreamResponse, ChatTile, ChatBubbleTile, ChatMessage, generateId, getLogger, Logger, Emitter, EmitterEvent, isAbortError, shuffleWithSeed, };
|
|
12
12
|
export * from './createChatAgent';
|
|
13
13
|
export * from './types';
|
|
14
|
+
export * from './json';
|
package/dist/chat/index.js
CHANGED
|
@@ -4,10 +4,11 @@ import StreamResponse from './StreamResponse';
|
|
|
4
4
|
import ChatTile from './ChatTile';
|
|
5
5
|
import ChatBubbleTile from './ChatBubbleTile';
|
|
6
6
|
import ChatMessage from './ChatMessage';
|
|
7
|
-
import { generateId,
|
|
7
|
+
import { generateId, isAbortError, shuffleWithSeed } from './utils';
|
|
8
8
|
import Logger, { getLogger } from './Logger';
|
|
9
9
|
import { Emitter, EmitterEvent } from './Emitter';
|
|
10
10
|
export { createHooks, Hookable } from 'hookable';
|
|
11
|
-
export { ChatAgent, ChatSession, StreamResponse, ChatTile, ChatBubbleTile, ChatMessage, generateId,
|
|
11
|
+
export { ChatAgent, ChatSession, StreamResponse, ChatTile, ChatBubbleTile, ChatMessage, generateId, getLogger, Logger, Emitter, EmitterEvent, isAbortError, shuffleWithSeed };
|
|
12
12
|
export * from './createChatAgent';
|
|
13
|
-
export * from './types';
|
|
13
|
+
export * from './types';
|
|
14
|
+
export * from './json';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function partialJSONParse<T = any>(input: string): T;
|
|
2
|
+
export interface JsonParseResult<T = any> {
|
|
3
|
+
value: T;
|
|
4
|
+
complete: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare function partialJSONParseWithStatus<T = any>(input: string): JsonParseResult<T>;
|
|
7
|
+
export declare function safeParseJSON<T = any>(str: any): T | undefined;
|
|
@@ -0,0 +1,540 @@
|
|
|
1
|
+
import "core-js/modules/es.regexp.exec.js";
|
|
2
|
+
import "core-js/modules/es.regexp.flags.js";
|
|
3
|
+
import "core-js/modules/es.string.trim.js";
|
|
4
|
+
import "core-js/modules/web.dom-collections.iterator.js";
|
|
5
|
+
/* eslint-disable no-continue,no-bitwise,no-param-reassign */
|
|
6
|
+
var TokenType = /*#__PURE__*/function (TokenType) {
|
|
7
|
+
TokenType[TokenType["Brace"] = 0] = "Brace";
|
|
8
|
+
TokenType[TokenType["Paren"] = 1] = "Paren";
|
|
9
|
+
TokenType[TokenType["Separator"] = 2] = "Separator";
|
|
10
|
+
TokenType[TokenType["Delimiter"] = 3] = "Delimiter";
|
|
11
|
+
TokenType[TokenType["String"] = 4] = "String";
|
|
12
|
+
TokenType[TokenType["Number"] = 5] = "Number";
|
|
13
|
+
TokenType[TokenType["Name"] = 6] = "Name";
|
|
14
|
+
return TokenType;
|
|
15
|
+
}(TokenType || {});
|
|
16
|
+
var TokenFlag = /*#__PURE__*/function (TokenFlag) {
|
|
17
|
+
TokenFlag[TokenFlag["None"] = 0] = "None";
|
|
18
|
+
TokenFlag[TokenFlag["IsKey"] = 1] = "IsKey";
|
|
19
|
+
TokenFlag[TokenFlag["IsDanglingKey"] = 2] = "IsDanglingKey";
|
|
20
|
+
return TokenFlag;
|
|
21
|
+
}(TokenFlag || {}); // Parallel arrays container
|
|
22
|
+
const C_BRACE_OPEN = 123; // {
|
|
23
|
+
const C_BRACE_CLOSE = 125; // }
|
|
24
|
+
const C_BRACKET_OPEN = 91; // [
|
|
25
|
+
const C_BRACKET_CLOSE = 93; // ]
|
|
26
|
+
const C_COLON = 58; // :
|
|
27
|
+
const C_COMMA = 44; // ,
|
|
28
|
+
const C_QUOTE = 34; // "
|
|
29
|
+
const C_BACKSLASH = 92; // \
|
|
30
|
+
const C_MINUS = 45; // -
|
|
31
|
+
const C_PLUS = 43; // +
|
|
32
|
+
const C_DOT = 46; // .
|
|
33
|
+
const C_e = 101; // e
|
|
34
|
+
const C_E = 69; // E
|
|
35
|
+
const C_SPACE = 32;
|
|
36
|
+
const C_TAB = 9;
|
|
37
|
+
const C_LF = 10;
|
|
38
|
+
const C_CR = 13;
|
|
39
|
+
function isDigit(code) {
|
|
40
|
+
return code >= 48 && code <= 57; // 0-9
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Lightweight stack for tracking context during tokenization
|
|
44
|
+
var ContextKind = /*#__PURE__*/function (ContextKind) {
|
|
45
|
+
ContextKind[ContextKind["Object"] = 0] = "Object";
|
|
46
|
+
ContextKind[ContextKind["Array"] = 1] = "Array";
|
|
47
|
+
return ContextKind;
|
|
48
|
+
}(ContextKind || {});
|
|
49
|
+
function tokenize(input) {
|
|
50
|
+
let current = 0;
|
|
51
|
+
const len = input.length;
|
|
52
|
+
const types = [];
|
|
53
|
+
const values = [];
|
|
54
|
+
const flags = [];
|
|
55
|
+
|
|
56
|
+
// Context stack for tracking JSON structure to flag keys
|
|
57
|
+
const stackKind = [];
|
|
58
|
+
const stackState = [];
|
|
59
|
+
|
|
60
|
+
// Helper to update context after a value
|
|
61
|
+
const afterValue = () => {
|
|
62
|
+
if (stackKind.length > 0) {
|
|
63
|
+
// Direct array access is faster
|
|
64
|
+
const idx = stackKind.length - 1;
|
|
65
|
+
if (stackKind[idx] === ContextKind.Object) {
|
|
66
|
+
stackState[idx] = 3; // Expect comma or end
|
|
67
|
+
} else {
|
|
68
|
+
stackState[idx] = 1; // Expect comma or end
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
while (current < len) {
|
|
73
|
+
const code = input.charCodeAt(current);
|
|
74
|
+
if (code === C_SPACE || code === C_TAB || code === C_LF || code === C_CR) {
|
|
75
|
+
current++;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (code === C_BRACE_OPEN) {
|
|
79
|
+
types.push(TokenType.Brace);
|
|
80
|
+
values.push('{');
|
|
81
|
+
flags.push(TokenFlag.None);
|
|
82
|
+
stackKind.push(ContextKind.Object);
|
|
83
|
+
stackState.push(0); // Expect key
|
|
84
|
+
current++;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (code === C_BRACE_CLOSE) {
|
|
88
|
+
types.push(TokenType.Brace);
|
|
89
|
+
values.push('}');
|
|
90
|
+
flags.push(TokenFlag.None);
|
|
91
|
+
stackKind.pop();
|
|
92
|
+
stackState.pop();
|
|
93
|
+
afterValue(); // Closing brace acts like a value completion for parent
|
|
94
|
+
current++;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (code === C_BRACKET_OPEN) {
|
|
98
|
+
types.push(TokenType.Paren);
|
|
99
|
+
values.push('[');
|
|
100
|
+
flags.push(TokenFlag.None);
|
|
101
|
+
stackKind.push(ContextKind.Array);
|
|
102
|
+
stackState.push(0); // Expect value
|
|
103
|
+
current++;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (code === C_BRACKET_CLOSE) {
|
|
107
|
+
types.push(TokenType.Paren);
|
|
108
|
+
values.push(']');
|
|
109
|
+
flags.push(TokenFlag.None);
|
|
110
|
+
stackKind.pop();
|
|
111
|
+
stackState.pop();
|
|
112
|
+
afterValue(); // Closing bracket acts like a value completion for parent
|
|
113
|
+
current++;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (code === C_COLON) {
|
|
117
|
+
types.push(TokenType.Separator);
|
|
118
|
+
values.push(':');
|
|
119
|
+
flags.push(TokenFlag.None);
|
|
120
|
+
if (stackKind.length > 0) {
|
|
121
|
+
const idx = stackKind.length - 1;
|
|
122
|
+
if (stackKind[idx] === ContextKind.Object) {
|
|
123
|
+
stackState[idx] = 2; // Expect value
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
current++;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (code === C_COMMA) {
|
|
130
|
+
types.push(TokenType.Delimiter);
|
|
131
|
+
values.push(',');
|
|
132
|
+
flags.push(TokenFlag.None);
|
|
133
|
+
if (stackKind.length > 0) {
|
|
134
|
+
const idx = stackKind.length - 1;
|
|
135
|
+
if (stackKind[idx] === ContextKind.Object) stackState[idx] = 0; // Expect key next
|
|
136
|
+
else stackState[idx] = 0; // Expect value next
|
|
137
|
+
}
|
|
138
|
+
current++;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (code === C_QUOTE) {
|
|
142
|
+
let flag = TokenFlag.None;
|
|
143
|
+
let isKeyContext = false;
|
|
144
|
+
if (stackKind.length > 0) {
|
|
145
|
+
const idx = stackKind.length - 1;
|
|
146
|
+
if (stackKind[idx] === ContextKind.Object && stackState[idx] === 0) {
|
|
147
|
+
isKeyContext = true;
|
|
148
|
+
flag |= TokenFlag.IsKey;
|
|
149
|
+
stackState[idx] = 1; // Expect colon next
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (!isKeyContext) {
|
|
153
|
+
afterValue();
|
|
154
|
+
}
|
|
155
|
+
const start = current;
|
|
156
|
+
current++; // skip opening quote
|
|
157
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
158
|
+
|
|
159
|
+
// Fast scan
|
|
160
|
+
while (current < len) {
|
|
161
|
+
const c = input.charCodeAt(current);
|
|
162
|
+
if (c === C_QUOTE) break;
|
|
163
|
+
if (c === C_BACKSLASH) {
|
|
164
|
+
current += 2; // skip backslash and next char
|
|
165
|
+
} else {
|
|
166
|
+
current++;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (current >= len) {
|
|
170
|
+
// Unterminated string
|
|
171
|
+
if (flag & TokenFlag.IsKey) {
|
|
172
|
+
flag |= TokenFlag.IsDanglingKey;
|
|
173
|
+
}
|
|
174
|
+
types.push(TokenType.String);
|
|
175
|
+
values.push(input.slice(start + 1, current));
|
|
176
|
+
flags.push(flag);
|
|
177
|
+
break; // End of input
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Found closing quote
|
|
181
|
+
const contentEnd = current;
|
|
182
|
+
current++; // consume closing quote
|
|
183
|
+
|
|
184
|
+
types.push(TokenType.String);
|
|
185
|
+
values.push(input.slice(start + 1, contentEnd));
|
|
186
|
+
flags.push(flag);
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Numbers
|
|
191
|
+
if (isDigit(code) || code === C_MINUS) {
|
|
192
|
+
afterValue();
|
|
193
|
+
const start = current;
|
|
194
|
+
if (code === C_MINUS) current++;
|
|
195
|
+
while (current < len) {
|
|
196
|
+
const c = input.charCodeAt(current);
|
|
197
|
+
if (isDigit(c) || c === C_DOT || c === C_e || c === C_E || c === C_PLUS || c === C_MINUS) {
|
|
198
|
+
current++;
|
|
199
|
+
} else {
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
types.push(TokenType.Number);
|
|
204
|
+
values.push(input.slice(start, current));
|
|
205
|
+
flags.push(TokenFlag.None);
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// true / false / null
|
|
210
|
+
if (code === 116 /* t */) {
|
|
211
|
+
if (input.startsWith('true', current)) {
|
|
212
|
+
afterValue();
|
|
213
|
+
types.push(TokenType.Name);
|
|
214
|
+
values.push('true');
|
|
215
|
+
flags.push(TokenFlag.None);
|
|
216
|
+
current += 4;
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (code === 102 /* f */) {
|
|
221
|
+
if (input.startsWith('false', current)) {
|
|
222
|
+
afterValue();
|
|
223
|
+
types.push(TokenType.Name);
|
|
224
|
+
values.push('false');
|
|
225
|
+
flags.push(TokenFlag.None);
|
|
226
|
+
current += 5;
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (code === 110 /* n */) {
|
|
231
|
+
if (input.startsWith('null', current)) {
|
|
232
|
+
afterValue();
|
|
233
|
+
types.push(TokenType.Name);
|
|
234
|
+
values.push('null');
|
|
235
|
+
flags.push(TokenFlag.None);
|
|
236
|
+
current += 4;
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Invalid or unknown
|
|
242
|
+
if (code >= 65 && code <= 90 ||
|
|
243
|
+
// A-Z
|
|
244
|
+
code >= 97 && code <= 122 // a-z
|
|
245
|
+
) {
|
|
246
|
+
let value = '';
|
|
247
|
+
while (current < len) {
|
|
248
|
+
const c = input.charCodeAt(current);
|
|
249
|
+
if (c >= 65 && c <= 90 || c >= 97 && c <= 122) {
|
|
250
|
+
value += input[current];
|
|
251
|
+
current++;
|
|
252
|
+
} else {
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
throw new Error("Invalid token: ".concat(value, " is not a valid token!"));
|
|
257
|
+
}
|
|
258
|
+
current++;
|
|
259
|
+
}
|
|
260
|
+
return {
|
|
261
|
+
types,
|
|
262
|
+
values,
|
|
263
|
+
flags
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
function strip(tokens) {
|
|
267
|
+
const {
|
|
268
|
+
types,
|
|
269
|
+
values,
|
|
270
|
+
flags
|
|
271
|
+
} = tokens;
|
|
272
|
+
if (types.length === 0) return tokens;
|
|
273
|
+
while (types.length > 0) {
|
|
274
|
+
const idx = types.length - 1;
|
|
275
|
+
const t = types[idx];
|
|
276
|
+
const v = values[idx];
|
|
277
|
+
const f = flags[idx];
|
|
278
|
+
if (t === TokenType.Separator) {
|
|
279
|
+
types.pop();
|
|
280
|
+
values.pop();
|
|
281
|
+
flags.pop();
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
if (t === TokenType.Number) {
|
|
285
|
+
// Check for trailing dot or minus
|
|
286
|
+
const lastChar = v.charCodeAt(v.length - 1);
|
|
287
|
+
if (lastChar === C_DOT || lastChar === C_MINUS) {
|
|
288
|
+
types.pop();
|
|
289
|
+
values.pop();
|
|
290
|
+
flags.pop();
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
if (t === TokenType.String) {
|
|
296
|
+
if (f & TokenFlag.IsKey) {
|
|
297
|
+
// Dangling key
|
|
298
|
+
// Check "aggressive" strip for empty objects logic from original
|
|
299
|
+
const n = types.length;
|
|
300
|
+
if (n >= 2) {
|
|
301
|
+
const t2Type = types[n - 2];
|
|
302
|
+
const t2Val = values[n - 2];
|
|
303
|
+
if (t2Type === TokenType.Brace && t2Val === '{') {
|
|
304
|
+
if (n >= 3 && types[n - 3] === TokenType.Delimiter) {
|
|
305
|
+
// , { "key" -> pop 3
|
|
306
|
+
types.length -= 3;
|
|
307
|
+
values.length -= 3;
|
|
308
|
+
flags.length -= 3;
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
if (t2Type === TokenType.Paren && t2Val === '[') {
|
|
313
|
+
if (n >= 3 && types[n - 3] === TokenType.Delimiter) {
|
|
314
|
+
// , [ "key" -> pop 3
|
|
315
|
+
types.length -= 3;
|
|
316
|
+
values.length -= 3;
|
|
317
|
+
flags.length -= 3;
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
types.pop();
|
|
323
|
+
values.pop();
|
|
324
|
+
flags.pop();
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
break;
|
|
328
|
+
}
|
|
329
|
+
if (t === TokenType.Delimiter) {
|
|
330
|
+
types.pop();
|
|
331
|
+
values.pop();
|
|
332
|
+
flags.pop();
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
if (t === TokenType.Brace) {
|
|
336
|
+
if (v === '{') {
|
|
337
|
+
if (types.length >= 2 && types[types.length - 2] === TokenType.Delimiter) {
|
|
338
|
+
types.length -= 2;
|
|
339
|
+
values.length -= 2;
|
|
340
|
+
flags.length -= 2;
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
if (t === TokenType.Paren) {
|
|
347
|
+
if (v === '[') {
|
|
348
|
+
if (types.length >= 2 && types[types.length - 2] === TokenType.Delimiter) {
|
|
349
|
+
types.length -= 2;
|
|
350
|
+
values.length -= 2;
|
|
351
|
+
flags.length -= 2;
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
break;
|
|
356
|
+
}
|
|
357
|
+
break;
|
|
358
|
+
}
|
|
359
|
+
return tokens;
|
|
360
|
+
}
|
|
361
|
+
function unstrip(tokens) {
|
|
362
|
+
const {
|
|
363
|
+
types,
|
|
364
|
+
values,
|
|
365
|
+
flags
|
|
366
|
+
} = tokens;
|
|
367
|
+
const stack = []; // Stack of expected closing chars
|
|
368
|
+
|
|
369
|
+
// Forward pass to build stack
|
|
370
|
+
const len = types.length;
|
|
371
|
+
for (let i = 0; i < len; i++) {
|
|
372
|
+
const t = types[i];
|
|
373
|
+
const v = values[i];
|
|
374
|
+
if (t === TokenType.Brace) {
|
|
375
|
+
if (v === '{') {
|
|
376
|
+
stack.push('}');
|
|
377
|
+
} else if (v === '}') {
|
|
378
|
+
// Optimistic matching: just pop the top expectation
|
|
379
|
+
// If stack is empty or mismatch, we just assume it closes the last open
|
|
380
|
+
stack.pop();
|
|
381
|
+
}
|
|
382
|
+
} else if (t === TokenType.Paren) {
|
|
383
|
+
if (v === '[') {
|
|
384
|
+
stack.push(']');
|
|
385
|
+
} else if (v === ']') {
|
|
386
|
+
stack.pop();
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Reverse complete
|
|
392
|
+
while (stack.length > 0) {
|
|
393
|
+
const char = stack.pop();
|
|
394
|
+
if (char === '}') {
|
|
395
|
+
types.push(TokenType.Brace);
|
|
396
|
+
values.push('}');
|
|
397
|
+
flags.push(TokenFlag.None);
|
|
398
|
+
} else {
|
|
399
|
+
types.push(TokenType.Paren);
|
|
400
|
+
values.push(']');
|
|
401
|
+
flags.push(TokenFlag.None);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return tokens;
|
|
405
|
+
}
|
|
406
|
+
function generate(tokens) {
|
|
407
|
+
const {
|
|
408
|
+
types,
|
|
409
|
+
values
|
|
410
|
+
} = tokens;
|
|
411
|
+
const parts = [];
|
|
412
|
+
const len = types.length;
|
|
413
|
+
for (let i = 0; i < len; i++) {
|
|
414
|
+
const t = types[i];
|
|
415
|
+
const v = values[i];
|
|
416
|
+
|
|
417
|
+
// Trailing comma check
|
|
418
|
+
if (t === TokenType.Delimiter && i + 1 < len) {
|
|
419
|
+
const nextT = types[i + 1];
|
|
420
|
+
const nextV = values[i + 1];
|
|
421
|
+
if (nextT === TokenType.Brace && nextV === '}' || nextT === TokenType.Paren && nextV === ']') {
|
|
422
|
+
// Check if prev was opening brace/paren
|
|
423
|
+
if (i > 0) {
|
|
424
|
+
const prevT = types[i - 1];
|
|
425
|
+
const prevV = values[i - 1];
|
|
426
|
+
if (prevT === TokenType.Brace && prevV === '{' || prevT === TokenType.Paren && prevV === '[') {
|
|
427
|
+
parts.push(v);
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
continue; // Skip trailing comma
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
if (t === TokenType.String) {
|
|
435
|
+
parts.push('"' + v + '"');
|
|
436
|
+
} else {
|
|
437
|
+
parts.push(v);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return parts.join('');
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/** * Best-effort partial JSON parser: tries to complete dangling structures * and then JSON.parse */
|
|
444
|
+
function stripCodeFence(input) {
|
|
445
|
+
if (typeof input !== 'string') return input;
|
|
446
|
+
const trimmed = input.trim();
|
|
447
|
+
|
|
448
|
+
// 只处理以 ``` 或 ~~~ 开头的
|
|
449
|
+
const fenceMatch = trimmed.match(/^(```|~~~)/);
|
|
450
|
+
if (!fenceMatch) return input;
|
|
451
|
+
const fence = fenceMatch[1]; // ``` 或 ~~~
|
|
452
|
+
|
|
453
|
+
// 找到第一行结束位置(开头 fence 那一整行,包括语言信息)
|
|
454
|
+
const firstNewlineIndex = trimmed.indexOf('\n');
|
|
455
|
+
if (firstNewlineIndex === -1) {
|
|
456
|
+
// 只有一行,比如 "```json" 这种,说明没内容
|
|
457
|
+
return '';
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// 去掉开头那一行 fence + 语言说明,剩下正文+结尾 fence+垃圾
|
|
461
|
+
const body = trimmed.slice(firstNewlineIndex + 1);
|
|
462
|
+
|
|
463
|
+
// 在正文中找最后一个同类型 fence
|
|
464
|
+
const lastFenceIndex = body.lastIndexOf(fence);
|
|
465
|
+
if (lastFenceIndex === -1) {
|
|
466
|
+
// 没有闭合 fence,就当只有开头 fence,剩下全是正文
|
|
467
|
+
return body.trim();
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// 截到最后一个 fence 之前,后面统统当垃圾扔掉
|
|
471
|
+
const content = body.slice(0, lastFenceIndex);
|
|
472
|
+
return content.trim();
|
|
473
|
+
}
|
|
474
|
+
export function partialJSONParse(input) {
|
|
475
|
+
if (!input || typeof input !== 'string') {
|
|
476
|
+
return {};
|
|
477
|
+
}
|
|
478
|
+
// Pipeline
|
|
479
|
+
const tokens = tokenize(input);
|
|
480
|
+
const cleaned = strip(tokens);
|
|
481
|
+
const closed = unstrip(cleaned);
|
|
482
|
+
// normalizeTrailingCommas is integrated into generate
|
|
483
|
+
const jsonish = generate(closed);
|
|
484
|
+
return JSON.parse(jsonish);
|
|
485
|
+
}
|
|
486
|
+
export function partialJSONParseWithStatus(input) {
|
|
487
|
+
if (typeof input !== 'string') {
|
|
488
|
+
return {
|
|
489
|
+
value: {},
|
|
490
|
+
complete: true
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
input = stripCodeFence(input.trim());
|
|
494
|
+
if (input === '') {
|
|
495
|
+
return {
|
|
496
|
+
value: {},
|
|
497
|
+
complete: false
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// 1) 先尝试“原文”是否就是完整 JSON
|
|
502
|
+
try {
|
|
503
|
+
const direct = JSON.parse(input);
|
|
504
|
+
return {
|
|
505
|
+
value: direct,
|
|
506
|
+
complete: true
|
|
507
|
+
};
|
|
508
|
+
} catch (_unused) {
|
|
509
|
+
// noop,继续走容错流程
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// 2) 走 partial 流程
|
|
513
|
+
try {
|
|
514
|
+
const value = partialJSONParse(input);
|
|
515
|
+
// 既然原文 parse 失败,则这是“修复后”才能成功,标记为不完整
|
|
516
|
+
return {
|
|
517
|
+
value,
|
|
518
|
+
complete: false
|
|
519
|
+
};
|
|
520
|
+
} catch (e) {
|
|
521
|
+
// 按你的“尽力而为”语义:失败就返回空对象 & 不完整
|
|
522
|
+
return {
|
|
523
|
+
value: {},
|
|
524
|
+
complete: false
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
export function safeParseJSON(str) {
|
|
529
|
+
if (str && typeof str === 'string') {
|
|
530
|
+
try {
|
|
531
|
+
return JSON.parse(str);
|
|
532
|
+
} catch (e) {
|
|
533
|
+
console.warn('safeParseJSON error:', e);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
if (str && typeof str === 'object') {
|
|
537
|
+
return str;
|
|
538
|
+
}
|
|
539
|
+
return undefined;
|
|
540
|
+
}
|
package/dist/chat/utils.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export declare function generateId(length?: number): string;
|
|
2
2
|
export declare function deepCloneToPlainObject(obj: any, visited?: WeakMap<object, any>): any;
|
|
3
|
-
export declare function safeParseJSON<T = any>(str: any): T | undefined;
|
|
4
3
|
export declare function deepMerge(target: any, source: any): any;
|
|
5
4
|
export declare function isAbortError(reason: any): any;
|
|
6
5
|
export declare function shuffleWithSeed<T>(array: T[], seed: string): T[];
|
package/dist/chat/utils.js
CHANGED
|
@@ -86,19 +86,6 @@ export function deepCloneToPlainObject(obj) {
|
|
|
86
86
|
}
|
|
87
87
|
return clonedObj;
|
|
88
88
|
}
|
|
89
|
-
export function safeParseJSON(str) {
|
|
90
|
-
if (str && typeof str === 'string') {
|
|
91
|
-
try {
|
|
92
|
-
return JSON.parse(str);
|
|
93
|
-
} catch (e) {
|
|
94
|
-
console.warn('safeParseJSON error:', e);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
if (str && typeof str === 'object') {
|
|
98
|
-
return str;
|
|
99
|
-
}
|
|
100
|
-
return undefined;
|
|
101
|
-
}
|
|
102
89
|
export function deepMerge(target, source) {
|
|
103
90
|
if (typeof target !== 'object' || target === null) {
|
|
104
91
|
return source; // 如果目标不是对象,直接返回来源
|
package/dist/plugins/ui.d.ts
CHANGED
package/dist/plugins/ui.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import "core-js/modules/esnext.iterator.constructor.js";
|
|
2
2
|
import "core-js/modules/esnext.iterator.map.js";
|
|
3
|
-
import "core-js/modules/web.dom-collections.iterator.js";
|
|
4
3
|
import { Emitter, EmitterEvent } from '../chat';
|
|
5
4
|
import { createHooks } from 'hookable';
|
|
6
5
|
export function withUI() {
|
|
@@ -33,7 +32,8 @@ export function withUI() {
|
|
|
33
32
|
}, 'after');
|
|
34
33
|
agent.onAgentDispose(() => {
|
|
35
34
|
const types = Object.keys(emitter.listeners);
|
|
36
|
-
for (
|
|
35
|
+
for (let i = 0; i < types.length; i++) {
|
|
36
|
+
const type = types[i];
|
|
37
37
|
delete emitter.listeners[type];
|
|
38
38
|
}
|
|
39
39
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ray-js/t-agent",
|
|
3
|
-
"version": "0.2.7-beta.
|
|
3
|
+
"version": "0.2.7-beta.10",
|
|
4
4
|
"author": "Tuya.inc",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|
|
@@ -26,5 +26,5 @@
|
|
|
26
26
|
"build": "ray build --type=component --output dist",
|
|
27
27
|
"clean": "rimraf ./dist"
|
|
28
28
|
},
|
|
29
|
-
"gitHead": "
|
|
29
|
+
"gitHead": "4fa71cb1278f9ef5d4a171f81ff87dbbc8040e4d"
|
|
30
30
|
}
|