fix(matrix): preserve shared send aliases and voice intent#52607
Conversation
aca9585 to
96827b2
Compare
Greptile SummaryThis PR fixes two related bugs in the Matrix action adapters: media-only sends that used shared parameter aliases ( The PR also includes a large number of out-of-scope changes (~40 non-Matrix files) consolidating direct extension imports into
Confidence Score: 4/5
Prompt To Fix All With AIThis is a comment left during a code review.
Path: extensions/matrix/src/tool-actions.ts
Line: 235-241
Comment:
**Voice-flag priority differs from `actions.ts`**
In `actions.ts` `asVoice` is checked first (wins over `audioAsVoice`), but here `audioAsVoice` is checked first. When a caller passes *both* flags with different values the two code paths will disagree. It also calls `readRawParam` twice per flag (read-then-read pattern), which can be simplified by caching the results.
```suggestion
const rawAudioAsVoice = readRawParam(params, "audioAsVoice");
const rawAsVoice = readRawParam(params, "asVoice");
const audioAsVoice =
typeof rawAsVoice === "boolean"
? rawAsVoice
: typeof rawAudioAsVoice === "boolean"
? rawAudioAsVoice
: undefined;
```
This aligns the priority (`asVoice` wins) with the `actions.ts` layer and avoids the repeated lookups.
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: extensions/matrix/src/tool-actions.ts
Line: 235-240
Comment:
**Voice-flag priority is reversed relative to `actions.ts`**
In `actions.ts`, `asVoice` takes priority over `audioAsVoice` (lines 177–180). Here in `tool-actions.ts` the order is flipped: `audioAsVoice` wins. This means a direct caller of `handleMatrixAction` supplying both `asVoice: false` and `audioAsVoice: true` would get `audioAsVoice: true` — the opposite of what the higher-level adapter would produce from the same input.
In practice the two paths rarely converge (by the time a call travels through `actions.ts` the value is already normalised to `audioAsVoice`), but keeping the priority consistent prevents surprising edge cases and makes reasoning about the overall pipeline easier.
Consider aligning `tool-actions.ts` to check `asVoice` first, matching the `actions.ts` behavior:
```suggestion
const rawAudioAsVoice = readRawParam(params, "audioAsVoice");
const rawAsVoice = readRawParam(params, "asVoice");
const audioAsVoice =
typeof rawAsVoice === "boolean"
? rawAsVoice
: typeof rawAudioAsVoice === "boolean"
? rawAudioAsVoice
: undefined;
```
This also removes the double invocation of `readRawParam` per flag (the current ternary calls it once for the `typeof` check and again to retrieve the value).
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "fix(matrix): preserve send aliases and v..." | Re-trigger Greptile |
| typeof readRawParam(params, "audioAsVoice") === "boolean" | ||
| ? (readRawParam(params, "audioAsVoice") as boolean) | ||
| : typeof readRawParam(params, "asVoice") === "boolean" | ||
| ? (readRawParam(params, "asVoice") as boolean) | ||
| : undefined; | ||
| const result = await sendMatrixMessage(to, content, { | ||
| mediaUrl: mediaUrl ?? undefined, |
There was a problem hiding this comment.
Voice-flag priority differs from
actions.ts
In actions.ts asVoice is checked first (wins over audioAsVoice), but here audioAsVoice is checked first. When a caller passes both flags with different values the two code paths will disagree. It also calls readRawParam twice per flag (read-then-read pattern), which can be simplified by caching the results.
| typeof readRawParam(params, "audioAsVoice") === "boolean" | |
| ? (readRawParam(params, "audioAsVoice") as boolean) | |
| : typeof readRawParam(params, "asVoice") === "boolean" | |
| ? (readRawParam(params, "asVoice") as boolean) | |
| : undefined; | |
| const result = await sendMatrixMessage(to, content, { | |
| mediaUrl: mediaUrl ?? undefined, | |
| const rawAudioAsVoice = readRawParam(params, "audioAsVoice"); | |
| const rawAsVoice = readRawParam(params, "asVoice"); | |
| const audioAsVoice = | |
| typeof rawAsVoice === "boolean" | |
| ? rawAsVoice | |
| : typeof rawAudioAsVoice === "boolean" | |
| ? rawAudioAsVoice | |
| : undefined; |
This aligns the priority (asVoice wins) with the actions.ts layer and avoids the repeated lookups.
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/matrix/src/tool-actions.ts
Line: 235-241
Comment:
**Voice-flag priority differs from `actions.ts`**
In `actions.ts` `asVoice` is checked first (wins over `audioAsVoice`), but here `audioAsVoice` is checked first. When a caller passes *both* flags with different values the two code paths will disagree. It also calls `readRawParam` twice per flag (read-then-read pattern), which can be simplified by caching the results.
```suggestion
const rawAudioAsVoice = readRawParam(params, "audioAsVoice");
const rawAsVoice = readRawParam(params, "asVoice");
const audioAsVoice =
typeof rawAsVoice === "boolean"
? rawAsVoice
: typeof rawAudioAsVoice === "boolean"
? rawAudioAsVoice
: undefined;
```
This aligns the priority (`asVoice` wins) with the `actions.ts` layer and avoids the repeated lookups.
How can I resolve this? If you propose a fix, please make it concise.| typeof readRawParam(params, "audioAsVoice") === "boolean" | ||
| ? (readRawParam(params, "audioAsVoice") as boolean) | ||
| : typeof readRawParam(params, "asVoice") === "boolean" | ||
| ? (readRawParam(params, "asVoice") as boolean) | ||
| : undefined; | ||
| const result = await sendMatrixMessage(to, content, { |
There was a problem hiding this comment.
Voice-flag priority is reversed relative to
actions.ts
In actions.ts, asVoice takes priority over audioAsVoice (lines 177–180). Here in tool-actions.ts the order is flipped: audioAsVoice wins. This means a direct caller of handleMatrixAction supplying both asVoice: false and audioAsVoice: true would get audioAsVoice: true — the opposite of what the higher-level adapter would produce from the same input.
In practice the two paths rarely converge (by the time a call travels through actions.ts the value is already normalised to audioAsVoice), but keeping the priority consistent prevents surprising edge cases and makes reasoning about the overall pipeline easier.
Consider aligning tool-actions.ts to check asVoice first, matching the actions.ts behavior:
| typeof readRawParam(params, "audioAsVoice") === "boolean" | |
| ? (readRawParam(params, "audioAsVoice") as boolean) | |
| : typeof readRawParam(params, "asVoice") === "boolean" | |
| ? (readRawParam(params, "asVoice") as boolean) | |
| : undefined; | |
| const result = await sendMatrixMessage(to, content, { | |
| const rawAudioAsVoice = readRawParam(params, "audioAsVoice"); | |
| const rawAsVoice = readRawParam(params, "asVoice"); | |
| const audioAsVoice = | |
| typeof rawAsVoice === "boolean" | |
| ? rawAsVoice | |
| : typeof rawAudioAsVoice === "boolean" | |
| ? rawAudioAsVoice | |
| : undefined; |
This also removes the double invocation of readRawParam per flag (the current ternary calls it once for the typeof check and again to retrieve the value).
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/matrix/src/tool-actions.ts
Line: 235-240
Comment:
**Voice-flag priority is reversed relative to `actions.ts`**
In `actions.ts`, `asVoice` takes priority over `audioAsVoice` (lines 177–180). Here in `tool-actions.ts` the order is flipped: `audioAsVoice` wins. This means a direct caller of `handleMatrixAction` supplying both `asVoice: false` and `audioAsVoice: true` would get `audioAsVoice: true` — the opposite of what the higher-level adapter would produce from the same input.
In practice the two paths rarely converge (by the time a call travels through `actions.ts` the value is already normalised to `audioAsVoice`), but keeping the priority consistent prevents surprising edge cases and makes reasoning about the overall pipeline easier.
Consider aligning `tool-actions.ts` to check `asVoice` first, matching the `actions.ts` behavior:
```suggestion
const rawAudioAsVoice = readRawParam(params, "audioAsVoice");
const rawAsVoice = readRawParam(params, "asVoice");
const audioAsVoice =
typeof rawAsVoice === "boolean"
? rawAsVoice
: typeof rawAudioAsVoice === "boolean"
? rawAudioAsVoice
: undefined;
```
This also removes the double invocation of `readRawParam` per flag (the current ternary calls it once for the `typeof` check and again to retrieve the value).
How can I resolve this? If you propose a fix, please make it concise.
Summary
mediaand droppedasVoice/audioAsVoicebefore the plugin send layer.mediaUrl,filePath, andpathaliases plusasVoice/audioAsVoicethroughactions.ts,tool-actions.ts, and the Matrix action wrapper; add focused regression coverage; add a changelog entry crediting @psacc and @vincentkoc.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
User-visible / Behavior Changes
messageactions now accept shared media parameter aliases (mediaUrl,filePath,path) in addition tomedia.messageactions now preserveasVoice/audioAsVoiceso supported audio sends can reach the Matrix voice-message path.Security Impact (required)
Repro + Verification
Environment
node,pnpm, orbunavailableSteps
messageaction withpathorfilePathinstead ofmedia, optionally withasVoice: true.sendMessageMatrix.Expected
mediaUrland forwards voice intent to the Matrix send layer.Actual
mediaand ignoredasVoice/audioAsVoice.Evidence
Human Verification (required)
extensions/matrix/src/actions.ts,extensions/matrix/src/tool-actions.ts, andextensions/matrix/src/matrix/actions/messages.ts; added focused regression tests for both adapter layers.asVoicepropagation to the send wrapper.node,pnpm, andbunare unavailable here.Review Conversations
Compatibility / Migration
Failure Recovery (if this breaks)
extensions/matrix/src/actions.ts,extensions/matrix/src/tool-actions.ts,extensions/matrix/src/matrix/actions/messages.tsRisks and Mitigations