@zhin.js/adapter-milky 6.0.3 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/adapter-milky",
3
- "version": "6.0.3",
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,13 +40,13 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "ws": "^8.21.1",
43
- "@zhin.js/adapter": "1.1.5",
44
- "@zhin.js/command": "1.0.7",
45
- "@zhin.js/core": "1.5.2",
46
- "@zhin.js/host-http": "1.0.6",
47
- "@zhin.js/im-contract": "1.0.1",
48
- "@zhin.js/logger": "1.0.75",
49
- "@zhin.js/plugin-runtime": "1.1.3"
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"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@types/node": "^26.1.2",
@@ -54,16 +54,16 @@
54
54
  "typescript": "^6.0.3",
55
55
  "vitest": "^4.1.10",
56
56
  "zod": "^4.4.3",
57
- "@zhin.js/agent": "1.1.3",
58
- "@zhin.js/host-http": "1.0.6"
57
+ "@zhin.js/agent": "1.1.5",
58
+ "@zhin.js/host-http": "1.0.8"
59
59
  },
60
60
  "peerDependencies": {
61
61
  "zod": "^4.0.0",
62
- "@zhin.js/adapter": "1.1.5",
63
- "@zhin.js/agent": "1.1.3",
64
- "@zhin.js/core": "1.5.2",
65
- "@zhin.js/plugin-runtime": "1.1.3",
66
- "zhin.js": "6.0.2"
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"
67
67
  },
68
68
  "peerDependenciesMeta": {
69
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。每项与顶层字段同构(name 必填,其余覆盖顶层)",
45
+ "description": "多账号:一个插件实例挂多个 endpoint。每项与顶层字段同构(id 必填,其余覆盖顶层)",
28
46
  "items": {
29
47
  "type": "object",
30
48
  "additionalProperties": true,
31
49
  "properties": {
32
- "name": {
33
- "type": "string",
34
- "description": "Milky bot name"
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
- "name",
86
+ "id",
51
87
  "baseUrl"
52
88
  ]
53
89
  }
@@ -18,20 +18,20 @@ export interface MilkyAgentEndpoint {
18
18
  }
19
19
 
20
20
  export interface MilkyAgentDeps {
21
- getEndpoint: (endpointId: string) => MilkyAgentEndpoint;
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
- endpointId: string,
28
+ endpointKey: string,
29
29
  endpoint: MilkyAgentEndpoint,
30
30
  ): () => void {
31
- endpoints.set(endpointId, endpoint);
31
+ endpoints.set(endpointKey, endpoint);
32
32
  return () => {
33
- if (endpoints.get(endpointId) === endpoint) {
34
- endpoints.delete(endpointId);
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(endpointId: string): MilkyAgentEndpoint {
48
- const registered = endpoints.get(endpointId);
49
- if (!registered) throw new Error(`Endpoint ${endpointId} 不存在`);
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
  };
package/src/protocol.ts CHANGED
@@ -15,7 +15,7 @@ const logger = getLogger('milky');
15
15
  export interface MilkyLegacyEndpointRow {
16
16
  readonly context?: string;
17
17
  readonly connection?: 'ws' | 'sse' | 'webhook' | 'wss';
18
- readonly name?: string;
18
+ readonly id?: string;
19
19
  readonly baseUrl?: string;
20
20
  readonly access_token?: string;
21
21
  readonly path?: string;
@@ -26,7 +26,7 @@ export interface MilkyLegacyEndpointRow {
26
26
  /** Plugin Runtime owner config (`plugins.<instanceKey>` / schema.json). */
27
27
  export interface MilkyAdapterConfig {
28
28
  readonly connection?: 'ws' | 'sse' | 'webhook' | 'wss';
29
- readonly name?: string;
29
+ readonly id?: string;
30
30
  readonly baseUrl?: string;
31
31
  readonly access_token?: string;
32
32
  readonly path?: string;
@@ -38,7 +38,7 @@ export interface MilkyAdapterConfig {
38
38
 
39
39
  export interface MilkyConfigBase {
40
40
  readonly context: 'milky';
41
- readonly name: string;
41
+ readonly id: string;
42
42
  readonly baseUrl: string;
43
43
  readonly access_token?: string;
44
44
  }
@@ -130,8 +130,8 @@ function normalizeConnection(connection: string | undefined): 'ws' | 'sse' | 'we
130
130
  export function resolveMilkyConfig(config: MilkyAdapterConfig = {}): ResolvedMilkyConfig {
131
131
  const entry = config.endpoints?.find((item) => item.context === 'milky');
132
132
  const connection = normalizeConnection(config.connection ?? entry?.connection);
133
- const name = (typeof config.name === 'string' && config.name)
134
- || (typeof entry?.name === 'string' && entry.name)
133
+ const id = (typeof config.id === 'string' && config.id)
134
+ || (typeof entry?.id === 'string' && entry.id)
135
135
  || process.env.MILKY_BOT_NAME
136
136
  || 'milky-bot';
137
137
  const baseUrl = config.baseUrl ?? entry?.baseUrl;
@@ -143,7 +143,7 @@ export function resolveMilkyConfig(config: MilkyAdapterConfig = {}): ResolvedMil
143
143
  const access_token = config.access_token ?? entry?.access_token;
144
144
  const base = {
145
145
  context: 'milky' as const,
146
- name,
146
+ id,
147
147
  baseUrl,
148
148
  access_token,
149
149
  };
@@ -262,11 +262,11 @@ export function isMessageReceiveEvent(
262
262
  * `temp`(群临时会话)→ 群容器内的 `private` 会话(parent = 来源群)。
263
263
  */
264
264
  export function milkyInboundConversation(
265
- endpointId: string,
265
+ endpointKey: string,
266
266
  data: MilkyIncomingMessage,
267
267
  ): ConversationRef {
268
268
  return {
269
- endpoint: { id: endpointId, adapter: endpointId.split('\0')[0] ?? endpointId },
269
+ endpoint: { id: endpointKey, adapter: endpointKey.split('\0')[0] ?? endpointKey },
270
270
  kind: data.message_scene === 'group' ? 'group' : 'private',
271
271
  id: String(data.peer_id),
272
272
  ...(data.message_scene === 'temp' && data.group
@@ -10,7 +10,7 @@ import {
10
10
  type EndpointSendRequest,
11
11
  } from '@zhin.js/adapter';
12
12
  import type { MessageGateway } from '@zhin.js/core/runtime';
13
- import { formatCompact, getLogger } from '@zhin.js/logger';
13
+ import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
14
14
  import type { CapabilityId } from '@zhin.js/plugin-runtime';
15
15
  import { createMilkyEndpointManagement } from './endpoint-management.js';
16
16
  import { registerMilkyAgentEndpoint } from './milky-agent-deps.js';
@@ -35,8 +35,6 @@ import {
35
35
  } from './protocol.js';
36
36
  import { openSseStream, type SseClientHandle } from './sse-client.js';
37
37
 
38
- const logger = getLogger('milky');
39
-
40
38
  export type CreateMilkySseStream = (options: {
41
39
  readonly url: string;
42
40
  readonly headers: Record<string, string>;
@@ -54,6 +52,8 @@ export interface MilkySseEndpointOptions {
54
52
  }
55
53
 
56
54
  export class MilkySseEndpoint implements EndpointInstance {
55
+ readonly #logger!: ReturnType<typeof getAdapterLogger>;
56
+
57
57
  readonly #options: MilkySseEndpointOptions;
58
58
  readonly #callApi: typeof callApi;
59
59
  readonly management: EndpointManagement = createMilkyEndpointManagement(this);
@@ -63,10 +63,11 @@ export class MilkySseEndpoint implements EndpointInstance {
63
63
  #unregisterAgent?: () => void;
64
64
 
65
65
  constructor(options: MilkySseEndpointOptions) {
66
+ this.#logger = getAdapterLogger('milky', options.config.id);
66
67
  this.#options = options;
67
68
  this.#callApi = options.callApi ?? callApi;
68
69
  this.#lifecycle = createEndpointLifecycle({
69
- name: options.config.name,
70
+ name: options.config.id,
70
71
  // reconnect_interval 旧语义为固定间隔:multiplier 1 + 无 jitter + 不封顶
71
72
  reconnect: {
72
73
  initialIntervalMs: options.config.reconnect_interval,
@@ -79,7 +80,7 @@ export class MilkySseEndpoint implements EndpointInstance {
79
80
 
80
81
  async start(): Promise<void> {
81
82
  if (this.#lifecycle.started) return;
82
- this.#unregisterAgent = registerMilkyAgentEndpoint(this.#options.config.name, this);
83
+ this.#unregisterAgent = registerMilkyAgentEndpoint(this.#options.config.id, this);
83
84
  try {
84
85
  await this.#lifecycle.start((handle) => this.#connect(handle));
85
86
  } catch (err) {
@@ -112,9 +113,9 @@ export class MilkySseEndpoint implements EndpointInstance {
112
113
  const { action, params } = buildSendAction(conversation, message);
113
114
  const data = await this.callApi(action, params) as { message_seq?: number } | undefined;
114
115
  const messageId = formatOutboundMessageId(conversation, data?.message_seq);
115
- logger.debug(formatCompact({
116
+ this.#logger.debug(formatCompact({
116
117
  op: 'milky_send',
117
- endpoint: this.#options.config.name,
118
+ endpoint: this.#options.config.id,
118
119
  target: `${conversation.kind}:${conversation.id}`,
119
120
  messageId,
120
121
  mode: 'sse',
@@ -231,21 +232,20 @@ export class MilkySseEndpoint implements EndpointInstance {
231
232
  message: { conversation, id: formatInboundMessageId(data) },
232
233
  content,
233
234
  segments,
234
- sender: String(data.sender_id),
235
+ sender: { id: String(data.sender_id), name: nickname },
236
+ endpointId: this.#options.config.id,
237
+ ...(mentioned ? { mentioned: true } : {}),
235
238
  metadata: Object.freeze({
236
239
  message_scene: data.message_scene,
237
240
  peer_id: String(data.peer_id),
238
241
  sender_id: String(data.sender_id),
239
242
  message_seq: data.message_seq,
240
- endpoint: this.#options.config.name,
241
243
  time: data.time ?? event.time,
242
244
  self_id: event.self_id != null ? String(event.self_id) : undefined,
243
245
  ...(nickname ? { nickname } : {}),
244
- ...(mentioned ? { mentioned: true } : {}),
245
- ...(audioUrl ? { audio_url: audioUrl } : {}),
246
246
  }),
247
247
  }).catch((err) => {
248
- logger.warn(formatCompact({
248
+ this.#logger.warn(formatCompact({
249
249
  op: 'milky_gateway_receive_failed',
250
250
  target,
251
251
  error: err instanceof Error ? err.message : String(err),
@@ -265,8 +265,8 @@ export class MilkySseEndpoint implements EndpointInstance {
265
265
  onOpen: () => {
266
266
  if (settled) return;
267
267
  settled = true;
268
- logger.debug(formatCompact({
269
- endpoint: this.#options.config.name,
268
+ this.#logger.debug(formatCompact({
269
+ endpoint: this.#options.config.id,
270
270
  mode: 'sse',
271
271
  url: safeUrl,
272
272
  }));
@@ -274,9 +274,9 @@ export class MilkySseEndpoint implements EndpointInstance {
274
274
  },
275
275
  onMessage: (data) => this.#onMessage(data),
276
276
  onError: (error) => {
277
- logger.warn(formatCompact({
277
+ this.#logger.warn(formatCompact({
278
278
  op: 'sse_error',
279
- endpoint: this.#options.config.name,
279
+ endpoint: this.#options.config.id,
280
280
  ok: false,
281
281
  error: error.message,
282
282
  }));
@@ -297,9 +297,8 @@ export class MilkySseEndpoint implements EndpointInstance {
297
297
  void stream.closed.then(() => {
298
298
  // stop-during-connect 竞态由基座静默 settle(主动停止不算失败),此处仅对运行期断开告警
299
299
  if (this.#lifecycle.state !== 'stopped') {
300
- logger.warn(formatCompact({
301
- op: 'disconnect',
302
- endpoint: this.#options.config.name,
300
+ this.#logger.warn(formatCompact({
301
+ op: 'disconnect',
303
302
  mode: 'sse',
304
303
  reconnect_ms: this.#options.config.reconnect_interval,
305
304
  }));
@@ -319,9 +318,9 @@ export class MilkySseEndpoint implements EndpointInstance {
319
318
  const event = JSON.parse(data) as MilkyEvent;
320
319
  this.admit(event);
321
320
  } catch (error) {
322
- logger.warn(formatCompact({
321
+ this.#logger.warn(formatCompact({
323
322
  op: 'milky_parse_failed',
324
- endpoint: this.#options.config.name,
323
+ endpoint: this.#options.config.id,
325
324
  mode: 'sse',
326
325
  error: error instanceof Error ? error.message : String(error),
327
326
  }));
@@ -9,7 +9,7 @@ import type {
9
9
  } from '@zhin.js/adapter';
10
10
  import type { MessageGateway } from '@zhin.js/core/runtime';
11
11
  import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
12
- import { formatCompact, getLogger } from '@zhin.js/logger';
12
+ import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
13
13
  import type { CapabilityId } from '@zhin.js/plugin-runtime';
14
14
  import { readRequestBody, verifyMilkyAccessToken } from './milky-auth.js';
15
15
  import { createMilkyEndpointManagement } from './endpoint-management.js';
@@ -33,8 +33,6 @@ import {
33
33
  type MilkyWebhookConfig,
34
34
  } from './protocol.js';
35
35
 
36
- const logger = getLogger('milky');
37
-
38
36
  export interface MilkyWebhookEndpointOptions {
39
37
  readonly id: CapabilityId;
40
38
  readonly gateway: MessageGateway;
@@ -44,6 +42,8 @@ export interface MilkyWebhookEndpointOptions {
44
42
  }
45
43
 
46
44
  export class MilkyWebhookEndpoint implements EndpointInstance {
45
+ readonly #logger!: ReturnType<typeof getAdapterLogger>;
46
+
47
47
  readonly #options: MilkyWebhookEndpointOptions;
48
48
  readonly #callApi: typeof callApi;
49
49
  readonly management: EndpointManagement = createMilkyEndpointManagement(this);
@@ -53,6 +53,7 @@ export class MilkyWebhookEndpoint implements EndpointInstance {
53
53
  #unregisterAgent?: () => void;
54
54
 
55
55
  constructor(options: MilkyWebhookEndpointOptions) {
56
+ this.#logger = getAdapterLogger('milky', options.config.id);
56
57
  this.#options = options;
57
58
  this.#callApi = options.callApi ?? callApi;
58
59
  }
@@ -60,11 +61,11 @@ export class MilkyWebhookEndpoint implements EndpointInstance {
60
61
  async start(): Promise<void> {
61
62
  if (this.#started) return;
62
63
  this.#started = true;
63
- this.#unregisterAgent = registerMilkyAgentEndpoint(this.#options.config.name, this);
64
+ this.#unregisterAgent = registerMilkyAgentEndpoint(this.#options.config.id, this);
64
65
  this.#setupRoutes();
65
- logger.info(formatCompact({
66
+ this.#logger.info(formatCompact({
66
67
  op: 'listen',
67
- endpoint: this.#options.config.name,
68
+ endpoint: this.#options.config.id,
68
69
  mode: 'webhook',
69
70
  path: this.#options.config.path,
70
71
  }));
@@ -84,7 +85,7 @@ export class MilkyWebhookEndpoint implements EndpointInstance {
84
85
  this.#unregisterAgent?.();
85
86
  this.#unregisterAgent = undefined;
86
87
  this.#started = false;
87
- logger.debug(formatCompact({ op: 'disconnect', endpoint: this.#options.config.name }));
88
+ this.#logger.debug(formatCompact({ op: 'disconnect' }));
88
89
  }
89
90
 
90
91
  async send({ conversation, payload }: EndpointSendRequest): Promise<string> {
@@ -92,9 +93,9 @@ export class MilkyWebhookEndpoint implements EndpointInstance {
92
93
  const { action, params } = buildSendAction(conversation, message);
93
94
  const data = await this.callApi(action, params) as { message_seq?: number } | undefined;
94
95
  const messageId = formatOutboundMessageId(conversation, data?.message_seq);
95
- logger.debug(formatCompact({
96
+ this.#logger.debug(formatCompact({
96
97
  op: 'milky_send',
97
- endpoint: this.#options.config.name,
98
+ endpoint: this.#options.config.id,
98
99
  target: `${conversation.kind}:${conversation.id}`,
99
100
  messageId,
100
101
  }));
@@ -210,21 +211,20 @@ export class MilkyWebhookEndpoint implements EndpointInstance {
210
211
  message: { conversation, id: formatInboundMessageId(data) },
211
212
  content,
212
213
  segments,
213
- sender: String(data.sender_id),
214
+ sender: { id: String(data.sender_id), name: nickname },
215
+ endpointId: this.#options.config.id,
216
+ ...(mentioned ? { mentioned: true } : {}),
214
217
  metadata: Object.freeze({
215
218
  message_scene: data.message_scene,
216
219
  peer_id: String(data.peer_id),
217
220
  sender_id: String(data.sender_id),
218
221
  message_seq: data.message_seq,
219
- endpoint: this.#options.config.name,
220
222
  time: data.time ?? event.time,
221
223
  self_id: event.self_id != null ? String(event.self_id) : undefined,
222
224
  ...(nickname ? { nickname } : {}),
223
- ...(mentioned ? { mentioned: true } : {}),
224
- ...(audioUrl ? { audio_url: audioUrl } : {}),
225
225
  }),
226
226
  }).catch((err) => {
227
- logger.warn(formatCompact({
227
+ this.#logger.warn(formatCompact({
228
228
  op: 'milky_gateway_receive_failed',
229
229
  target,
230
230
  error: err instanceof Error ? err.message : String(err),
@@ -261,7 +261,7 @@ export class MilkyWebhookEndpoint implements EndpointInstance {
261
261
  response.writeHead(200, { 'Content-Type': 'application/json' });
262
262
  response.end(JSON.stringify({ status: 'ok' }));
263
263
  } catch (error) {
264
- logger.error('Milky webhook error:', error);
264
+ this.#logger.error('Milky webhook error:', error);
265
265
  if (!response.headersSent) {
266
266
  response.writeHead(500, { 'Content-Type': 'application/json' });
267
267
  response.end(JSON.stringify({ message: 'Internal Server Error' }));
@@ -11,7 +11,7 @@ import {
11
11
  type EndpointSendRequest,
12
12
  } from '@zhin.js/adapter';
13
13
  import type { MessageGateway } from '@zhin.js/core/runtime';
14
- import { formatCompact, getLogger } from '@zhin.js/logger';
14
+ import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
15
15
  import type { CapabilityId } from '@zhin.js/plugin-runtime';
16
16
  import { createMilkyEndpointManagement } from './endpoint-management.js';
17
17
  import { registerMilkyAgentEndpoint } from './milky-agent-deps.js';
@@ -36,7 +36,6 @@ import {
36
36
  } from './protocol.js';
37
37
  import type { MilkyWsCreateOptions, MilkyWsSocket } from './ws-types.js';
38
38
 
39
- const logger = getLogger('milky');
40
39
  const WS_OPEN = 1;
41
40
 
42
41
  export interface MilkyWsEndpointOptions {
@@ -51,6 +50,8 @@ export interface MilkyWsEndpointOptions {
51
50
  }
52
51
 
53
52
  export class MilkyWsEndpoint implements EndpointInstance {
53
+ readonly #logger!: ReturnType<typeof getAdapterLogger>;
54
+
54
55
  readonly #options: MilkyWsEndpointOptions;
55
56
  readonly #callApi: typeof callApi;
56
57
  readonly management: EndpointManagement = createMilkyEndpointManagement(this);
@@ -60,10 +61,11 @@ export class MilkyWsEndpoint implements EndpointInstance {
60
61
  #unregisterAgent?: () => void;
61
62
 
62
63
  constructor(options: MilkyWsEndpointOptions) {
64
+ this.#logger = getAdapterLogger('milky', options.config.id);
63
65
  this.#options = options;
64
66
  this.#callApi = options.callApi ?? callApi;
65
67
  this.#lifecycle = createEndpointLifecycle({
66
- name: options.config.name,
68
+ name: options.config.id,
67
69
  // reconnect_interval 旧语义为固定间隔:multiplier 1 + 无 jitter + 不封顶
68
70
  reconnect: {
69
71
  initialIntervalMs: options.config.reconnect_interval,
@@ -76,7 +78,7 @@ export class MilkyWsEndpoint implements EndpointInstance {
76
78
 
77
79
  async start(): Promise<void> {
78
80
  if (this.#lifecycle.started) return;
79
- this.#unregisterAgent = registerMilkyAgentEndpoint(this.#options.config.name, this);
81
+ this.#unregisterAgent = registerMilkyAgentEndpoint(this.#options.config.id, this);
80
82
  try {
81
83
  await this.#lifecycle.start((handle) => this.#connect(handle));
82
84
  } catch (err) {
@@ -115,9 +117,9 @@ export class MilkyWsEndpoint implements EndpointInstance {
115
117
  const { action, params } = buildSendAction(conversation, message);
116
118
  const data = await this.callApi(action, params) as { message_seq?: number } | undefined;
117
119
  const messageId = formatOutboundMessageId(conversation, data?.message_seq);
118
- logger.debug(formatCompact({
120
+ this.#logger.debug(formatCompact({
119
121
  op: 'milky_send',
120
- endpoint: this.#options.config.name,
122
+ endpoint: this.#options.config.id,
121
123
  target: `${conversation.kind}:${conversation.id}`,
122
124
  messageId,
123
125
  }));
@@ -235,21 +237,20 @@ export class MilkyWsEndpoint implements EndpointInstance {
235
237
  message: { conversation, id: formatInboundMessageId(data) },
236
238
  content,
237
239
  segments,
238
- sender: String(data.sender_id),
240
+ sender: { id: String(data.sender_id), name: nickname },
241
+ endpointId: this.#options.config.id,
242
+ ...(mentioned ? { mentioned: true } : {}),
239
243
  metadata: Object.freeze({
240
244
  message_scene: data.message_scene,
241
245
  peer_id: String(data.peer_id),
242
246
  sender_id: String(data.sender_id),
243
247
  message_seq: data.message_seq,
244
- endpoint: this.#options.config.name,
245
248
  time: data.time ?? event.time,
246
249
  self_id: event.self_id != null ? String(event.self_id) : undefined,
247
250
  ...(nickname ? { nickname } : {}),
248
- ...(mentioned ? { mentioned: true } : {}),
249
- ...(audioUrl ? { audio_url: audioUrl } : {}),
250
251
  }),
251
252
  }).catch((err) => {
252
- logger.warn(formatCompact({
253
+ this.#logger.warn(formatCompact({
253
254
  op: 'milky_gateway_receive_failed',
254
255
  target,
255
256
  error: err instanceof Error ? err.message : String(err),
@@ -279,14 +280,14 @@ export class MilkyWsEndpoint implements EndpointInstance {
279
280
  if (settled) return;
280
281
  settled = true;
281
282
  if (!this.#options.config.access_token) {
282
- logger.warn(formatCompact({
283
- endpoint: this.#options.config.name,
283
+ this.#logger.warn(formatCompact({
284
+ endpoint: this.#options.config.id,
284
285
  ok: false,
285
286
  error: 'missing access_token',
286
287
  }));
287
288
  }
288
- logger.debug(formatCompact({
289
- endpoint: this.#options.config.name,
289
+ this.#logger.debug(formatCompact({
290
+ endpoint: this.#options.config.id,
290
291
  mode: 'ws',
291
292
  url: safeUrl,
292
293
  }));
@@ -319,9 +320,8 @@ export class MilkyWsEndpoint implements EndpointInstance {
319
320
  : codeNum === 1006
320
321
  ? ' [异常关闭]'
321
322
  : '';
322
- logger.warn(formatCompact({
323
+ this.#logger.warn(formatCompact({
323
324
  op: 'disconnect',
324
- endpoint: this.#options.config.name,
325
325
  code: codeNum,
326
326
  error: `${reasonStr || 'closed'}${codeHint}`,
327
327
  reconnect_ms: this.#options.config.reconnect_interval,
@@ -336,9 +336,9 @@ export class MilkyWsEndpoint implements EndpointInstance {
336
336
 
337
337
  ws.on('error', (err) => {
338
338
  const error = err instanceof Error ? err : new Error(String(err));
339
- logger.warn(formatCompact({
339
+ this.#logger.warn(formatCompact({
340
340
  op: 'ws_error',
341
- endpoint: this.#options.config.name,
341
+ endpoint: this.#options.config.id,
342
342
  ok: false,
343
343
  error: error.message,
344
344
  }));
@@ -362,9 +362,9 @@ export class MilkyWsEndpoint implements EndpointInstance {
362
362
  const event = JSON.parse(raw) as MilkyEvent;
363
363
  this.admit(event);
364
364
  } catch (error) {
365
- logger.warn(formatCompact({
365
+ this.#logger.warn(formatCompact({
366
366
  op: 'milky_parse_failed',
367
- endpoint: this.#options.config.name,
367
+ endpoint: this.#options.config.id,
368
368
  error: error instanceof Error ? error.message : String(error),
369
369
  }));
370
370
  }