@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/CHANGELOG.md CHANGED
@@ -1,5 +1,75 @@
1
1
  # @zhin.js/adapter-milky
2
2
 
3
+ ## 6.0.5
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [6f9c366]
8
+ - Updated dependencies [373a56b]
9
+ - Updated dependencies [0de46a8]
10
+ - Updated dependencies [c106ecc]
11
+ - Updated dependencies [ca92e03]
12
+ - Updated dependencies [b0f37ae]
13
+ - Updated dependencies [ba08a2f]
14
+ - Updated dependencies [b08f7fe]
15
+ - Updated dependencies [daffd4c]
16
+ - Updated dependencies [36c7400]
17
+ - Updated dependencies [a9fa72e]
18
+ - Updated dependencies [c8de3ef]
19
+ - Updated dependencies [60f0fc8]
20
+ - Updated dependencies [574c990]
21
+ - Updated dependencies [d096f16]
22
+ - Updated dependencies [3f29623]
23
+ - Updated dependencies [2916852]
24
+ - Updated dependencies [d047869]
25
+ - Updated dependencies [162fa34]
26
+ - Updated dependencies [e62561e]
27
+ - Updated dependencies [3eeeb46]
28
+ - Updated dependencies [85d0f82]
29
+ - Updated dependencies [61bfc1c]
30
+ - Updated dependencies [04bad47]
31
+ - Updated dependencies [e40b048]
32
+ - Updated dependencies [5a5b1bb]
33
+ - Updated dependencies [f1708c3]
34
+ - Updated dependencies [d254a81]
35
+ - Updated dependencies [7123c47]
36
+ - Updated dependencies [05befc1]
37
+ - Updated dependencies [0663b6a]
38
+ - Updated dependencies [f28f9b3]
39
+ - Updated dependencies [9f340f7]
40
+ - Updated dependencies [e53444f]
41
+ - Updated dependencies [5eedd26]
42
+ - Updated dependencies [92b0dd7]
43
+ - Updated dependencies [f919b6f]
44
+ - Updated dependencies [098e411]
45
+ - Updated dependencies [e1b7c01]
46
+ - Updated dependencies [9b94f87]
47
+ - Updated dependencies [a7df753]
48
+ - @zhin.js/agent@1.1.5
49
+ - @zhin.js/host-http@1.0.8
50
+ - @zhin.js/im-contract@1.0.3
51
+ - @zhin.js/adapter@1.1.7
52
+ - @zhin.js/plugin-runtime@1.1.5
53
+ - @zhin.js/command@1.0.9
54
+ - @zhin.js/core@1.5.4
55
+ - zhin.js@6.0.4
56
+
57
+ ## 6.0.4
58
+
59
+ ### Patch Changes
60
+
61
+ - f8c7a54: fix: im
62
+ - Updated dependencies [f8c7a54]
63
+ - @zhin.js/logger@1.0.76
64
+ - @zhin.js/host-http@1.0.7
65
+ - @zhin.js/adapter@1.1.6
66
+ - @zhin.js/agent@1.1.4
67
+ - @zhin.js/command@1.0.8
68
+ - @zhin.js/core@1.5.3
69
+ - @zhin.js/im-contract@1.0.2
70
+ - @zhin.js/plugin-runtime@1.1.4
71
+ - zhin.js@6.0.3
72
+
3
73
  ## 6.0.3
4
74
 
5
75
  ### Patch Changes
package/adapters/milky.js CHANGED
@@ -20,8 +20,8 @@ export default defineAdapter({
20
20
  const config = resolveMilkyConfig(context.config);
21
21
  const gateway = context.use(messageGatewayToken);
22
22
  // 注册到插件运行时状态(milky.endpoint list 的"运行中"数据源)
23
- context.use(milkyRuntimeStateToken).endpoints.set(config.name, {
24
- name: config.name,
23
+ context.use(milkyRuntimeStateToken).endpoints.set(config.id, {
24
+ id: config.id,
25
25
  mode: config.connection,
26
26
  });
27
27
  if (config.connection === 'webhook') {
package/adapters/milky.ts CHANGED
@@ -43,8 +43,8 @@ export default defineAdapter<MilkyAdapterConfig>({
43
43
  const config = resolveMilkyConfig(context.config);
44
44
  const gateway = context.use(messageGatewayToken);
45
45
  // 注册到插件运行时状态(milky.endpoint list 的"运行中"数据源)
46
- context.use(milkyRuntimeStateToken).endpoints.set(config.name, {
47
- name: config.name,
46
+ context.use(milkyRuntimeStateToken).endpoints.set(config.id, {
47
+ id: config.id,
48
48
  mode: config.connection,
49
49
  });
50
50
  if (config.connection === 'webhook') {
@@ -16,9 +16,9 @@ export interface MilkyAgentEndpoint {
16
16
  recallMessage?(id: string): Promise<void>;
17
17
  }
18
18
  export interface MilkyAgentDeps {
19
- getEndpoint: (endpointId: string) => MilkyAgentEndpoint;
19
+ getEndpoint: (endpointKey: string) => MilkyAgentEndpoint;
20
20
  }
21
- export declare function registerMilkyAgentEndpoint(endpointId: string, endpoint: MilkyAgentEndpoint): () => void;
21
+ export declare function registerMilkyAgentEndpoint(endpointKey: string, endpoint: MilkyAgentEndpoint): () => void;
22
22
  /** Optional override used by tests / transitional callers. Pass `null` to clear. */
23
23
  export declare function setMilkyAgentDeps(deps: MilkyAgentDeps | null): void;
24
24
  export declare function getMilkyAgentDeps(): MilkyAgentDeps;
@@ -4,11 +4,11 @@
4
4
  */
5
5
  const endpoints = new Map();
6
6
  let override = null;
7
- export function registerMilkyAgentEndpoint(endpointId, endpoint) {
8
- endpoints.set(endpointId, endpoint);
7
+ export function registerMilkyAgentEndpoint(endpointKey, endpoint) {
8
+ endpoints.set(endpointKey, endpoint);
9
9
  return () => {
10
- if (endpoints.get(endpointId) === endpoint) {
11
- endpoints.delete(endpointId);
10
+ if (endpoints.get(endpointKey) === endpoint) {
11
+ endpoints.delete(endpointKey);
12
12
  }
13
13
  };
14
14
  }
@@ -20,10 +20,10 @@ export function getMilkyAgentDeps() {
20
20
  if (override)
21
21
  return override;
22
22
  return {
23
- getEndpoint(endpointId) {
24
- const registered = endpoints.get(endpointId);
23
+ getEndpoint(endpointKey) {
24
+ const registered = endpoints.get(endpointKey);
25
25
  if (!registered)
26
- throw new Error(`Endpoint ${endpointId} 不存在`);
26
+ throw new Error(`Endpoint ${endpointKey} 不存在`);
27
27
  return registered;
28
28
  },
29
29
  };
package/lib/protocol.d.ts CHANGED
@@ -9,7 +9,7 @@ import type { ConversationRef } from '@zhin.js/im-contract';
9
9
  export interface MilkyLegacyEndpointRow {
10
10
  readonly context?: string;
11
11
  readonly connection?: 'ws' | 'sse' | 'webhook' | 'wss';
12
- readonly name?: string;
12
+ readonly id?: string;
13
13
  readonly baseUrl?: string;
14
14
  readonly access_token?: string;
15
15
  readonly path?: string;
@@ -19,7 +19,7 @@ export interface MilkyLegacyEndpointRow {
19
19
  /** Plugin Runtime owner config (`plugins.<instanceKey>` / schema.json). */
20
20
  export interface MilkyAdapterConfig {
21
21
  readonly connection?: 'ws' | 'sse' | 'webhook' | 'wss';
22
- readonly name?: string;
22
+ readonly id?: string;
23
23
  readonly baseUrl?: string;
24
24
  readonly access_token?: string;
25
25
  readonly path?: string;
@@ -30,7 +30,7 @@ export interface MilkyAdapterConfig {
30
30
  }
31
31
  export interface MilkyConfigBase {
32
32
  readonly context: 'milky';
33
- readonly name: string;
33
+ readonly id: string;
34
34
  readonly baseUrl: string;
35
35
  readonly access_token?: string;
36
36
  }
@@ -123,7 +123,7 @@ export declare function isMessageReceiveEvent(event: MilkyEvent): event is Milky
123
123
  * 入站归一化 → ConversationRef:`friend`(私聊)→ `private`;`group` → `group`;
124
124
  * `temp`(群临时会话)→ 群容器内的 `private` 会话(parent = 来源群)。
125
125
  */
126
- export declare function milkyInboundConversation(endpointId: string, data: MilkyIncomingMessage): ConversationRef;
126
+ export declare function milkyInboundConversation(endpointKey: string, data: MilkyIncomingMessage): ConversationRef;
127
127
  export declare function formatInboundContent(data: MilkyIncomingMessage): string;
128
128
  /**
129
129
  * 入站消息段 → canonical Segment[](与 formatInboundContent 纯文本视图同源双轨)。
package/lib/protocol.js CHANGED
@@ -14,8 +14,8 @@ function normalizeConnection(connection) {
14
14
  export function resolveMilkyConfig(config = {}) {
15
15
  const entry = config.endpoints?.find((item) => item.context === 'milky');
16
16
  const connection = normalizeConnection(config.connection ?? entry?.connection);
17
- const name = (typeof config.name === 'string' && config.name)
18
- || (typeof entry?.name === 'string' && entry.name)
17
+ const id = (typeof config.id === 'string' && config.id)
18
+ || (typeof entry?.id === 'string' && entry.id)
19
19
  || process.env.MILKY_BOT_NAME
20
20
  || 'milky-bot';
21
21
  const baseUrl = config.baseUrl ?? entry?.baseUrl;
@@ -25,7 +25,7 @@ export function resolveMilkyConfig(config = {}) {
25
25
  const access_token = config.access_token ?? entry?.access_token;
26
26
  const base = {
27
27
  context: 'milky',
28
- name,
28
+ id,
29
29
  baseUrl,
30
30
  access_token,
31
31
  };
@@ -129,9 +129,9 @@ export function isMessageReceiveEvent(event) {
129
129
  * 入站归一化 → ConversationRef:`friend`(私聊)→ `private`;`group` → `group`;
130
130
  * `temp`(群临时会话)→ 群容器内的 `private` 会话(parent = 来源群)。
131
131
  */
132
- export function milkyInboundConversation(endpointId, data) {
132
+ export function milkyInboundConversation(endpointKey, data) {
133
133
  return {
134
- endpoint: { id: endpointId, adapter: endpointId.split('\0')[0] ?? endpointId },
134
+ endpoint: { id: endpointKey, adapter: endpointKey.split('\0')[0] ?? endpointKey },
135
135
  kind: data.message_scene === 'group' ? 'group' : 'private',
136
136
  id: String(data.peer_id),
137
137
  ...(data.message_scene === 'temp' && data.group
@@ -2,13 +2,13 @@
2
2
  * Milky SSE client endpoint — GET text/event-stream on /event.
3
3
  */
4
4
  import { createEndpointLifecycle, } from '@zhin.js/adapter';
5
- import { formatCompact, getLogger } from '@zhin.js/logger';
5
+ import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
6
6
  import { createMilkyEndpointManagement } from './endpoint-management.js';
7
7
  import { registerMilkyAgentEndpoint } from './milky-agent-deps.js';
8
8
  import { buildSendAction, buildSseConnectOptions, callApi, extractInboundAudioUrl, formatInboundContent, formatInboundMessageId, formatInboundSegments, formatOutboundMessageId, formatOutboundSegments, isMentioned, milkyInboundConversation, parseMessageReceiveData, parseMilkyMessageId, senderNickname, } from './protocol.js';
9
9
  import { openSseStream } from './sse-client.js';
10
- const logger = getLogger('milky');
11
10
  export class MilkySseEndpoint {
11
+ #logger;
12
12
  #options;
13
13
  #callApi;
14
14
  management = createMilkyEndpointManagement(this);
@@ -17,10 +17,11 @@ export class MilkySseEndpoint {
17
17
  #open = false;
18
18
  #unregisterAgent;
19
19
  constructor(options) {
20
+ this.#logger = getAdapterLogger('milky', options.config.id);
20
21
  this.#options = options;
21
22
  this.#callApi = options.callApi ?? callApi;
22
23
  this.#lifecycle = createEndpointLifecycle({
23
- name: options.config.name,
24
+ name: options.config.id,
24
25
  // reconnect_interval 旧语义为固定间隔:multiplier 1 + 无 jitter + 不封顶
25
26
  reconnect: {
26
27
  initialIntervalMs: options.config.reconnect_interval,
@@ -33,7 +34,7 @@ export class MilkySseEndpoint {
33
34
  async start() {
34
35
  if (this.#lifecycle.started)
35
36
  return;
36
- this.#unregisterAgent = registerMilkyAgentEndpoint(this.#options.config.name, this);
37
+ this.#unregisterAgent = registerMilkyAgentEndpoint(this.#options.config.id, this);
37
38
  try {
38
39
  await this.#lifecycle.start((handle) => this.#connect(handle));
39
40
  }
@@ -63,9 +64,9 @@ export class MilkySseEndpoint {
63
64
  const { action, params } = buildSendAction(conversation, message);
64
65
  const data = await this.callApi(action, params);
65
66
  const messageId = formatOutboundMessageId(conversation, data?.message_seq);
66
- logger.debug(formatCompact({
67
+ this.#logger.debug(formatCompact({
67
68
  op: 'milky_send',
68
- endpoint: this.#options.config.name,
69
+ endpoint: this.#options.config.id,
69
70
  target: `${conversation.kind}:${conversation.id}`,
70
71
  messageId,
71
72
  mode: 'sse',
@@ -171,21 +172,20 @@ export class MilkySseEndpoint {
171
172
  message: { conversation, id: formatInboundMessageId(data) },
172
173
  content,
173
174
  segments,
174
- sender: String(data.sender_id),
175
+ sender: { id: String(data.sender_id), name: nickname },
176
+ endpointId: this.#options.config.id,
177
+ ...(mentioned ? { mentioned: true } : {}),
175
178
  metadata: Object.freeze({
176
179
  message_scene: data.message_scene,
177
180
  peer_id: String(data.peer_id),
178
181
  sender_id: String(data.sender_id),
179
182
  message_seq: data.message_seq,
180
- endpoint: this.#options.config.name,
181
183
  time: data.time ?? event.time,
182
184
  self_id: event.self_id != null ? String(event.self_id) : undefined,
183
185
  ...(nickname ? { nickname } : {}),
184
- ...(mentioned ? { mentioned: true } : {}),
185
- ...(audioUrl ? { audio_url: audioUrl } : {}),
186
186
  }),
187
187
  }).catch((err) => {
188
- logger.warn(formatCompact({
188
+ this.#logger.warn(formatCompact({
189
189
  op: 'milky_gateway_receive_failed',
190
190
  target,
191
191
  error: err instanceof Error ? err.message : String(err),
@@ -204,8 +204,8 @@ export class MilkySseEndpoint {
204
204
  if (settled)
205
205
  return;
206
206
  settled = true;
207
- logger.debug(formatCompact({
208
- endpoint: this.#options.config.name,
207
+ this.#logger.debug(formatCompact({
208
+ endpoint: this.#options.config.id,
209
209
  mode: 'sse',
210
210
  url: safeUrl,
211
211
  }));
@@ -213,9 +213,9 @@ export class MilkySseEndpoint {
213
213
  },
214
214
  onMessage: (data) => this.#onMessage(data),
215
215
  onError: (error) => {
216
- logger.warn(formatCompact({
216
+ this.#logger.warn(formatCompact({
217
217
  op: 'sse_error',
218
- endpoint: this.#options.config.name,
218
+ endpoint: this.#options.config.id,
219
219
  ok: false,
220
220
  error: error.message,
221
221
  }));
@@ -237,9 +237,8 @@ export class MilkySseEndpoint {
237
237
  void stream.closed.then(() => {
238
238
  // stop-during-connect 竞态由基座静默 settle(主动停止不算失败),此处仅对运行期断开告警
239
239
  if (this.#lifecycle.state !== 'stopped') {
240
- logger.warn(formatCompact({
240
+ this.#logger.warn(formatCompact({
241
241
  op: 'disconnect',
242
- endpoint: this.#options.config.name,
243
242
  mode: 'sse',
244
243
  reconnect_ms: this.#options.config.reconnect_interval,
245
244
  }));
@@ -259,9 +258,9 @@ export class MilkySseEndpoint {
259
258
  this.admit(event);
260
259
  }
261
260
  catch (error) {
262
- logger.warn(formatCompact({
261
+ this.#logger.warn(formatCompact({
263
262
  op: 'milky_parse_failed',
264
- endpoint: this.#options.config.name,
263
+ endpoint: this.#options.config.id,
265
264
  mode: 'sse',
266
265
  error: error instanceof Error ? error.message : String(error),
267
266
  }));
@@ -1,10 +1,10 @@
1
- import { formatCompact, getLogger } from '@zhin.js/logger';
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
5
  import { buildSendAction, callApi, extractInboundAudioUrl, formatInboundContent, formatInboundMessageId, formatInboundSegments, formatOutboundMessageId, formatOutboundSegments, isMentioned, milkyInboundConversation, parseMessageReceiveData, parseMilkyMessageId, senderNickname, } from './protocol.js';
6
- const logger = getLogger('milky');
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.name, this);
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.name,
28
+ endpoint: this.#options.config.id,
28
29
  mode: 'webhook',
29
30
  path: this.#options.config.path,
30
31
  }));
@@ -42,16 +43,16 @@ export class MilkyWebhookEndpoint {
42
43
  this.#unregisterAgent?.();
43
44
  this.#unregisterAgent = undefined;
44
45
  this.#started = false;
45
- logger.debug(formatCompact({ op: 'disconnect', endpoint: this.#options.config.name }));
46
+ this.#logger.debug(formatCompact({ op: 'disconnect' }));
46
47
  }
47
48
  async send({ conversation, payload }) {
48
49
  const message = formatOutboundSegments(payload);
49
50
  const { action, params } = buildSendAction(conversation, message);
50
51
  const data = await this.callApi(action, params);
51
52
  const messageId = formatOutboundMessageId(conversation, data?.message_seq);
52
- logger.debug(formatCompact({
53
+ this.#logger.debug(formatCompact({
53
54
  op: 'milky_send',
54
- endpoint: this.#options.config.name,
55
+ endpoint: this.#options.config.id,
55
56
  target: `${conversation.kind}:${conversation.id}`,
56
57
  messageId,
57
58
  }));
@@ -156,21 +157,20 @@ export class MilkyWebhookEndpoint {
156
157
  message: { conversation, id: formatInboundMessageId(data) },
157
158
  content,
158
159
  segments,
159
- sender: String(data.sender_id),
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' }));
@@ -3,13 +3,13 @@
3
3
  */
4
4
  import WebSocket from 'ws';
5
5
  import { createEndpointLifecycle, } from '@zhin.js/adapter';
6
- import { formatCompact, getLogger } from '@zhin.js/logger';
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
9
  import { buildSendAction, buildWsConnectOptions, callApi, extractInboundAudioUrl, formatInboundContent, formatInboundMessageId, formatInboundSegments, formatOutboundMessageId, formatOutboundSegments, isMentioned, milkyInboundConversation, parseMessageReceiveData, parseMilkyMessageId, senderNickname, } from './protocol.js';
10
- const logger = getLogger('milky');
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.name,
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.name, this);
38
+ this.#unregisterAgent = registerMilkyAgentEndpoint(this.#options.config.id, this);
38
39
  try {
39
40
  await this.#lifecycle.start((handle) => this.#connect(handle));
40
41
  }
@@ -71,9 +72,9 @@ export class MilkyWsEndpoint {
71
72
  const { action, params } = buildSendAction(conversation, message);
72
73
  const data = await this.callApi(action, params);
73
74
  const messageId = formatOutboundMessageId(conversation, data?.message_seq);
74
- logger.debug(formatCompact({
75
+ this.#logger.debug(formatCompact({
75
76
  op: 'milky_send',
76
- endpoint: this.#options.config.name,
77
+ endpoint: this.#options.config.id,
77
78
  target: `${conversation.kind}:${conversation.id}`,
78
79
  messageId,
79
80
  }));
@@ -180,21 +181,20 @@ export class MilkyWsEndpoint {
180
181
  message: { conversation, id: formatInboundMessageId(data) },
181
182
  content,
182
183
  segments,
183
- sender: String(data.sender_id),
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.name,
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.name,
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.name,
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.name,
308
+ endpoint: this.#options.config.id,
310
309
  error: error instanceof Error ? error.message : String(error),
311
310
  }));
312
311
  }
@@ -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, getLogger } from '@zhin.js/logger';
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
9
  import { buildSendAction, callApi, extractInboundAudioUrl, formatInboundContent, formatInboundMessageId, formatInboundSegments, formatOutboundMessageId, formatOutboundSegments, isMentioned, milkyInboundConversation, parseMessageReceiveData, parseMilkyMessageId, senderNickname, } from './protocol.js';
10
- const logger = getLogger('milky');
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.name, this);
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.name,
38
+ endpoint: this.#options.config.id,
38
39
  mode: 'wss',
39
40
  path: this.#options.config.path,
40
41
  }));
@@ -71,9 +72,9 @@ export class MilkyWssEndpoint {
71
72
  const { action, params } = buildSendAction(conversation, message);
72
73
  const data = await this.callApi(action, params);
73
74
  const messageId = formatOutboundMessageId(conversation, data?.message_seq);
74
- logger.debug(formatCompact({
75
+ this.#logger.debug(formatCompact({
75
76
  op: 'milky_send',
76
- endpoint: this.#options.config.name,
77
+ endpoint: this.#options.config.id,
77
78
  target: `${conversation.kind}:${conversation.id}`,
78
79
  messageId,
79
80
  }));
@@ -178,21 +179,20 @@ export class MilkyWssEndpoint {
178
179
  message: { conversation, id: formatInboundMessageId(data) },
179
180
  content,
180
181
  segments,
181
- sender: String(data.sender_id),
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.name,
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.name,
246
+ endpoint: this.#options.config.id,
247
247
  error: error instanceof Error ? error.message : String(error),
248
248
  }));
249
249
  }