Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 36 additions & 8 deletions src/milky/api/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,27 @@ const SendPrivateMessage = defineApi(

let result: RawMessage
if (payload.message[0].type === 'forward') {
const forwardData = payload.message[0].data as {
messages: OutgoingForwardedMessage[]
title?: string
preview?: { text: string }[]
summary?: string
prompt?: string
}
Comment on lines +47 to +53
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: 转发消息 payload 的结构在私聊和群聊处理器中都被重复并手动类型断言;建议提取一个共享的类型/辅助方法。

payload.message[0].data 的这个结构性类型断言现在在 SendPrivateMessageSendGroupMessage 中都出现了一次,因此只要转发 payload 的结构发生变更(例如新增字段),就必须在多个地方同步修改。定义一个共享的 ForwardPayload 类型和辅助方法(例如 getForwardPayload(payload.message[0]))可以把这部分结构集中管理,降低两个处理器实现产生不一致的风险。

推荐实现方式:

    type ForwardPayload = {
      messages: OutgoingForwardedMessage[]
      title?: string
      preview?: { text: string }[]
      summary?: string
      prompt?: string
    }

    const getForwardPayload = (message: { data: unknown }): ForwardPayload => {
      return message.data as ForwardPayload
    }

    let result: RawMessage
    if (payload.message[0].type === 'forward') {
      const forwardData = getForwardPayload(payload.message[0])
      const raw = await transformOutgoingForwardMessages(
        ctx,
        forwardData.messages,
        peer,
        {
          title: forwardData.title,
          preview: forwardData.preview,
          summary: forwardData.summary,
          prompt: forwardData.prompt
        }

你提到这个结构性类型断言在 SendPrivateMessageSendGroupMessage 中都被重复使用。请在群聊处理器中做同样的替换:

  1. 找到群聊消息处理器中与之对应的代码块,即检查 payload.message[0].type === 'forward' 并对 payload.message[0].data 进行相同结构的内联类型断言的地方。
  2. const forwardData = getForwardPayload(payload.message[0]) 来替换这段内联断言,其余使用方式保持不变(例如 forwardData.messagesforwardData.title 等)。

由于 ForwardPayloadgetForwardPayload 只在第一次使用附近定义一次,它们会被这两个处理器共享,而无需在其他地方再做额外修改。

Original comment in English

suggestion: The forward message payload shape is duplicated and manually cast in both private and group handlers; consider extracting a shared type/helper.

This structural cast of payload.message[0].data is now duplicated in both SendPrivateMessage and SendGroupMessage, so any change to the forward payload (e.g., new fields) must be updated in multiple places. A shared ForwardPayload type and helper (e.g., getForwardPayload(payload.message[0])) would centralize this shape and reduce the risk of the handlers drifting out of sync.

Suggested implementation:

    type ForwardPayload = {
      messages: OutgoingForwardedMessage[]
      title?: string
      preview?: { text: string }[]
      summary?: string
      prompt?: string
    }

    const getForwardPayload = (message: { data: unknown }): ForwardPayload => {
      return message.data as ForwardPayload
    }

    let result: RawMessage
    if (payload.message[0].type === 'forward') {
      const forwardData = getForwardPayload(payload.message[0])
      const raw = await transformOutgoingForwardMessages(
        ctx,
        forwardData.messages,
        peer,
        {
          title: forwardData.title,
          preview: forwardData.preview,
          summary: forwardData.summary,
          prompt: forwardData.prompt
        }

You mentioned this structural cast is duplicated in both SendPrivateMessage and SendGroupMessage. Apply the same replacement in the group handler:

  1. Locate the analogous block in the group message handler where payload.message[0].type === 'forward' is checked and payload.message[0].data is cast inline to the same shape.
  2. Replace that inline cast with const forwardData = getForwardPayload(payload.message[0]) and keep the rest of the usage (forwardData.messages, forwardData.title, etc.) the same.

Because ForwardPayload and getForwardPayload are defined once near the first usage, they will be shared by both handlers without further changes.

const raw = await transformOutgoingForwardMessages(
ctx,
payload.message[0].data.messages as OutgoingForwardedMessage[],
peer
forwardData.messages,
peer,
{
title: forwardData.title,
preview: forwardData.preview,
summary: forwardData.summary,
prompt: forwardData.prompt
}
)
const resid = await ctx.app.pmhq.uploadForward(peer, raw.multiMsgItems)
const uuid = randomUUID()
const prompt = raw.prompt
result = await ctx.app.sendMessage(ctx, peer, [{
elementType: 10,
elementId: '',
Expand All @@ -64,7 +78,7 @@ const SendPrivateMessage = defineApi(
type: 'normal',
width: 300,
},
desc: '[聊天记录]',
desc: prompt,
extra: JSON.stringify({
filename: uuid,
tsum: raw.tsum,
Expand All @@ -78,7 +92,7 @@ const SendPrivateMessage = defineApi(
uniseq: uuid,
},
},
prompt: '[聊天记录]',
prompt,
ver: '0.0.0.5',
view: 'contact',
}),
Expand Down Expand Up @@ -117,13 +131,27 @@ const SendGroupMessage = defineApi(

let result: RawMessage
if (payload.message[0].type === 'forward') {
const forwardData = payload.message[0].data as {
messages: OutgoingForwardedMessage[]
title?: string
preview?: { text: string }[]
summary?: string
prompt?: string
}
const raw = await transformOutgoingForwardMessages(
ctx,
payload.message[0].data.messages as OutgoingForwardedMessage[],
peer
forwardData.messages,
peer,
{
title: forwardData.title,
preview: forwardData.preview,
summary: forwardData.summary,
prompt: forwardData.prompt
}
)
const resid = await ctx.app.pmhq.uploadForward(peer, raw.multiMsgItems)
const uuid = randomUUID()
const prompt = raw.prompt
result = await ctx.app.sendMessage(ctx, peer, [{
elementType: 10,
elementId: '',
Expand All @@ -137,7 +165,7 @@ const SendGroupMessage = defineApi(
type: 'normal',
width: 300,
},
desc: '[聊天记录]',
desc: prompt,
extra: JSON.stringify({
filename: uuid,
tsum: raw.tsum,
Expand All @@ -151,7 +179,7 @@ const SendGroupMessage = defineApi(
uniseq: uuid,
},
},
prompt: '[聊天记录]',
prompt,
ver: '0.0.0.5',
view: 'contact',
}),
Expand Down
24 changes: 18 additions & 6 deletions src/milky/transform/message/outgoing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,16 @@ export async function transformOutgoingMessage(
export async function transformOutgoingForwardMessages(
ctx: Context,
messages: OutgoingForwardedMessage[],
peer: Peer
peer: Peer,
options?: {
Comment on lines 90 to +94
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: options 的结构在 transformOutgoingForwardMessagesForwardMessageEncoder.generate 中都被重复定义;建议提取一个共享的类型别名。

{ title?, preview?, summary?, prompt? } 这个 options 对象分别在函数和类方法中单独定义,一旦属性发生变化,它们可能会在没有任何提示的情况下产生偏差。请提取一个共享类型(例如 ForwardRenderOptions),并在两个签名中使用它,以保持一致并提高可读性。

推荐实现方式:

type ForwardRenderOptions = {
  title?: string
  preview?: { text: string }[]
  summary?: string
  prompt?: string
}

export async function transformOutgoingForwardMessages(
  ctx: Context,
  messages: OutgoingForwardedMessage[],
  peer: Peer,
  options?: ForwardRenderOptions
) {
  const encoder = new ForwardMessageEncoder(ctx, peer)
  return await encoder.generate(messages, options)
}

class ForwardMessageEncoder {

请在本文件中相应地更新 ForwardMessageEncoder.generate 方法签名以使用共享类型:

  • 将它的参数从内联的 options 结构替换为 options?: ForwardRenderOptions(或者如果目前还没有该参数,则添加它)。
  • 删除任何与 { title?, preview?, summary?, prompt? } 相关的重复 options 类型定义,统一改为引用 ForwardRenderOptions,以确保该函数和类方法始终保持同步。
Original comment in English

suggestion: The options shape is duplicated in both transformOutgoingForwardMessages and ForwardMessageEncoder.generate; consider a shared type alias.

The { title?, preview?, summary?, prompt? } options object is defined separately in the function and the class method, so they can silently diverge if properties change. Please extract a shared type (e.g., ForwardRenderOptions) and use it in both signatures to keep them aligned and easier to read.

Suggested implementation:

type ForwardRenderOptions = {
  title?: string
  preview?: { text: string }[]
  summary?: string
  prompt?: string
}

export async function transformOutgoingForwardMessages(
  ctx: Context,
  messages: OutgoingForwardedMessage[],
  peer: Peer,
  options?: ForwardRenderOptions
) {
  const encoder = new ForwardMessageEncoder(ctx, peer)
  return await encoder.generate(messages, options)
}

class ForwardMessageEncoder {

Update the ForwardMessageEncoder.generate method signature elsewhere in this file to also use the shared type:

  • Change its parameter from an inline options shape to options?: ForwardRenderOptions (or add the parameter if it doesn’t exist yet).
  • Remove any duplicated options type definitions related to { title?, preview?, summary?, prompt? } and reference ForwardRenderOptions instead, so both the function and the class method stay in sync.

title?: string
preview?: { text: string }[]
summary?: string
prompt?: string
}
) {
const encoder = new ForwardMessageEncoder(ctx, peer)
return await encoder.generate(messages)
return await encoder.generate(messages, options)
}

class ForwardMessageEncoder {
Expand Down Expand Up @@ -304,7 +310,12 @@ class ForwardMessageEncoder {
}
}

async generate(content: OutgoingForwardedMessage[]) {
async generate(content: OutgoingForwardedMessage[], options?: {
title?: string
preview?: { text: string }[]
summary?: string
prompt?: string
}) {
await this.render(content)
return {
multiMsgItems: [{
Expand All @@ -314,9 +325,10 @@ class ForwardMessageEncoder {
}
}],
tsum: this.tsum,
source: this.isGroup ? '群聊的聊天记录' : '聊天记录',
summary: `查看${this.tsum}条转发消息`,
news: this.news
source: options?.title ?? (this.isGroup ? '群聊的聊天记录' : '聊天记录'),
summary: options?.summary ?? `查看${this.tsum}条转发消息`,
news: options?.preview ?? this.news,
prompt: options?.prompt ?? '[聊天记录]'
}
}
}
Loading