Context-engine plugins (e.g. lossless-claw) that call LLM APIs via
completeSimple cannot resolve API keys from the main OpenClaw config.
This causes repeated 'No API key for provider' errors and forces
fallback to truncation.
Add runtime.modelAuth to PluginRuntimeCore with getApiKeyForModel and
resolveApiKeyForProvider so plugins can resolve credentials through
the standard auth pipeline (config, env vars, auth profiles).
Also re-export these helpers and the ResolvedProviderAuth type from
the plugin-sdk barrel for direct import by plugin authors.
Fixes#40902
* fix(matrix): remove memberCount heuristic from DM detection
The memberCount === 2 check in isDirectMessage() misclassifies 2-person
group rooms (admin channels, monitoring rooms) as DMs, routing them to
the main session instead of their room-specific session.
Matrix already distinguishes DMs from groups at the protocol level via
m.direct account data and is_direct member state flags. Both are already
checked by client.dms.isDm() and hasDirectFlag(). The memberCount
heuristic only adds false positives for 2-person groups.
Move resolveMemberCount() below the protocol-level checks so it is only
reached for rooms not matched by m.direct or is_direct. This narrows its
role to diagnostic logging for confirmed group rooms.
Refs: #19739
* fix(matrix): add conservative fallback for broken DM flags
Some homeservers (notably Continuwuity) have broken m.direct account
data or never set is_direct on invite events. With the memberCount
heuristic removed, these DMs are no longer detected.
Add a conservative fallback that requires two signals before classifying
as DM: memberCount === 2 AND no explicit m.room.name. Group rooms almost
always have explicit names; DMs almost never do.
Error handling distinguishes M_NOT_FOUND (missing state event, expected
for unnamed rooms) from network/auth errors. Non-404 errors fall through
to group classification rather than guessing.
This is independently revertable — removing this commit restores pure
protocol-based detection without any heuristic fallback.
* fix(matrix): add parentPeer for DM room binding support
Add parentPeer to DM routes so conversations are bindable by room ID
while preserving DM trust semantics (secure 1:1, no group restrictions).
Suggested by @KirillShchetinin.
* fix(matrix): override DM detection for explicitly configured rooms
Builds on @robertcorreiro's config-driven approach from #9106.
Move resolveMatrixRoomConfig() before the DM check. If a room matches
a non-wildcard config entry (matchSource === "direct") and was
classified as DM, override the classification to group. This gives users
a deterministic escape hatch for misclassified rooms.
Wildcards are excluded from the override to avoid breaking DM routing
when a "*" catch-all exists. roomConfig is gated behind isRoom so DMs
never inherit group settings (skills, systemPrompt, autoReply).
This commit is independently droppable if the scope is too broad.
* test(matrix): add DM detection and config override tests
- 15 unit tests for direct.ts: all detection paths, priority order,
M_NOT_FOUND vs network error handling, edge cases (whitespace names,
API failures)
- 8 unit tests for rooms.ts: matchSource classification, wildcard
safety for DM override, direct match priority over wildcard
* Changelog: note matrix DM routing follow-up
* fix(matrix): preserve DM fallback and room bindings
---------
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>