22import type { webhook } from "@line/bot-sdk" ;
33import { recordChannelActivity } from "openclaw/plugin-sdk/channel-activity-runtime" ;
44import {
5+ buildChannelInboundMediaPayload ,
56 formatInboundMediaUnavailableText ,
67 formatInboundEnvelope ,
78 formatLocationText ,
89 resolveInboundSessionEnvelopeContext ,
10+ toInboundMediaFacts ,
911 toLocationContext ,
12+ type ChannelInboundMediaInput ,
1013} from "openclaw/plugin-sdk/channel-inbound" ;
1114import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts" ;
1215import {
@@ -225,18 +228,20 @@ function extractMessageText(message: MessageEvent["message"]): string {
225228 return "" ;
226229}
227230
228- function extractMediaPlaceholder ( message : MessageEvent [ "message" ] ) : string {
231+ function extractNativeMediaKind (
232+ message : MessageEvent [ "message" ] ,
233+ ) : ChannelInboundMediaInput [ "kind" ] | undefined {
229234 switch ( message . type ) {
230235 case "image" :
231- return "<media: image> " ;
236+ return "image" ;
232237 case "video" :
233- return "<media: video> " ;
238+ return "video" ;
234239 case "audio" :
235- return "<media: audio> " ;
240+ return "audio" ;
236241 case "file" :
237- return "<media: document> " ;
242+ return "document" ;
238243 default :
239- return "" ;
244+ return undefined ;
240245 }
241246}
242247
@@ -288,12 +293,7 @@ async function finalizeLineInboundContext(params: {
288293 timestamp : number ;
289294 messageSid : string ;
290295 commandAuthorized : boolean ;
291- media : {
292- firstPath : string | undefined ;
293- firstContentType ?: string ;
294- paths ?: string [ ] ;
295- types ?: string [ ] ;
296- } ;
296+ media : readonly ChannelInboundMediaInput [ ] ;
297297 locationContext ?: ReturnType < typeof toLocationContext > ;
298298 verboseLog : { kind : "inbound" | "postback" ; mediaCount ?: number } ;
299299 inboundHistory ?: Pick < HistoryEntry , "sender" | "body" | "timestamp" > [ ] ;
@@ -322,6 +322,7 @@ async function finalizeLineInboundContext(params: {
322322 } ) ;
323323
324324 const agentBody = params . agentBody ?? params . rawBody ;
325+ const mediaPayload = buildChannelInboundMediaPayload ( toInboundMediaFacts ( params . media ) ) ;
325326 const body = formatInboundEnvelope ( {
326327 channel : "LINE" ,
327328 from : conversationLabel ,
@@ -355,12 +356,7 @@ async function finalizeLineInboundContext(params: {
355356 Surface : "line" ,
356357 MessageSid : params . messageSid ,
357358 Timestamp : params . timestamp ,
358- MediaPath : params . media . firstPath ,
359- MediaType : params . media . firstContentType ,
360- MediaUrl : params . media . firstPath ,
361- MediaPaths : params . media . paths ,
362- MediaUrls : params . media . paths ,
363- MediaTypes : params . media . types ,
359+ ...mediaPayload ,
364360 ...params . locationContext ,
365361 CommandAuthorized : params . commandAuthorized ,
366362 OriginatingChannel : "line" as const ,
@@ -457,21 +453,22 @@ export async function buildLineMessageContext(params: BuildLineMessageContextPar
457453 const timestamp = event . timestamp ;
458454
459455 const textContent = extractMessageText ( message ) ;
460- const placeholder = extractMediaPlaceholder ( message ) ;
461-
462- let rawBody = textContent || placeholder ;
463- if ( ! rawBody && allMedia . length > 0 ) {
464- rawBody = `<media:image>${ allMedia . length > 1 ? ` (${ allMedia . length } images)` : "" } ` ;
465- }
456+ const nativeMediaKind = extractNativeMediaKind ( message ) ;
457+ const mediaFacts : ChannelInboundMediaInput [ ] =
458+ allMedia . length > 0
459+ ? allMedia . map ( ( media ) => ( { ...media , kind : nativeMediaKind } ) )
460+ : nativeMediaKind
461+ ? [ { kind : nativeMediaKind } ]
462+ : [ ] ;
463+ const rawBody = textContent ;
466464 const agentBody = mediaUnavailable
467465 ? formatInboundMediaUnavailableText ( {
468466 body : rawBody ,
469- mediaPlaceholder : placeholder ,
470467 notice : "[line attachment unavailable]" ,
471468 } )
472469 : rawBody ;
473470
474- if ( ! agentBody && allMedia . length === 0 ) {
471+ if ( ! agentBody && mediaFacts . length === 0 ) {
475472 return null ;
476473 }
477474
@@ -497,15 +494,7 @@ export async function buildLineMessageContext(params: BuildLineMessageContextPar
497494 timestamp,
498495 messageSid : messageId ,
499496 commandAuthorized,
500- media : {
501- firstPath : allMedia [ 0 ] ?. path ,
502- firstContentType : allMedia [ 0 ] ?. contentType ,
503- paths : allMedia . length > 0 ? allMedia . map ( ( m ) => m . path ) : undefined ,
504- types :
505- allMedia . length > 0
506- ? ( allMedia . map ( ( m ) => m . contentType ) . filter ( Boolean ) as string [ ] )
507- : undefined ,
508- } ,
497+ media : mediaFacts ,
509498 locationContext,
510499 verboseLog : { kind : "inbound" , mediaCount : allMedia . length } ,
511500 inboundHistory,
@@ -564,12 +553,7 @@ export async function buildLinePostbackContext(params: {
564553 timestamp,
565554 messageSid,
566555 commandAuthorized,
567- media : {
568- firstPath : "" ,
569- firstContentType : undefined ,
570- paths : undefined ,
571- types : undefined ,
572- } ,
556+ media : [ ] ,
573557 verboseLog : { kind : "postback" } ,
574558 } ) ;
575559
0 commit comments