@ray-js/t-agent 0.2.7-beta.6 → 0.2.7-beta.8
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/dist/chat/ChatAgent.js +6 -3
- package/dist/chat/ChatBubbleTile.js +4 -3
- package/dist/chat/ChatMessage.js +10 -5
- 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.js +2 -2
- package/package.json +2 -2
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/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.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.8",
|
|
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": "31a0d88f88eddae8bfd802e4861c76cd02c07692"
|
|
30
30
|
}
|