@ray-js/t-agent-plugin-aistream 0.2.7-beta.9 → 0.2.8-beta.1
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 +286 -95
- package/dist/AIStreamTypes.d.ts +41 -3
- package/dist/AIStreamTypes.js +6 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -1
- package/dist/mcp/McpServer.d.ts +11 -0
- package/dist/mcp/McpServer.js +162 -0
- package/dist/mcp/index.d.ts +3 -0
- package/dist/mcp/index.js +3 -0
- package/dist/mcp/types.d.ts +114 -0
- package/dist/mcp/types.js +1 -0
- package/dist/mcp/withMCP.d.ts +15 -0
- package/dist/mcp/withMCP.js +98 -0
- package/dist/utils/AIStream.d.ts +14 -1
- package/dist/utils/AIStream.js +60 -10
- package/dist/utils/defaultMock.js +285 -79
- package/dist/utils/mock.d.ts +14 -0
- package/dist/utils/object.d.ts +0 -1
- package/dist/utils/object.js +1 -24
- package/dist/utils/observer.d.ts +6 -2
- package/dist/utils/observer.js +17 -6
- package/dist/utils/sendMessage.js +48 -15
- package/dist/utils/track.js +2 -2
- package/dist/utils/ttt.d.ts +3 -2
- package/dist/utils/ttt.js +2 -1
- package/dist/withAIStream.d.ts +4 -1
- package/dist/withAIStream.js +66 -17
- package/package.json +2 -2
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
|
|
2
|
+
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
3
|
+
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
|
4
|
+
const _excluded = ["handler"];
|
|
5
|
+
import "core-js/modules/es.json.stringify.js";
|
|
6
|
+
import "core-js/modules/es.string.trim.js";
|
|
7
|
+
import "core-js/modules/esnext.iterator.constructor.js";
|
|
8
|
+
import "core-js/modules/esnext.iterator.map.js";
|
|
9
|
+
import "core-js/modules/web.dom-collections.iterator.js";
|
|
10
|
+
function isCallToolResult(value) {
|
|
11
|
+
return !!value && Array.isArray(value.content);
|
|
12
|
+
}
|
|
13
|
+
function normalizeToolResult(value) {
|
|
14
|
+
if (isCallToolResult(value)) {
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
if (typeof value === 'string') {
|
|
18
|
+
return {
|
|
19
|
+
content: [{
|
|
20
|
+
type: 'text',
|
|
21
|
+
text: value
|
|
22
|
+
}]
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
content: [{
|
|
27
|
+
type: 'text',
|
|
28
|
+
text: JSON.stringify(value == null ? {} : value)
|
|
29
|
+
}]
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function createJsonRpcError(id, code, message, data) {
|
|
33
|
+
const response = {
|
|
34
|
+
jsonrpc: '2.0',
|
|
35
|
+
id,
|
|
36
|
+
error: {
|
|
37
|
+
code,
|
|
38
|
+
message
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
if (data !== undefined) {
|
|
42
|
+
response.error.data = data;
|
|
43
|
+
}
|
|
44
|
+
return JSON.stringify(response);
|
|
45
|
+
}
|
|
46
|
+
export class McpServer {
|
|
47
|
+
constructor(serverInfo) {
|
|
48
|
+
var _options$capabilities;
|
|
49
|
+
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
50
|
+
_defineProperty(this, "tools", new Map());
|
|
51
|
+
this.serverInfo = serverInfo;
|
|
52
|
+
this.protocolVersion = options.protocolVersion || '2025-06-18';
|
|
53
|
+
this.capabilities = _objectSpread({
|
|
54
|
+
tools: _objectSpread({
|
|
55
|
+
listChanged: true
|
|
56
|
+
}, ((_options$capabilities = options.capabilities) === null || _options$capabilities === void 0 ? void 0 : _options$capabilities.tools) || {}),
|
|
57
|
+
resources: {}
|
|
58
|
+
}, options.capabilities || {});
|
|
59
|
+
}
|
|
60
|
+
registerTool(name, config, handler) {
|
|
61
|
+
this.tools.set(name, _objectSpread(_objectSpread({
|
|
62
|
+
name
|
|
63
|
+
}, config), {}, {
|
|
64
|
+
handler
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
getToolDefinitions() {
|
|
68
|
+
return Array.from(this.tools.values()).map(_ref => {
|
|
69
|
+
let {
|
|
70
|
+
handler: _handler
|
|
71
|
+
} = _ref,
|
|
72
|
+
tool = _objectWithoutProperties(_ref, _excluded);
|
|
73
|
+
return _objectSpread(_objectSpread({}, tool), {}, {
|
|
74
|
+
inputSchema: tool.inputSchema || {
|
|
75
|
+
type: 'object',
|
|
76
|
+
properties: {}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
async handleRequest(payload, context) {
|
|
82
|
+
let request;
|
|
83
|
+
try {
|
|
84
|
+
request = JSON.parse(payload);
|
|
85
|
+
} catch (error) {
|
|
86
|
+
return createJsonRpcError(null, -32700, 'Parse error');
|
|
87
|
+
}
|
|
88
|
+
const reqContext = _objectSpread(_objectSpread({}, context), {}, {
|
|
89
|
+
mcpReq: request
|
|
90
|
+
});
|
|
91
|
+
const {
|
|
92
|
+
id = null,
|
|
93
|
+
method,
|
|
94
|
+
params
|
|
95
|
+
} = request;
|
|
96
|
+
switch (method) {
|
|
97
|
+
case 'initialize':
|
|
98
|
+
return JSON.stringify({
|
|
99
|
+
jsonrpc: '2.0',
|
|
100
|
+
id,
|
|
101
|
+
result: {
|
|
102
|
+
protocolVersion: this.protocolVersion,
|
|
103
|
+
capabilities: this.capabilities,
|
|
104
|
+
serverInfo: this.serverInfo
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
case 'notifications/initialized':
|
|
108
|
+
return null;
|
|
109
|
+
case 'tools/list':
|
|
110
|
+
return JSON.stringify({
|
|
111
|
+
jsonrpc: '2.0',
|
|
112
|
+
id,
|
|
113
|
+
result: {
|
|
114
|
+
tools: this.getToolDefinitions()
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
case 'tools/call':
|
|
118
|
+
{
|
|
119
|
+
if (!params || typeof params !== 'object' || Array.isArray(params)) {
|
|
120
|
+
return createJsonRpcError(id, -32602, 'Invalid params: tools/call params must be an object');
|
|
121
|
+
}
|
|
122
|
+
const toolName = params === null || params === void 0 ? void 0 : params.name;
|
|
123
|
+
const args = (params === null || params === void 0 ? void 0 : params.arguments) || {};
|
|
124
|
+
if (typeof toolName !== 'string' || !toolName.trim()) {
|
|
125
|
+
return createJsonRpcError(id, -32602, 'Invalid params: tools/call name must be a non-empty string');
|
|
126
|
+
}
|
|
127
|
+
if (params.arguments !== undefined && (typeof params.arguments !== 'object' || params.arguments === null || Array.isArray(params.arguments))) {
|
|
128
|
+
return createJsonRpcError(id, -32602, 'Invalid params: tools/call arguments must be an object');
|
|
129
|
+
}
|
|
130
|
+
const tool = toolName ? this.tools.get(toolName) : undefined;
|
|
131
|
+
if (!tool) {
|
|
132
|
+
return createJsonRpcError(id, -32601, "Tool not found: ".concat(toolName));
|
|
133
|
+
}
|
|
134
|
+
try {
|
|
135
|
+
const result = await tool.handler(args, reqContext);
|
|
136
|
+
return JSON.stringify({
|
|
137
|
+
jsonrpc: '2.0',
|
|
138
|
+
id,
|
|
139
|
+
result: normalizeToolResult(result)
|
|
140
|
+
});
|
|
141
|
+
} catch (error) {
|
|
142
|
+
return JSON.stringify({
|
|
143
|
+
jsonrpc: '2.0',
|
|
144
|
+
id,
|
|
145
|
+
result: {
|
|
146
|
+
content: [{
|
|
147
|
+
type: 'text',
|
|
148
|
+
text: JSON.stringify({
|
|
149
|
+
status: 'error',
|
|
150
|
+
message: error instanceof Error ? error.message : String(error)
|
|
151
|
+
})
|
|
152
|
+
}],
|
|
153
|
+
isError: true
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
default:
|
|
159
|
+
return createJsonRpcError(id, -32601, "Unknown method: ".concat(method));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { AbortSignalObject } from '@ray-js/t-agent';
|
|
2
|
+
export type JsonRpcId = string | number | null;
|
|
3
|
+
export type JsonPrimitive = string | number | boolean | null;
|
|
4
|
+
export type JsonValue = JsonPrimitive | JsonObject | JsonValue[];
|
|
5
|
+
export interface JsonObject {
|
|
6
|
+
[key: string]: JsonValue;
|
|
7
|
+
}
|
|
8
|
+
export type JsonSchemaTypeName = 'string' | 'number' | 'integer' | 'boolean' | 'object' | 'array' | 'null';
|
|
9
|
+
export interface JsonSchema {
|
|
10
|
+
type?: JsonSchemaTypeName | JsonSchemaTypeName[];
|
|
11
|
+
title?: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
default?: JsonValue;
|
|
14
|
+
examples?: JsonValue[];
|
|
15
|
+
enum?: JsonValue[];
|
|
16
|
+
const?: JsonValue;
|
|
17
|
+
format?: string;
|
|
18
|
+
properties?: Record<string, JsonSchema>;
|
|
19
|
+
required?: string[];
|
|
20
|
+
items?: JsonSchema | JsonSchema[];
|
|
21
|
+
prefixItems?: JsonSchema[];
|
|
22
|
+
additionalProperties?: boolean | JsonSchema;
|
|
23
|
+
oneOf?: JsonSchema[];
|
|
24
|
+
anyOf?: JsonSchema[];
|
|
25
|
+
allOf?: JsonSchema[];
|
|
26
|
+
minimum?: number;
|
|
27
|
+
maximum?: number;
|
|
28
|
+
exclusiveMinimum?: number;
|
|
29
|
+
exclusiveMaximum?: number;
|
|
30
|
+
multipleOf?: number;
|
|
31
|
+
minLength?: number;
|
|
32
|
+
maxLength?: number;
|
|
33
|
+
pattern?: string;
|
|
34
|
+
minItems?: number;
|
|
35
|
+
maxItems?: number;
|
|
36
|
+
uniqueItems?: boolean;
|
|
37
|
+
minProperties?: number;
|
|
38
|
+
maxProperties?: number;
|
|
39
|
+
$defs?: Record<string, JsonSchema>;
|
|
40
|
+
definitions?: Record<string, JsonSchema>;
|
|
41
|
+
$ref?: string;
|
|
42
|
+
}
|
|
43
|
+
export interface JsonRpcRequest<TMethod extends string = string, TParams = any> {
|
|
44
|
+
jsonrpc: '2.0';
|
|
45
|
+
id?: JsonRpcId;
|
|
46
|
+
method: TMethod;
|
|
47
|
+
params?: TParams;
|
|
48
|
+
}
|
|
49
|
+
export interface JsonRpcResponse<TResult = any> {
|
|
50
|
+
jsonrpc: '2.0';
|
|
51
|
+
id: JsonRpcId;
|
|
52
|
+
result?: TResult;
|
|
53
|
+
error?: {
|
|
54
|
+
code: number;
|
|
55
|
+
message: string;
|
|
56
|
+
data?: any;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export interface BaseContext {
|
|
60
|
+
sessionId?: string;
|
|
61
|
+
mcpReq: JsonRpcRequest;
|
|
62
|
+
signal?: AbortSignalObject;
|
|
63
|
+
[key: string]: any;
|
|
64
|
+
}
|
|
65
|
+
export interface McpServerInfo {
|
|
66
|
+
name: string;
|
|
67
|
+
version: string;
|
|
68
|
+
}
|
|
69
|
+
export interface McpServerOptions {
|
|
70
|
+
protocolVersion?: string;
|
|
71
|
+
capabilities?: {
|
|
72
|
+
tools?: {
|
|
73
|
+
listChanged?: boolean;
|
|
74
|
+
};
|
|
75
|
+
resources?: Record<string, any>;
|
|
76
|
+
[key: string]: any;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
export interface McpToolAnnotations {
|
|
80
|
+
title?: string;
|
|
81
|
+
readOnlyHint?: boolean;
|
|
82
|
+
destructiveHint?: boolean;
|
|
83
|
+
idempotentHint?: boolean;
|
|
84
|
+
openWorldHint?: boolean;
|
|
85
|
+
}
|
|
86
|
+
export interface McpToolConfig {
|
|
87
|
+
title?: string;
|
|
88
|
+
description?: string;
|
|
89
|
+
inputSchema?: JsonSchema;
|
|
90
|
+
annotations?: McpToolAnnotations;
|
|
91
|
+
}
|
|
92
|
+
export interface McpTextContent {
|
|
93
|
+
type: 'text';
|
|
94
|
+
text: string;
|
|
95
|
+
}
|
|
96
|
+
export interface McpImageContent {
|
|
97
|
+
type: 'image';
|
|
98
|
+
data: string;
|
|
99
|
+
mimeType: string;
|
|
100
|
+
}
|
|
101
|
+
export type McpContent = McpTextContent | McpImageContent;
|
|
102
|
+
export interface CallToolResult {
|
|
103
|
+
content: McpContent[];
|
|
104
|
+
isError?: boolean;
|
|
105
|
+
structuredContent?: Record<string, any>;
|
|
106
|
+
[key: string]: any;
|
|
107
|
+
}
|
|
108
|
+
export type McpToolHandler<TContext extends BaseContext = BaseContext> = (args: Record<string, any>, context: TContext) => Promise<CallToolResult | Record<string, any> | string | void> | CallToolResult | Record<string, any> | string | void;
|
|
109
|
+
export interface McpToolDefinition extends McpToolConfig {
|
|
110
|
+
name: string;
|
|
111
|
+
}
|
|
112
|
+
export interface McpTool<TContext extends BaseContext = BaseContext> extends McpToolDefinition {
|
|
113
|
+
handler: McpToolHandler<TContext>;
|
|
114
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ChatAgent, GetChatPluginHandler } from '@ray-js/t-agent';
|
|
2
|
+
import { AIStreamPlugin } from '../withAIStream';
|
|
3
|
+
import { SessionEventBody } from '../AIStreamTypes';
|
|
4
|
+
import { McpServer } from './McpServer';
|
|
5
|
+
import { BaseContext } from './types';
|
|
6
|
+
export interface WithMCPOptions<TContext extends BaseContext = BaseContext> {
|
|
7
|
+
createServer: (agent: ChatAgent<AIStreamPlugin>) => McpServer<TContext>;
|
|
8
|
+
createContext?: (event: SessionEventBody, agent: ChatAgent<AIStreamPlugin>) => Omit<TContext, 'mcpReq' | 'sessionId' | 'signal'>;
|
|
9
|
+
}
|
|
10
|
+
export type MCPPlugin = GetChatPluginHandler<typeof withMCP>;
|
|
11
|
+
export declare function withMCP<TContext extends BaseContext = BaseContext>(options: WithMCPOptions<TContext>): (_agent: ChatAgent) => {
|
|
12
|
+
mcp: {
|
|
13
|
+
getServer: () => McpServer<TContext>;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
2
|
+
import "core-js/modules/esnext.iterator.constructor.js";
|
|
3
|
+
import "core-js/modules/esnext.iterator.for-each.js";
|
|
4
|
+
import "core-js/modules/web.dom-collections.iterator.js";
|
|
5
|
+
import { EventType } from '../AIStreamTypes';
|
|
6
|
+
import AbortController from '../utils/abort';
|
|
7
|
+
import { deepmerge } from '@ray-js/t-agent';
|
|
8
|
+
import logger from '../utils/logger';
|
|
9
|
+
export function withMCP(options) {
|
|
10
|
+
return _agent => {
|
|
11
|
+
if (!_agent.plugins.aiStream) {
|
|
12
|
+
throw new Error('withMCP must be used after withAIStream');
|
|
13
|
+
}
|
|
14
|
+
const agent = _agent;
|
|
15
|
+
const {
|
|
16
|
+
createServer,
|
|
17
|
+
createContext
|
|
18
|
+
} = options;
|
|
19
|
+
const {
|
|
20
|
+
onAgentDispose
|
|
21
|
+
} = agent;
|
|
22
|
+
const {
|
|
23
|
+
onUserDataRead,
|
|
24
|
+
onSessionEventReceived,
|
|
25
|
+
sendEvent
|
|
26
|
+
} = agent.plugins.aiStream;
|
|
27
|
+
const pendingMap = new Map();
|
|
28
|
+
let server = null;
|
|
29
|
+
const ensureServer = () => {
|
|
30
|
+
if (!server) {
|
|
31
|
+
server = createServer(agent);
|
|
32
|
+
}
|
|
33
|
+
return server;
|
|
34
|
+
};
|
|
35
|
+
onUserDataRead(async (_type, _data, result) => {
|
|
36
|
+
if (_type !== 'create-session') {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const activeServer = ensureServer();
|
|
40
|
+
result.userData = deepmerge(result.userData, {
|
|
41
|
+
sessionAttributes: {
|
|
42
|
+
deviceMcp: {
|
|
43
|
+
mcpVersion: activeServer.protocolVersion,
|
|
44
|
+
mcpTools: activeServer.getToolDefinitions(),
|
|
45
|
+
supportCustomMCP: true
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
onAgentDispose(() => {
|
|
51
|
+
pendingMap.forEach(controller => controller.abort(new Error('Agent disposed')));
|
|
52
|
+
pendingMap.clear();
|
|
53
|
+
server = null;
|
|
54
|
+
});
|
|
55
|
+
onSessionEventReceived(async event => {
|
|
56
|
+
if (event.eventType !== EventType.MCP_CMD || !event.payload) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const abortController = new AbortController();
|
|
60
|
+
pendingMap.set(event.eventId, abortController);
|
|
61
|
+
try {
|
|
62
|
+
const activeServer = ensureServer();
|
|
63
|
+
const extraContext = createContext ? createContext(event, agent) : {};
|
|
64
|
+
logger.debug('withMCP receive event', {
|
|
65
|
+
sessionId: event.sessionId,
|
|
66
|
+
eventId: event.eventId,
|
|
67
|
+
payload: event.payload
|
|
68
|
+
});
|
|
69
|
+
const response = await activeServer.handleRequest(event.payload, _objectSpread(_objectSpread({}, extraContext), {}, {
|
|
70
|
+
sessionId: event.sessionId,
|
|
71
|
+
signal: abortController.signal,
|
|
72
|
+
eventBody: event
|
|
73
|
+
}));
|
|
74
|
+
if (!response || abortController.signal.aborted) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
logger.debug('withMCP send response', {
|
|
78
|
+
sessionId: event.sessionId,
|
|
79
|
+
eventId: event.eventId,
|
|
80
|
+
payload: response
|
|
81
|
+
});
|
|
82
|
+
await sendEvent({
|
|
83
|
+
sessionId: event.sessionId,
|
|
84
|
+
eventId: event.eventId,
|
|
85
|
+
eventType: EventType.MCP_CMD,
|
|
86
|
+
payload: response
|
|
87
|
+
});
|
|
88
|
+
} finally {
|
|
89
|
+
pendingMap.delete(event.eventId);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
return {
|
|
93
|
+
mcp: {
|
|
94
|
+
getServer: ensureServer
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
}
|
package/dist/utils/AIStream.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AIStreamAudioFile, AIStreamUserData, Attribute, BizTag, ConnectClientType, ConnectState, FileFormat, VideoCameraType } from '../AIStreamTypes';
|
|
1
|
+
import { AIStreamAudioFile, AIStreamUserData, Attribute, BizTag, ConnectClientType, ConnectState, FileFormat, SessionEventBody, VideoCameraType } from '../AIStreamTypes';
|
|
2
2
|
import { AIStreamDataEntry, AIStreamObserverPool } from './observer';
|
|
3
3
|
import { AbortSignalObject } from '@ray-js/t-agent';
|
|
4
4
|
import { AIStreamError } from './errors';
|
|
@@ -49,6 +49,14 @@ interface AIStreamEventOptions {
|
|
|
49
49
|
userData?: Attribute[];
|
|
50
50
|
userDataJson?: string;
|
|
51
51
|
}
|
|
52
|
+
export type AIStreamSessionEventOptions = {
|
|
53
|
+
/** 会话 id */
|
|
54
|
+
sessionId: string;
|
|
55
|
+
/** 事件 id */
|
|
56
|
+
eventId: string;
|
|
57
|
+
/** 扩展属性 */
|
|
58
|
+
payload?: string;
|
|
59
|
+
};
|
|
52
60
|
export declare class AIStreamSession {
|
|
53
61
|
private connection;
|
|
54
62
|
private pool;
|
|
@@ -64,13 +72,18 @@ export declare class AIStreamSession {
|
|
|
64
72
|
[key: string]: any;
|
|
65
73
|
chatId?: string | undefined;
|
|
66
74
|
}>;
|
|
75
|
+
private listeners;
|
|
67
76
|
constructor(connection: AIStreamConnection, pool: AIStreamObserverPool, options: AIStreamSessionOptions);
|
|
68
77
|
ensureSession(): Promise<void>;
|
|
78
|
+
_onSessionEvent: (entry: AIStreamDataEntry) => void;
|
|
69
79
|
_onStateChanged: (entry: AIStreamDataEntry) => void;
|
|
70
80
|
startEvent(options?: AIStreamEventOptions): Promise<AIStreamEvent>;
|
|
71
81
|
private onDataEntry;
|
|
72
82
|
private cleanupEvent;
|
|
73
83
|
cleanup(): void;
|
|
84
|
+
on(name: 'sessionEvent', callback: (body: SessionEventBody) => void): void;
|
|
85
|
+
off(name: 'sessionEvent', callback: (body: SessionEventBody) => void): void;
|
|
86
|
+
private emit;
|
|
74
87
|
close(): Promise<void>;
|
|
75
88
|
}
|
|
76
89
|
type AIStreamEventWriteChunk = {
|
package/dist/utils/AIStream.js
CHANGED
|
@@ -6,7 +6,7 @@ import "core-js/modules/esnext.iterator.find.js";
|
|
|
6
6
|
import "core-js/modules/esnext.iterator.for-each.js";
|
|
7
7
|
import "core-js/modules/esnext.iterator.map.js";
|
|
8
8
|
import "core-js/modules/web.dom-collections.iterator.js";
|
|
9
|
-
import { AIStreamErrorCode, AIStreamServerErrorCode, BizTag, ConnectClientType, ConnectState, EventType, NetworkType, SessionState } from '../AIStreamTypes';
|
|
9
|
+
import { AIStreamAppErrorCode, AIStreamErrorCode, AIStreamServerErrorCode, BizTag, ConnectClientType, ConnectState, EventType, NetworkType, SessionState } from '../AIStreamTypes';
|
|
10
10
|
import { closeSession, connect, createSession, disconnect, getCurrentHomeInfo, getNetworkType, isConnected, queryAgentToken, sendEventChatBreak, sendEventEnd, sendEventPayloadEnd, sendEventStart, sendImageData, sendTextData, startRecordAndSendAudioData, stopRecordAndSendAudioData } from './ttt';
|
|
11
11
|
import { AIStreamObserver, AIStreamObserverPool } from './observer';
|
|
12
12
|
import { isAbortError, safeParseJSON } from '@ray-js/t-agent';
|
|
@@ -47,13 +47,18 @@ export class AIStreamConnection {
|
|
|
47
47
|
// 断开事件触发时只做清理,因为连接已经关掉了
|
|
48
48
|
this.cleanup();
|
|
49
49
|
}
|
|
50
|
-
}
|
|
51
|
-
if (entry.type === 'sessionState') {
|
|
50
|
+
} else if (entry.type === 'sessionState') {
|
|
52
51
|
this.activeSessions.forEach(session => {
|
|
53
52
|
if (session.sessionId && session.sessionId === entry.body.sessionId) {
|
|
54
53
|
session._onStateChanged(entry);
|
|
55
54
|
}
|
|
56
55
|
});
|
|
56
|
+
} else if (entry.type === 'sessionEvent') {
|
|
57
|
+
this.activeSessions.forEach(session => {
|
|
58
|
+
if (session.sessionId && session.sessionId === entry.body.sessionId) {
|
|
59
|
+
session._onSessionEvent(entry);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
57
62
|
}
|
|
58
63
|
});
|
|
59
64
|
this.pool = pool;
|
|
@@ -68,7 +73,8 @@ export class AIStreamConnection {
|
|
|
68
73
|
this.observer = new AIStreamObserver(this.onStateChanged, this.pool);
|
|
69
74
|
this.observer.observe({
|
|
70
75
|
connectionState: true,
|
|
71
|
-
sessionState: true
|
|
76
|
+
sessionState: true,
|
|
77
|
+
sessionEvent: true
|
|
72
78
|
});
|
|
73
79
|
}
|
|
74
80
|
};
|
|
@@ -164,6 +170,15 @@ export class AIStreamSession {
|
|
|
164
170
|
_defineProperty(this, "disposed", false);
|
|
165
171
|
_defineProperty(this, "promise", null);
|
|
166
172
|
_defineProperty(this, "tokenExtParamsResolvable", createResolvable());
|
|
173
|
+
_defineProperty(this, "listeners", {
|
|
174
|
+
sessionEvent: new Set()
|
|
175
|
+
});
|
|
176
|
+
_defineProperty(this, "_onSessionEvent", entry => {
|
|
177
|
+
if (entry.type !== 'sessionEvent') {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
this.emit(entry);
|
|
181
|
+
});
|
|
167
182
|
_defineProperty(this, "_onStateChanged", entry => {
|
|
168
183
|
var _this$activeEvent;
|
|
169
184
|
(_this$activeEvent = this.activeEvent) === null || _this$activeEvent === void 0 || _this$activeEvent.emit('data', entry);
|
|
@@ -262,7 +277,8 @@ export class AIStreamSession {
|
|
|
262
277
|
if (options.getSessionUserData) {
|
|
263
278
|
userData = await options.getSessionUserData();
|
|
264
279
|
}
|
|
265
|
-
|
|
280
|
+
let finErr;
|
|
281
|
+
for (let i = 0; i < 30; i++) {
|
|
266
282
|
const [err, res] = await tryCatchTTT(() => createSession({
|
|
267
283
|
bizTag: options.bizTag,
|
|
268
284
|
agentToken,
|
|
@@ -270,13 +286,31 @@ export class AIStreamSession {
|
|
|
270
286
|
userDataJson: JSON.stringify(userData)
|
|
271
287
|
}));
|
|
272
288
|
if (err) {
|
|
289
|
+
finErr = err;
|
|
290
|
+
if (err.code === AIStreamAppErrorCode.RECONNECT) {
|
|
291
|
+
// 200 毫秒后再试
|
|
292
|
+
await new Promise(resolve => {
|
|
293
|
+
setTimeout(resolve, 200);
|
|
294
|
+
});
|
|
295
|
+
continue;
|
|
296
|
+
} else {
|
|
297
|
+
this.promise = null;
|
|
298
|
+
throw err;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if (res) {
|
|
302
|
+
this.sessionId = res.sessionId;
|
|
303
|
+
this.sendDataChannels = res.sendDataChannels;
|
|
304
|
+
this.revDataChannels = res.revDataChannels;
|
|
273
305
|
this.promise = null;
|
|
274
|
-
|
|
306
|
+
return;
|
|
275
307
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
308
|
+
}
|
|
309
|
+
this.promise = null;
|
|
310
|
+
if (finErr) {
|
|
311
|
+
throw finErr;
|
|
312
|
+
} else {
|
|
313
|
+
throw new AIStreamError('createSession reconnect timeout', AIStreamErrorCode.EVENT_ABORTED);
|
|
280
314
|
}
|
|
281
315
|
})();
|
|
282
316
|
return this.promise;
|
|
@@ -366,6 +400,21 @@ export class AIStreamSession {
|
|
|
366
400
|
this.sendDataChannels = [];
|
|
367
401
|
this.revDataChannels = [];
|
|
368
402
|
}
|
|
403
|
+
on(name, callback) {
|
|
404
|
+
if (name === 'sessionEvent') {
|
|
405
|
+
this.listeners.sessionEvent.add(callback);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
off(name, callback) {
|
|
409
|
+
if (name === 'sessionEvent') {
|
|
410
|
+
this.listeners.sessionEvent.delete(callback);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
emit(data) {
|
|
414
|
+
if (data.type === 'sessionEvent') {
|
|
415
|
+
this.listeners.sessionEvent.forEach(cb => cb(data.body));
|
|
416
|
+
}
|
|
417
|
+
}
|
|
369
418
|
|
|
370
419
|
// 会话关闭清理
|
|
371
420
|
async close() {
|
|
@@ -373,6 +422,7 @@ export class AIStreamSession {
|
|
|
373
422
|
this.disposed = true;
|
|
374
423
|
await this.connection.closeSession(this);
|
|
375
424
|
this.cleanup();
|
|
425
|
+
this.listeners.sessionEvent.clear();
|
|
376
426
|
}
|
|
377
427
|
}
|
|
378
428
|
export class AIStreamEvent {
|