Add unit tests for resolveApiKeyFromAuthProfile covering the four
resolution branches: api_key profile returns the plaintext key,
oauth/token-only providers return undefined, providers with no profile
return undefined, and keyRef-only (no plaintext) profiles are skipped.
Also covers the older-host case where the provider-auth SDK subpath is
unavailable.
To keep the test self-contained (no real OpenClaw install or on-disk
auth-profile store), resolveApiKeyFromAuthProfile gains an optional
fourth parameter to inject a fake provider-auth SDK loader. Production
callers pass three arguments and keep loading the real SDK via require.
Signed-off-by: MicroGrey <changyuhang@outlook.com>
When offload.model references a provider whose apiKey is managed via
OpenClaw's auth-profiles mechanism (the recommended default, e.g. set up
with 'openclaw auth'), the local-llm initializer previously only read
models.providers[provider].apiKey in the config tree. If the key was
absent there, LocalLlmClient construction was skipped and L1/L1.5/L2
were disabled with a misleading "missing apiKey" error -- even though the
key existed and the main agent model worked fine.
Fix: add src/offload/auth-profile-key.ts, a synchronous helper that
loads the auth-profile store via openclaw/plugin-sdk/provider-auth and
returns the first api_key-type credential for the provider. The helper
is guarded with try/catch so older OpenClaw versions that do not expose
this SDK subpath degrade silently to the previous behavior.
In index.ts, the apiKey lookup becomes:
providerCfg?.apiKey ?? resolveApiKeyFromAuthProfile(api, providerKey, logger)
registerOffload() keeps its synchronous contract; no race is introduced
around backendClient assignment.
Closes#90
Signed-off-by: MicroGrey <changyuhang@outlook.com>
* refactor: unify duplicate Logger interfaces into single canonical type
23 files had local Logger/StoreLogger/PluginLogger/PipelineLogger/RunnerLogger/ExtractorLogger/TriggerLogger
interface definitions with identical shapes ({debug?, info, warn, error}).
Replace all with imports from the canonical `Logger` in `src/core/types.ts`:
- 17 files: local `interface Logger` → `import type { Logger }`
- 6 files: named variants (StoreLogger, PluginLogger, etc.) → `type X = Logger` alias
Two intentionally different interfaces are preserved:
- `CheckpointLogger` (only info + optional warn) — different contract
- `ensure-hook-policy.ts` Logger (no error) — different contract
Net: -120 lines, zero behavioral change.
Signed-off-by: yuanrengu <heyonggang0811@126.com>
* docs: update Logger JSDoc to reflect canonical relationship
StoreLogger, PluginLogger, etc. are now type aliases of Logger, not the
other way around. Update the comment to clarify this inverted relationship.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Signed-off-by: yuanrengu <heyonggang0811@126.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
UNSAFE_CHAR_RE included the surrogate range [\uD800-\uDFFF] without the `u`
flag, so JS treated strings as UTF-16 code units and stripped each half of
every well-formed non-BMP code point. sanitizeText and sanitizeJsonLine
therefore destroyed emoji, CJK Extension B, math bold, etc. in tool params,
tool results, and ref-md archives.
Adding the `u` flag makes paired surrogates combine into a single code point
before matching, so the [\uD800-\uDFFF] entry now matches only lone (malformed)
surrogates, which is the original intent. All other entries (replacement char,
C0/C1 controls, zero-width chars, line separators, BOM) keep their behavior.
Added a vitest suite covering the preserved and stripped cases.
Closes#30