@zhin.js/adapter-milky 6.0.2 → 6.0.5
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/CHANGELOG.md +86 -0
- package/README.md +3 -3
- package/adapters/milky.js +2 -2
- package/adapters/milky.ts +2 -2
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/milky-agent-deps.d.ts +2 -2
- package/lib/milky-agent-deps.js +7 -7
- package/lib/protocol.d.ts +15 -13
- package/lib/protocol.js +27 -30
- package/lib/sse-endpoint.d.ts +2 -5
- package/lib/sse-endpoint.js +27 -28
- package/lib/webhook-endpoint.d.ts +2 -5
- package/lib/webhook-endpoint.js +23 -23
- package/lib/ws-endpoint.d.ts +2 -5
- package/lib/ws-endpoint.js +29 -30
- package/lib/wss-endpoint.d.ts +2 -5
- package/lib/wss-endpoint.js +25 -25
- package/package.json +15 -14
- package/schema.json +41 -5
- package/src/index.ts +1 -6
- package/src/milky-agent-deps.ts +8 -8
- package/src/protocol.ts +34 -37
- package/src/sse-endpoint.ts +30 -30
- package/src/webhook-endpoint.ts +29 -25
- package/src/ws-endpoint.ts +31 -30
- package/src/wss-endpoint.ts +31 -26
- /package/commands/endpoint/add/{[name:string].js → [id].js} +0 -0
- /package/commands/endpoint/add/{[name:string].ts → [id].ts} +0 -0
- /package/commands/endpoint/remove/{[name:string].js → [id].js} +0 -0
- /package/commands/endpoint/remove/{[name:string].ts → [id].ts} +0 -0
package/lib/webhook-endpoint.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { formatCompact,
|
|
1
|
+
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
2
2
|
import { readRequestBody, verifyMilkyAccessToken } from './milky-auth.js';
|
|
3
3
|
import { createMilkyEndpointManagement } from './endpoint-management.js';
|
|
4
4
|
import { registerMilkyAgentEndpoint } from './milky-agent-deps.js';
|
|
5
|
-
import { buildSendAction, callApi, extractInboundAudioUrl, formatInboundContent, formatInboundMessageId, formatInboundSegments,
|
|
6
|
-
const logger = getLogger('milky');
|
|
5
|
+
import { buildSendAction, callApi, extractInboundAudioUrl, formatInboundContent, formatInboundMessageId, formatInboundSegments, formatOutboundMessageId, formatOutboundSegments, isMentioned, milkyInboundConversation, parseMessageReceiveData, parseMilkyMessageId, senderNickname, } from './protocol.js';
|
|
7
6
|
export class MilkyWebhookEndpoint {
|
|
7
|
+
#logger;
|
|
8
8
|
#options;
|
|
9
9
|
#callApi;
|
|
10
10
|
management = createMilkyEndpointManagement(this);
|
|
@@ -13,6 +13,7 @@ export class MilkyWebhookEndpoint {
|
|
|
13
13
|
#started = false;
|
|
14
14
|
#unregisterAgent;
|
|
15
15
|
constructor(options) {
|
|
16
|
+
this.#logger = getAdapterLogger('milky', options.config.id);
|
|
16
17
|
this.#options = options;
|
|
17
18
|
this.#callApi = options.callApi ?? callApi;
|
|
18
19
|
}
|
|
@@ -20,11 +21,11 @@ export class MilkyWebhookEndpoint {
|
|
|
20
21
|
if (this.#started)
|
|
21
22
|
return;
|
|
22
23
|
this.#started = true;
|
|
23
|
-
this.#unregisterAgent = registerMilkyAgentEndpoint(this.#options.config.
|
|
24
|
+
this.#unregisterAgent = registerMilkyAgentEndpoint(this.#options.config.id, this);
|
|
24
25
|
this.#setupRoutes();
|
|
25
|
-
logger.info(formatCompact({
|
|
26
|
+
this.#logger.info(formatCompact({
|
|
26
27
|
op: 'listen',
|
|
27
|
-
endpoint: this.#options.config.
|
|
28
|
+
endpoint: this.#options.config.id,
|
|
28
29
|
mode: 'webhook',
|
|
29
30
|
path: this.#options.config.path,
|
|
30
31
|
}));
|
|
@@ -42,17 +43,17 @@ export class MilkyWebhookEndpoint {
|
|
|
42
43
|
this.#unregisterAgent?.();
|
|
43
44
|
this.#unregisterAgent = undefined;
|
|
44
45
|
this.#started = false;
|
|
45
|
-
logger.debug(formatCompact({ op: 'disconnect'
|
|
46
|
+
this.#logger.debug(formatCompact({ op: 'disconnect' }));
|
|
46
47
|
}
|
|
47
|
-
async send({
|
|
48
|
+
async send({ conversation, payload }) {
|
|
48
49
|
const message = formatOutboundSegments(payload);
|
|
49
|
-
const { action, params } = buildSendAction(
|
|
50
|
+
const { action, params } = buildSendAction(conversation, message);
|
|
50
51
|
const data = await this.callApi(action, params);
|
|
51
|
-
const messageId = formatOutboundMessageId(
|
|
52
|
-
logger.debug(formatCompact({
|
|
52
|
+
const messageId = formatOutboundMessageId(conversation, data?.message_seq);
|
|
53
|
+
this.#logger.debug(formatCompact({
|
|
53
54
|
op: 'milky_send',
|
|
54
|
-
endpoint: this.#options.config.
|
|
55
|
-
target
|
|
55
|
+
endpoint: this.#options.config.id,
|
|
56
|
+
target: `${conversation.kind}:${conversation.id}`,
|
|
56
57
|
messageId,
|
|
57
58
|
}));
|
|
58
59
|
return messageId;
|
|
@@ -144,33 +145,32 @@ export class MilkyWebhookEndpoint {
|
|
|
144
145
|
};
|
|
145
146
|
}
|
|
146
147
|
#admitMessage(data, event) {
|
|
147
|
-
const
|
|
148
|
+
const conversation = milkyInboundConversation(String(this.#options.id), data);
|
|
149
|
+
const target = `${conversation.kind}:${conversation.id}`;
|
|
148
150
|
const content = formatInboundContent(data);
|
|
149
151
|
const segments = formatInboundSegments(data);
|
|
150
152
|
const audioUrl = extractInboundAudioUrl(data);
|
|
151
153
|
const nickname = senderNickname(data);
|
|
152
154
|
const mentioned = isMentioned(data, event.self_id);
|
|
153
155
|
void this.#options.gateway.receive({
|
|
154
|
-
|
|
155
|
-
|
|
156
|
+
conversation,
|
|
157
|
+
message: { conversation, id: formatInboundMessageId(data) },
|
|
156
158
|
content,
|
|
157
159
|
segments,
|
|
158
|
-
sender: String(data.sender_id),
|
|
159
|
-
|
|
160
|
+
sender: { id: String(data.sender_id), name: nickname },
|
|
161
|
+
endpointId: this.#options.config.id,
|
|
162
|
+
...(mentioned ? { mentioned: true } : {}),
|
|
160
163
|
metadata: Object.freeze({
|
|
161
164
|
message_scene: data.message_scene,
|
|
162
165
|
peer_id: String(data.peer_id),
|
|
163
166
|
sender_id: String(data.sender_id),
|
|
164
167
|
message_seq: data.message_seq,
|
|
165
|
-
endpoint: this.#options.config.name,
|
|
166
168
|
time: data.time ?? event.time,
|
|
167
169
|
self_id: event.self_id != null ? String(event.self_id) : undefined,
|
|
168
170
|
...(nickname ? { nickname } : {}),
|
|
169
|
-
...(mentioned ? { mentioned: true } : {}),
|
|
170
|
-
...(audioUrl ? { audio_url: audioUrl } : {}),
|
|
171
171
|
}),
|
|
172
172
|
}).catch((err) => {
|
|
173
|
-
logger.warn(formatCompact({
|
|
173
|
+
this.#logger.warn(formatCompact({
|
|
174
174
|
op: 'milky_gateway_receive_failed',
|
|
175
175
|
target,
|
|
176
176
|
error: err instanceof Error ? err.message : String(err),
|
|
@@ -206,7 +206,7 @@ export class MilkyWebhookEndpoint {
|
|
|
206
206
|
response.end(JSON.stringify({ status: 'ok' }));
|
|
207
207
|
}
|
|
208
208
|
catch (error) {
|
|
209
|
-
logger.error('Milky webhook error:', error);
|
|
209
|
+
this.#logger.error('Milky webhook error:', error);
|
|
210
210
|
if (!response.headersSent) {
|
|
211
211
|
response.writeHead(500, { 'Content-Type': 'application/json' });
|
|
212
212
|
response.end(JSON.stringify({ message: 'Internal Server Error' }));
|
package/lib/ws-endpoint.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type EndpointInstance, type EndpointManagement } from '@zhin.js/adapter';
|
|
1
|
+
import { type EndpointInstance, type EndpointManagement, type EndpointSendRequest } from '@zhin.js/adapter';
|
|
2
2
|
import type { MessageGateway } from '@zhin.js/core/runtime';
|
|
3
3
|
import type { CapabilityId } from '@zhin.js/plugin-runtime';
|
|
4
4
|
import { callApi, type MilkyEvent, type MilkyWsConfig } from './protocol.js';
|
|
@@ -18,10 +18,7 @@ export declare class MilkyWsEndpoint implements EndpointInstance {
|
|
|
18
18
|
open(): void;
|
|
19
19
|
close(): void;
|
|
20
20
|
stop(): Promise<void>;
|
|
21
|
-
send({
|
|
22
|
-
readonly target: string;
|
|
23
|
-
readonly payload: unknown;
|
|
24
|
-
}): Promise<string>;
|
|
21
|
+
send({ conversation, payload }: EndpointSendRequest): Promise<string>;
|
|
25
22
|
/** Public API for agent tools / callers. */
|
|
26
23
|
callApi(action: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
27
24
|
recallMessage(id: string): Promise<void>;
|
package/lib/ws-endpoint.js
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import WebSocket from 'ws';
|
|
5
5
|
import { createEndpointLifecycle, } from '@zhin.js/adapter';
|
|
6
|
-
import { formatCompact,
|
|
6
|
+
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
7
7
|
import { createMilkyEndpointManagement } from './endpoint-management.js';
|
|
8
8
|
import { registerMilkyAgentEndpoint } from './milky-agent-deps.js';
|
|
9
|
-
import { buildSendAction, buildWsConnectOptions, callApi, extractInboundAudioUrl, formatInboundContent, formatInboundMessageId, formatInboundSegments,
|
|
10
|
-
const logger = getLogger('milky');
|
|
9
|
+
import { buildSendAction, buildWsConnectOptions, callApi, extractInboundAudioUrl, formatInboundContent, formatInboundMessageId, formatInboundSegments, formatOutboundMessageId, formatOutboundSegments, isMentioned, milkyInboundConversation, parseMessageReceiveData, parseMilkyMessageId, senderNickname, } from './protocol.js';
|
|
11
10
|
const WS_OPEN = 1;
|
|
12
11
|
export class MilkyWsEndpoint {
|
|
12
|
+
#logger;
|
|
13
13
|
#options;
|
|
14
14
|
#callApi;
|
|
15
15
|
management = createMilkyEndpointManagement(this);
|
|
@@ -18,10 +18,11 @@ export class MilkyWsEndpoint {
|
|
|
18
18
|
#open = false;
|
|
19
19
|
#unregisterAgent;
|
|
20
20
|
constructor(options) {
|
|
21
|
+
this.#logger = getAdapterLogger('milky', options.config.id);
|
|
21
22
|
this.#options = options;
|
|
22
23
|
this.#callApi = options.callApi ?? callApi;
|
|
23
24
|
this.#lifecycle = createEndpointLifecycle({
|
|
24
|
-
name: options.config.
|
|
25
|
+
name: options.config.id,
|
|
25
26
|
// reconnect_interval 旧语义为固定间隔:multiplier 1 + 无 jitter + 不封顶
|
|
26
27
|
reconnect: {
|
|
27
28
|
initialIntervalMs: options.config.reconnect_interval,
|
|
@@ -34,7 +35,7 @@ export class MilkyWsEndpoint {
|
|
|
34
35
|
async start() {
|
|
35
36
|
if (this.#lifecycle.started)
|
|
36
37
|
return;
|
|
37
|
-
this.#unregisterAgent = registerMilkyAgentEndpoint(this.#options.config.
|
|
38
|
+
this.#unregisterAgent = registerMilkyAgentEndpoint(this.#options.config.id, this);
|
|
38
39
|
try {
|
|
39
40
|
await this.#lifecycle.start((handle) => this.#connect(handle));
|
|
40
41
|
}
|
|
@@ -66,15 +67,15 @@ export class MilkyWsEndpoint {
|
|
|
66
67
|
this.#ws = undefined;
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
|
-
async send({
|
|
70
|
+
async send({ conversation, payload }) {
|
|
70
71
|
const message = formatOutboundSegments(payload);
|
|
71
|
-
const { action, params } = buildSendAction(
|
|
72
|
+
const { action, params } = buildSendAction(conversation, message);
|
|
72
73
|
const data = await this.callApi(action, params);
|
|
73
|
-
const messageId = formatOutboundMessageId(
|
|
74
|
-
logger.debug(formatCompact({
|
|
74
|
+
const messageId = formatOutboundMessageId(conversation, data?.message_seq);
|
|
75
|
+
this.#logger.debug(formatCompact({
|
|
75
76
|
op: 'milky_send',
|
|
76
|
-
endpoint: this.#options.config.
|
|
77
|
-
target
|
|
77
|
+
endpoint: this.#options.config.id,
|
|
78
|
+
target: `${conversation.kind}:${conversation.id}`,
|
|
78
79
|
messageId,
|
|
79
80
|
}));
|
|
80
81
|
return messageId;
|
|
@@ -168,33 +169,32 @@ export class MilkyWsEndpoint {
|
|
|
168
169
|
};
|
|
169
170
|
}
|
|
170
171
|
#admitMessage(data, event) {
|
|
171
|
-
const
|
|
172
|
+
const conversation = milkyInboundConversation(String(this.#options.id), data);
|
|
173
|
+
const target = `${conversation.kind}:${conversation.id}`;
|
|
172
174
|
const content = formatInboundContent(data);
|
|
173
175
|
const segments = formatInboundSegments(data);
|
|
174
176
|
const audioUrl = extractInboundAudioUrl(data);
|
|
175
177
|
const nickname = senderNickname(data);
|
|
176
178
|
const mentioned = isMentioned(data, event.self_id);
|
|
177
179
|
void this.#options.gateway.receive({
|
|
178
|
-
|
|
179
|
-
|
|
180
|
+
conversation,
|
|
181
|
+
message: { conversation, id: formatInboundMessageId(data) },
|
|
180
182
|
content,
|
|
181
183
|
segments,
|
|
182
|
-
sender: String(data.sender_id),
|
|
183
|
-
|
|
184
|
+
sender: { id: String(data.sender_id), name: nickname },
|
|
185
|
+
endpointId: this.#options.config.id,
|
|
186
|
+
...(mentioned ? { mentioned: true } : {}),
|
|
184
187
|
metadata: Object.freeze({
|
|
185
188
|
message_scene: data.message_scene,
|
|
186
189
|
peer_id: String(data.peer_id),
|
|
187
190
|
sender_id: String(data.sender_id),
|
|
188
191
|
message_seq: data.message_seq,
|
|
189
|
-
endpoint: this.#options.config.name,
|
|
190
192
|
time: data.time ?? event.time,
|
|
191
193
|
self_id: event.self_id != null ? String(event.self_id) : undefined,
|
|
192
194
|
...(nickname ? { nickname } : {}),
|
|
193
|
-
...(mentioned ? { mentioned: true } : {}),
|
|
194
|
-
...(audioUrl ? { audio_url: audioUrl } : {}),
|
|
195
195
|
}),
|
|
196
196
|
}).catch((err) => {
|
|
197
|
-
logger.warn(formatCompact({
|
|
197
|
+
this.#logger.warn(formatCompact({
|
|
198
198
|
op: 'milky_gateway_receive_failed',
|
|
199
199
|
target,
|
|
200
200
|
error: err instanceof Error ? err.message : String(err),
|
|
@@ -222,14 +222,14 @@ export class MilkyWsEndpoint {
|
|
|
222
222
|
return;
|
|
223
223
|
settled = true;
|
|
224
224
|
if (!this.#options.config.access_token) {
|
|
225
|
-
logger.warn(formatCompact({
|
|
226
|
-
endpoint: this.#options.config.
|
|
225
|
+
this.#logger.warn(formatCompact({
|
|
226
|
+
endpoint: this.#options.config.id,
|
|
227
227
|
ok: false,
|
|
228
228
|
error: 'missing access_token',
|
|
229
229
|
}));
|
|
230
230
|
}
|
|
231
|
-
logger.debug(formatCompact({
|
|
232
|
-
endpoint: this.#options.config.
|
|
231
|
+
this.#logger.debug(formatCompact({
|
|
232
|
+
endpoint: this.#options.config.id,
|
|
233
233
|
mode: 'ws',
|
|
234
234
|
url: safeUrl,
|
|
235
235
|
}));
|
|
@@ -262,9 +262,8 @@ export class MilkyWsEndpoint {
|
|
|
262
262
|
: codeNum === 1006
|
|
263
263
|
? ' [异常关闭]'
|
|
264
264
|
: '';
|
|
265
|
-
logger.warn(formatCompact({
|
|
265
|
+
this.#logger.warn(formatCompact({
|
|
266
266
|
op: 'disconnect',
|
|
267
|
-
endpoint: this.#options.config.name,
|
|
268
267
|
code: codeNum,
|
|
269
268
|
error: `${reasonStr || 'closed'}${codeHint}`,
|
|
270
269
|
reconnect_ms: this.#options.config.reconnect_interval,
|
|
@@ -278,9 +277,9 @@ export class MilkyWsEndpoint {
|
|
|
278
277
|
});
|
|
279
278
|
ws.on('error', (err) => {
|
|
280
279
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
281
|
-
logger.warn(formatCompact({
|
|
280
|
+
this.#logger.warn(formatCompact({
|
|
282
281
|
op: 'ws_error',
|
|
283
|
-
endpoint: this.#options.config.
|
|
282
|
+
endpoint: this.#options.config.id,
|
|
284
283
|
ok: false,
|
|
285
284
|
error: error.message,
|
|
286
285
|
}));
|
|
@@ -304,9 +303,9 @@ export class MilkyWsEndpoint {
|
|
|
304
303
|
this.admit(event);
|
|
305
304
|
}
|
|
306
305
|
catch (error) {
|
|
307
|
-
logger.warn(formatCompact({
|
|
306
|
+
this.#logger.warn(formatCompact({
|
|
308
307
|
op: 'milky_parse_failed',
|
|
309
|
-
endpoint: this.#options.config.
|
|
308
|
+
endpoint: this.#options.config.id,
|
|
310
309
|
error: error instanceof Error ? error.message : String(error),
|
|
311
310
|
}));
|
|
312
311
|
}
|
package/lib/wss-endpoint.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { EndpointInstance, EndpointManagement } from '@zhin.js/adapter';
|
|
1
|
+
import type { EndpointInstance, EndpointManagement, EndpointSendRequest } from '@zhin.js/adapter';
|
|
2
2
|
import type { MessageGateway } from '@zhin.js/core/runtime';
|
|
3
3
|
import type { HttpHost } from '@zhin.js/host-http';
|
|
4
4
|
import type { CapabilityId } from '@zhin.js/plugin-runtime';
|
|
@@ -18,10 +18,7 @@ export declare class MilkyWssEndpoint implements EndpointInstance {
|
|
|
18
18
|
open(): void;
|
|
19
19
|
close(): void;
|
|
20
20
|
stop(): Promise<void>;
|
|
21
|
-
send({
|
|
22
|
-
readonly target: string;
|
|
23
|
-
readonly payload: unknown;
|
|
24
|
-
}): Promise<string>;
|
|
21
|
+
send({ conversation, payload }: EndpointSendRequest): Promise<string>;
|
|
25
22
|
callApi(action: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
26
23
|
recallMessage(id: string): Promise<void>;
|
|
27
24
|
kickMember(groupId: number, userId: number, rejectAddRequest?: boolean): Promise<boolean>;
|
package/lib/wss-endpoint.js
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
* Milky reverse WSS endpoint — httpHostToken WS upgrade inbound + baseUrl HTTP API outbound.
|
|
3
3
|
*/
|
|
4
4
|
import { clearInterval } from 'node:timers';
|
|
5
|
-
import { formatCompact,
|
|
5
|
+
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
6
6
|
import { verifyMilkyAccessToken } from './milky-auth.js';
|
|
7
7
|
import { createMilkyEndpointManagement } from './endpoint-management.js';
|
|
8
8
|
import { registerMilkyAgentEndpoint } from './milky-agent-deps.js';
|
|
9
|
-
import { buildSendAction, callApi, extractInboundAudioUrl, formatInboundContent, formatInboundMessageId, formatInboundSegments,
|
|
10
|
-
const logger = getLogger('milky');
|
|
9
|
+
import { buildSendAction, callApi, extractInboundAudioUrl, formatInboundContent, formatInboundMessageId, formatInboundSegments, formatOutboundMessageId, formatOutboundSegments, isMentioned, milkyInboundConversation, parseMessageReceiveData, parseMilkyMessageId, senderNickname, } from './protocol.js';
|
|
11
10
|
const WS_OPEN = 1;
|
|
12
11
|
export class MilkyWssEndpoint {
|
|
12
|
+
#logger;
|
|
13
13
|
#options;
|
|
14
14
|
#callApi;
|
|
15
15
|
management = createMilkyEndpointManagement(this);
|
|
@@ -20,6 +20,7 @@ export class MilkyWssEndpoint {
|
|
|
20
20
|
#started = false;
|
|
21
21
|
#unregisterAgent;
|
|
22
22
|
constructor(options) {
|
|
23
|
+
this.#logger = getAdapterLogger('milky', options.config.id);
|
|
23
24
|
this.#options = options;
|
|
24
25
|
this.#callApi = options.callApi ?? callApi;
|
|
25
26
|
}
|
|
@@ -27,14 +28,14 @@ export class MilkyWssEndpoint {
|
|
|
27
28
|
if (this.#started)
|
|
28
29
|
return;
|
|
29
30
|
this.#started = true;
|
|
30
|
-
this.#unregisterAgent = registerMilkyAgentEndpoint(this.#options.config.
|
|
31
|
+
this.#unregisterAgent = registerMilkyAgentEndpoint(this.#options.config.id, this);
|
|
31
32
|
const handle = this.#options.http.ws(this.#options.config.path);
|
|
32
33
|
this.#wsRelease = handle.onConnection((connection) => {
|
|
33
34
|
this.#acceptConnection(connection);
|
|
34
35
|
});
|
|
35
|
-
logger.info(formatCompact({
|
|
36
|
+
this.#logger.info(formatCompact({
|
|
36
37
|
op: 'listen',
|
|
37
|
-
endpoint: this.#options.config.
|
|
38
|
+
endpoint: this.#options.config.id,
|
|
38
39
|
mode: 'wss',
|
|
39
40
|
path: this.#options.config.path,
|
|
40
41
|
}));
|
|
@@ -66,15 +67,15 @@ export class MilkyWssEndpoint {
|
|
|
66
67
|
}
|
|
67
68
|
this.#started = false;
|
|
68
69
|
}
|
|
69
|
-
async send({
|
|
70
|
+
async send({ conversation, payload }) {
|
|
70
71
|
const message = formatOutboundSegments(payload);
|
|
71
|
-
const { action, params } = buildSendAction(
|
|
72
|
+
const { action, params } = buildSendAction(conversation, message);
|
|
72
73
|
const data = await this.callApi(action, params);
|
|
73
|
-
const messageId = formatOutboundMessageId(
|
|
74
|
-
logger.debug(formatCompact({
|
|
74
|
+
const messageId = formatOutboundMessageId(conversation, data?.message_seq);
|
|
75
|
+
this.#logger.debug(formatCompact({
|
|
75
76
|
op: 'milky_send',
|
|
76
|
-
endpoint: this.#options.config.
|
|
77
|
-
target
|
|
77
|
+
endpoint: this.#options.config.id,
|
|
78
|
+
target: `${conversation.kind}:${conversation.id}`,
|
|
78
79
|
messageId,
|
|
79
80
|
}));
|
|
80
81
|
return messageId;
|
|
@@ -166,33 +167,32 @@ export class MilkyWssEndpoint {
|
|
|
166
167
|
};
|
|
167
168
|
}
|
|
168
169
|
#admitMessage(data, event) {
|
|
169
|
-
const
|
|
170
|
+
const conversation = milkyInboundConversation(String(this.#options.id), data);
|
|
171
|
+
const target = `${conversation.kind}:${conversation.id}`;
|
|
170
172
|
const content = formatInboundContent(data);
|
|
171
173
|
const segments = formatInboundSegments(data);
|
|
172
174
|
const audioUrl = extractInboundAudioUrl(data);
|
|
173
175
|
const nickname = senderNickname(data);
|
|
174
176
|
const mentioned = isMentioned(data, event.self_id);
|
|
175
177
|
void this.#options.gateway.receive({
|
|
176
|
-
|
|
177
|
-
|
|
178
|
+
conversation,
|
|
179
|
+
message: { conversation, id: formatInboundMessageId(data) },
|
|
178
180
|
content,
|
|
179
181
|
segments,
|
|
180
|
-
sender: String(data.sender_id),
|
|
181
|
-
|
|
182
|
+
sender: { id: String(data.sender_id) },
|
|
183
|
+
endpointId: this.#options.config.id,
|
|
184
|
+
...(mentioned ? { mentioned: true } : {}),
|
|
182
185
|
metadata: Object.freeze({
|
|
183
186
|
message_scene: data.message_scene,
|
|
184
187
|
peer_id: String(data.peer_id),
|
|
185
188
|
sender_id: String(data.sender_id),
|
|
186
189
|
message_seq: data.message_seq,
|
|
187
|
-
endpoint: this.#options.config.name,
|
|
188
190
|
time: data.time ?? event.time,
|
|
189
191
|
self_id: event.self_id != null ? String(event.self_id) : undefined,
|
|
190
192
|
...(nickname ? { nickname } : {}),
|
|
191
|
-
...(mentioned ? { mentioned: true } : {}),
|
|
192
|
-
...(audioUrl ? { audio_url: audioUrl } : {}),
|
|
193
193
|
}),
|
|
194
194
|
}).catch((err) => {
|
|
195
|
-
logger.warn(formatCompact({
|
|
195
|
+
this.#logger.warn(formatCompact({
|
|
196
196
|
op: 'milky_gateway_receive_failed',
|
|
197
197
|
target,
|
|
198
198
|
error: err instanceof Error ? err.message : String(err),
|
|
@@ -222,8 +222,8 @@ export class MilkyWssEndpoint {
|
|
|
222
222
|
if (this.#ws === socket)
|
|
223
223
|
this.#ws = undefined;
|
|
224
224
|
});
|
|
225
|
-
logger.debug(formatCompact({
|
|
226
|
-
endpoint: this.#options.config.
|
|
225
|
+
this.#logger.debug(formatCompact({
|
|
226
|
+
endpoint: this.#options.config.id,
|
|
227
227
|
mode: 'wss',
|
|
228
228
|
peer: connection.request.socket.remoteAddress,
|
|
229
229
|
}));
|
|
@@ -241,9 +241,9 @@ export class MilkyWssEndpoint {
|
|
|
241
241
|
this.admit(event);
|
|
242
242
|
}
|
|
243
243
|
catch (error) {
|
|
244
|
-
logger.warn(formatCompact({
|
|
244
|
+
this.#logger.warn(formatCompact({
|
|
245
245
|
op: 'milky_parse_failed',
|
|
246
|
-
endpoint: this.#options.config.
|
|
246
|
+
endpoint: this.#options.config.id,
|
|
247
247
|
error: error instanceof Error ? error.message : String(error),
|
|
248
248
|
}));
|
|
249
249
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-milky",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.5",
|
|
4
4
|
"description": "Zhin.js Milky adapter for Plugin Runtime (WebSocket client)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -40,12 +40,13 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"ws": "^8.21.1",
|
|
43
|
-
"@zhin.js/adapter": "1.1.
|
|
44
|
-
"@zhin.js/command": "1.0.
|
|
45
|
-
"@zhin.js/core": "1.5.
|
|
46
|
-
"@zhin.js/host-http": "1.0.
|
|
47
|
-
"@zhin.js/
|
|
48
|
-
"@zhin.js/
|
|
43
|
+
"@zhin.js/adapter": "1.1.7",
|
|
44
|
+
"@zhin.js/command": "1.0.9",
|
|
45
|
+
"@zhin.js/core": "1.5.4",
|
|
46
|
+
"@zhin.js/host-http": "1.0.8",
|
|
47
|
+
"@zhin.js/im-contract": "1.0.3",
|
|
48
|
+
"@zhin.js/logger": "1.0.76",
|
|
49
|
+
"@zhin.js/plugin-runtime": "1.1.5"
|
|
49
50
|
},
|
|
50
51
|
"devDependencies": {
|
|
51
52
|
"@types/node": "^26.1.2",
|
|
@@ -53,16 +54,16 @@
|
|
|
53
54
|
"typescript": "^6.0.3",
|
|
54
55
|
"vitest": "^4.1.10",
|
|
55
56
|
"zod": "^4.4.3",
|
|
56
|
-
"@zhin.js/agent": "1.1.
|
|
57
|
-
"@zhin.js/host-http": "1.0.
|
|
57
|
+
"@zhin.js/agent": "1.1.5",
|
|
58
|
+
"@zhin.js/host-http": "1.0.8"
|
|
58
59
|
},
|
|
59
60
|
"peerDependencies": {
|
|
60
61
|
"zod": "^4.0.0",
|
|
61
|
-
"@zhin.js/adapter": "1.1.
|
|
62
|
-
"@zhin.js/agent": "1.1.
|
|
63
|
-
"@zhin.js/core": "1.5.
|
|
64
|
-
"@zhin.js/plugin-runtime": "1.1.
|
|
65
|
-
"zhin.js": "6.0.
|
|
62
|
+
"@zhin.js/adapter": "1.1.7",
|
|
63
|
+
"@zhin.js/agent": "1.1.5",
|
|
64
|
+
"@zhin.js/core": "1.5.4",
|
|
65
|
+
"@zhin.js/plugin-runtime": "1.1.5",
|
|
66
|
+
"zhin.js": "6.0.4"
|
|
66
67
|
},
|
|
67
68
|
"peerDependenciesMeta": {
|
|
68
69
|
"zhin.js": {
|
package/schema.json
CHANGED
|
@@ -22,16 +22,48 @@
|
|
|
22
22
|
"type": "number",
|
|
23
23
|
"default": 30000
|
|
24
24
|
},
|
|
25
|
+
"master": {
|
|
26
|
+
"type": [
|
|
27
|
+
"string",
|
|
28
|
+
"number"
|
|
29
|
+
],
|
|
30
|
+
"description": "框架 master(QQ uin;AI/工具权限、endpoint 管理)。endpoints[i].master 可逐项覆盖"
|
|
31
|
+
},
|
|
32
|
+
"trusted": {
|
|
33
|
+
"type": "array",
|
|
34
|
+
"items": {
|
|
35
|
+
"type": [
|
|
36
|
+
"string",
|
|
37
|
+
"number"
|
|
38
|
+
],
|
|
39
|
+
"description": "Trusted QQ uin"
|
|
40
|
+
},
|
|
41
|
+
"description": "框架 trusted 用户列表(弱于 master)。endpoints[i].trusted 可逐项追加"
|
|
42
|
+
},
|
|
25
43
|
"endpoints": {
|
|
26
44
|
"type": "array",
|
|
27
|
-
"description": "多账号:一个插件实例挂多个 endpoint。每项与顶层字段同构(
|
|
45
|
+
"description": "多账号:一个插件实例挂多个 endpoint。每项与顶层字段同构(id 必填,其余覆盖顶层)",
|
|
28
46
|
"items": {
|
|
29
47
|
"type": "object",
|
|
30
48
|
"additionalProperties": true,
|
|
31
49
|
"properties": {
|
|
32
|
-
"
|
|
33
|
-
"type":
|
|
34
|
-
|
|
50
|
+
"master": {
|
|
51
|
+
"type": [
|
|
52
|
+
"string",
|
|
53
|
+
"number"
|
|
54
|
+
],
|
|
55
|
+
"description": "本 endpoint 的框架 master(QQ uin);覆盖顶层 master"
|
|
56
|
+
},
|
|
57
|
+
"trusted": {
|
|
58
|
+
"type": "array",
|
|
59
|
+
"items": {
|
|
60
|
+
"type": [
|
|
61
|
+
"string",
|
|
62
|
+
"number"
|
|
63
|
+
],
|
|
64
|
+
"description": "Trusted QQ uin"
|
|
65
|
+
},
|
|
66
|
+
"description": "本 endpoint 的 trusted 列表"
|
|
35
67
|
},
|
|
36
68
|
"baseUrl": {
|
|
37
69
|
"type": "string",
|
|
@@ -44,10 +76,14 @@
|
|
|
44
76
|
"access_token": {
|
|
45
77
|
"type": "string",
|
|
46
78
|
"description": "Milky access token"
|
|
79
|
+
},
|
|
80
|
+
"id": {
|
|
81
|
+
"type": "string",
|
|
82
|
+
"description": "Milky bot name"
|
|
47
83
|
}
|
|
48
84
|
},
|
|
49
85
|
"required": [
|
|
50
|
-
"
|
|
86
|
+
"id",
|
|
51
87
|
"baseUrl"
|
|
52
88
|
]
|
|
53
89
|
}
|
package/src/index.ts
CHANGED
|
@@ -5,15 +5,11 @@ export {
|
|
|
5
5
|
callApi,
|
|
6
6
|
extractInboundAudioUrl,
|
|
7
7
|
formatInboundContent,
|
|
8
|
-
formatInboundMessageId,
|
|
9
|
-
formatInboundTarget,
|
|
10
|
-
formatOutboundMessageId,
|
|
11
8
|
formatOutboundSegments,
|
|
12
9
|
isMentioned,
|
|
13
10
|
isMessageReceiveEvent,
|
|
11
|
+
milkyInboundConversation,
|
|
14
12
|
parseMessageReceiveData,
|
|
15
|
-
parseMilkyMessageId,
|
|
16
|
-
parseSendTarget,
|
|
17
13
|
resolveMilkyConfig,
|
|
18
14
|
senderNickname,
|
|
19
15
|
type MilkyAdapterConfig,
|
|
@@ -30,7 +26,6 @@ export {
|
|
|
30
26
|
type MilkyWireSegment,
|
|
31
27
|
type MilkyWsConfig,
|
|
32
28
|
type MilkyWssConfig,
|
|
33
|
-
type ParsedSendTarget,
|
|
34
29
|
type ResolvedMilkyConfig,
|
|
35
30
|
} from './protocol.js';
|
|
36
31
|
|
package/src/milky-agent-deps.ts
CHANGED
|
@@ -18,20 +18,20 @@ export interface MilkyAgentEndpoint {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export interface MilkyAgentDeps {
|
|
21
|
-
getEndpoint: (
|
|
21
|
+
getEndpoint: (endpointKey: string) => MilkyAgentEndpoint;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
const endpoints = new Map<string, MilkyAgentEndpoint>();
|
|
25
25
|
let override: MilkyAgentDeps | null = null;
|
|
26
26
|
|
|
27
27
|
export function registerMilkyAgentEndpoint(
|
|
28
|
-
|
|
28
|
+
endpointKey: string,
|
|
29
29
|
endpoint: MilkyAgentEndpoint,
|
|
30
30
|
): () => void {
|
|
31
|
-
endpoints.set(
|
|
31
|
+
endpoints.set(endpointKey, endpoint);
|
|
32
32
|
return () => {
|
|
33
|
-
if (endpoints.get(
|
|
34
|
-
endpoints.delete(
|
|
33
|
+
if (endpoints.get(endpointKey) === endpoint) {
|
|
34
|
+
endpoints.delete(endpointKey);
|
|
35
35
|
}
|
|
36
36
|
};
|
|
37
37
|
}
|
|
@@ -44,9 +44,9 @@ export function setMilkyAgentDeps(deps: MilkyAgentDeps | null): void {
|
|
|
44
44
|
export function getMilkyAgentDeps(): MilkyAgentDeps {
|
|
45
45
|
if (override) return override;
|
|
46
46
|
return {
|
|
47
|
-
getEndpoint(
|
|
48
|
-
const registered = endpoints.get(
|
|
49
|
-
if (!registered) throw new Error(`Endpoint ${
|
|
47
|
+
getEndpoint(endpointKey: string): MilkyAgentEndpoint {
|
|
48
|
+
const registered = endpoints.get(endpointKey);
|
|
49
|
+
if (!registered) throw new Error(`Endpoint ${endpointKey} 不存在`);
|
|
50
50
|
return registered;
|
|
51
51
|
},
|
|
52
52
|
};
|