Skip to content

fix(line): preserve uploaded file names for media detection#96403

Merged
vincentkoc merged 2 commits into
openclaw:mainfrom
zaidazmi:codex/line-file-audio-filename
Jun 29, 2026
Merged

fix(line): preserve uploaded file names for media detection#96403
vincentkoc merged 2 commits into
openclaw:mainfrom
zaidazmi:codex/line-file-audio-filename

Conversation

@zaidazmi

@zaidazmi zaidazmi commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Related: #96163

What Problem This Solves

Fixes an issue where LINE users who upload an audio file as a file message can lose the original filename before OpenClaw stores the attachment, leaving the media path without the .m4a/audio extension hint needed by downstream audio detection when MIME sniffing is inconclusive.

Why This Change Was Made

LINE FileMessageContent already carries fileName, and OpenClaw's media store already accepts originalFilename for MIME/extension fallback and safe saved-media IDs. This change keeps the fix inside the LINE plugin boundary: file messages normalize and pass the LINE filename into downloadLineMedia, and the download wrapper forwards it to saveMediaStream.

This intentionally does not claim to fix the separate reported 0-byte LINE content stream behavior from #96163; that still needs live LINE/API evidence before changing download endpoints or stream handling.

User Impact

LINE audio files uploaded through the file picker can now retain names like voice-note.m4a through media storage, allowing the existing media-understanding path to classify them as audio instead of falling back to an unknown extensionless attachment when bytes alone do not identify the format.

Duplicate/work check: I found no open PR for #96163, downloadLineMedia originalFilename, FileMessage fileName saveMediaStream, or LINE file-upload audio metadata. Nearby open PRs checked: #86873 changes LINE download idle timeouts, not filename propagation; #71517 changes Feishu/shared filename decoding, not LINE FileMessage.fileName handoff.

Evidence

  • node scripts/run-vitest.mjs extensions/line/src/download.test.ts extensions/line/src/bot-handlers.test.ts extensions/line/src/bot-message-context.test.ts src/media-understanding/attachments.guards.test.ts src/media-understanding/apply.test.ts
  • node scripts/run-vitest.mjs extensions/line/src/bot-handlers.test.ts
  • pnpm exec oxfmt --check extensions/line/src/download.ts extensions/line/src/bot-handlers.ts extensions/line/src/download.test.ts extensions/line/src/bot-handlers.test.ts
  • pnpm exec oxfmt --check extensions/line/src/bot-handlers.test.ts && git diff --check
  • git diff --check
  • $autoreview final pass: clean, no accepted/actionable findings

Dependency/source proof checked: local @line/bot-sdk FileMessageContent type includes fileName and fileSize; saveMediaStream already accepts originalFilename and uses it for MIME detection/path extension fallback with sanitization.

Real behavior proof

Behavior addressed: LINE file-style audio filename preservation through OpenClaw media storage/classification, using the real saveMediaStream and resolveAttachmentKind runtime path.

Real environment tested: local OpenClaw checkout with Node 26.3.1 and an isolated OPENCLAW_HOME=$(mktemp -d).

Exact steps or command run after this patch: OPENCLAW_HOME=$(mktemp -d) node --import tsx --input-type=module - from the repo root, with an inline probe importing src/media/store.ts and src/media-understanding/attachments.normalize.ts, then streaming unknown bytes through saveMediaStream first without an original filename and then with voice-note.m4a.

Evidence after fix:

proof: actual saveMediaStream + resolveAttachmentKind runtime path
withoutFilename.originalFilename: <none>
withoutFilename.savedBasename: <uuid>
withoutFilename.savedExtension: <none>
withoutFilename.detectedContentType: <none>
withoutFilename.attachmentKind: unknown
withFilename.originalFilename: voice-note.m4a
withFilename.savedBasename: voice-note---<uuid>.m4a
withFilename.savedExtension: .m4a
withFilename.detectedContentType: audio/x-m4a
withFilename.attachmentKind: audio

Observed result after fix: without the filename hint, the saved attachment is extensionless and classifies as unknown; with voice-note.m4a, the saved basename preserves the sanitized audio extension and the actual attachment classifier returns audio.

What was not tested: no live LINE credential/API upload was run, and this does not validate or fix the separate 0-byte LINE content stream behavior from #96163.

@openclaw-barnacle openclaw-barnacle Bot added channel: line Channel integration: line size: S labels Jun 24, 2026
@clawsweeper

clawsweeper Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 24, 2026, 8:54 AM ET / 12:54 UTC.

Summary
The branch passes LINE FileMessage.fileName through handleMessageEvent and downloadLineMedia into saveMediaStream, with focused tests for filename propagation.

PR surface: Source +9, Tests +57. Total +66 across 4 files.

Reproducibility: yes. for the scoped metadata/audio-detection path: current main drops LINE fileName before media storage, and classification depends on MIME or saved-path extension. No high-confidence live reproduction was established for the separate 0-byte LINE stream behavior.

Review metrics: none identified.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #96163
Summary: This PR is a focused candidate fix for the filename/audio-detection half of the broader open LINE file-audio issue; the 0-byte download half remains on the issue.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🐚 platinum hermit
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • none.

Risk before merge

  • [P1] The linked LINE file-audio issue also reports a 0-byte content stream; this PR only fixes filename metadata for successful or non-empty file downloads and should not close the linked issue by itself.
  • [P1] No live LINE credential upload was run; the supplied proof covers the real OpenClaw media-store and classifier runtime path plus source-level LINE metadata handoff.

Maintainer options:

  1. Decide the mitigation before merge
    Land the focused filename handoff as a partial LINE fix if maintainers accept the scope, and keep [Feature]: LINE: file-type audio attachments not transcribed (0-byte download + missed audio detection) #96163 open for the empty-stream investigation.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge

  • [P2] No repair lane is needed because there are no concrete review findings; maintainers should decide whether to land this as a partial fix while leaving the linked empty-stream issue open.

Security
Cleared: No concrete security or supply-chain concern found; the diff threads an existing LINE metadata string into the already-sanitizing media-store path and adds tests.

Review details

Best possible solution:

Land the focused filename handoff as a partial LINE fix if maintainers accept the scope, and keep #96163 open for the empty-stream investigation.

Do we have a high-confidence way to reproduce the issue?

Yes for the scoped metadata/audio-detection path: current main drops LINE fileName before media storage, and classification depends on MIME or saved-path extension. No high-confidence live reproduction was established for the separate 0-byte LINE stream behavior.

Is this the best way to solve the issue?

Yes for the scoped metadata fix: using LINE's existing fileName field and the existing saveMediaStream originalFilename contract is the narrowest maintainable owner-boundary fix. Endpoint or stream-handling changes should wait for live LINE/API evidence.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against ae9474b5fdc0.

Label changes

Label justifications:

  • P1: The PR addresses a broken LINE channel workflow where uploaded audio files can be missed by transcription for real users.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): Sufficient for the scoped behavior: the PR body includes terminal output from the real saveMediaStream plus resolveAttachmentKind runtime path showing filename-backed storage and audio classification after the fix.
  • proof: sufficient: Contributor real behavior proof is sufficient. Sufficient for the scoped behavior: the PR body includes terminal output from the real saveMediaStream plus resolveAttachmentKind runtime path showing filename-backed storage and audio classification after the fix.
Evidence reviewed

PR surface:

Source +9, Tests +57. Total +66 across 4 files.

View PR surface stats
Area Files Added Removed Net
Source 2 11 2 +9
Tests 2 60 3 +57
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 4 71 5 +66

What I checked:

  • Current main drops LINE file names before download: Current main includes LINE file messages in the downloadable set but calls downloadLineMedia with only message id, token, and max bytes, so the webhook fileName cannot reach media storage. (extensions/line/src/bot-handlers.ts:53, ae9474b5fdc0)
  • Current download wrapper omits originalFilename: downloadLineMedia currently forwards the LINE content stream to saveMediaStream without the optional originalFilename argument. (extensions/line/src/download.ts:22, ae9474b5fdc0)
  • Existing media store already supports the required filename hint: saveMediaStream accepts originalFilename, uses it for MIME detection, resolves a safe extension, and builds the saved media id through the existing sanitizing path. (src/media/store.ts:616, ae9474b5fdc0)
  • Attachment classification uses path extension fallback: When MIME is unavailable, attachment classification falls back to filename/path extension and recognizes audio filenames such as .m4a. (src/media-understanding/attachments.normalize.ts:93, ae9474b5fdc0)
  • PR diff threads the filename through the LINE boundary: The patch normalizes message.fileName for LINE file messages, passes it as originalFilename, and adds tests for both handler and download-wrapper forwarding. (extensions/line/src/bot-handlers.ts:470, c0470a294fc3)
  • LINE SDK contract exposes file metadata: The inspected @line/bot-sdk 11.0.1 package defines FileMessageContent with required fileName and fileSize fields, matching the PR's metadata source. (npm:@line/[email protected]/package/dist/webhook/model/fileMessageContent.d.ts:13)

Likely related people:

  • steipete: Peter Steinberger appears heavily in the media-store and attachment-classification history that defines the originalFilename and audio-extension behavior this PR relies on. (role: media-store and media-understanding area contributor; confidence: high; commits: 1da7906a5dcb, 6545317a2cb9, 870cc22cb08c; files: src/media/store.ts, src/media-understanding/attachments.normalize.ts, extensions/line/src/download.ts)
  • vincentkoc: Vincent Koc moved LINE ownership into the extension boundary and has recent LINE runtime seam work in the same plugin area. (role: LINE extension boundary contributor; confidence: medium; commits: 213198123042, ac0fd26e1699, 5207d081d459; files: extensions/line/src/bot-handlers.ts, extensions/line/src/download.ts)
  • Takhoffman: Tak Hoffman authored a prior LINE media/auth/routing fix touching the old handler, download, and message-context paths that overlap this bug class. (role: adjacent LINE media fix contributor; confidence: medium; commits: 9a5bfb1fe56d; files: src/line/bot-handlers.ts, src/line/download.ts, src/line/bot-message-context.ts)
  • plum-dawg: The original LINE plugin commit added the first bot handler and download implementation that later moved into the extension path. (role: original LINE plugin introducer; confidence: low; commits: c96ffa7186a4; files: src/line/bot-handlers.ts, src/line/download.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 High-priority user-facing bug, regression, or broken workflow. labels Jun 24, 2026
@zaidazmi

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 24, 2026
@vincentkoc
vincentkoc merged commit aa5ec51 into openclaw:main Jun 29, 2026
117 of 125 checks passed
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jun 30, 2026
…#96403)

* fix(line): preserve file upload filenames

* test(line): fail unexpected media downloads
QiuYuang pushed a commit to QiuYuang/openclaw that referenced this pull request Jul 1, 2026
…#96403)

* fix(line): preserve file upload filenames

* test(line): fail unexpected media downloads
chenyangjun-xy pushed a commit to chenyangjun-xy/openclaw that referenced this pull request Jul 1, 2026
…#96403)

* fix(line): preserve file upload filenames

* test(line): fail unexpected media downloads
chenyangjun-xy pushed a commit to chenyangjun-xy/openclaw that referenced this pull request Jul 3, 2026
…#96403)

* fix(line): preserve file upload filenames

* test(line): fail unexpected media downloads
Rorqualx pushed a commit to Rorqualx/cortex that referenced this pull request Jul 5, 2026
…#96403)

* fix(line): preserve file upload filenames

* test(line): fail unexpected media downloads

(cherry picked from commit aa5ec51)
Rorqualx pushed a commit to Rorqualx/cortex that referenced this pull request Jul 8, 2026
…#96403)

* fix(line): preserve file upload filenames

* test(line): fail unexpected media downloads

(cherry picked from commit aa5ec51)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: line Channel integration: line P1 High-priority user-facing bug, regression, or broken workflow. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: S status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants