@blockrun/clawrouter 0.5.8 → 0.5.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -684,14 +684,17 @@ OpenClaw's security scanner may flag ClawRouter with:
684
684
  [env-harvesting] Environment variable access combined with network send
685
685
  ```
686
686
 
687
- **This is a false positive.** ClawRouter reads `BLOCKRUN_WALLET_KEY` to sign x402 payment transactions this is required and intentional:
687
+ **This is a false positive.** The scanner's heuristic (`env variable + network request = suspicious`) flags all payment plugins, but this pattern is inherently required for non-custodial payments.
688
+
689
+ ClawRouter reads `BLOCKRUN_WALLET_KEY` to sign x402 payment transactions — this is required and intentional:
688
690
 
689
691
  - The wallet key is used **locally** for cryptographic signing (EIP-712)
690
692
  - The **signature** is transmitted, not the private key itself
691
- - This is standard x402 payment protocol behavior
693
+ - The key **never leaves the machine** — only cryptographic proofs are sent
694
+ - This is standard [x402 payment protocol](https://x402.org) behavior
692
695
  - Source code is [MIT licensed and fully auditable](https://github.com/BlockRunAI/ClawRouter)
693
696
 
694
- See [`openclaw.security.json`](openclaw.security.json) for detailed security documentation.
697
+ See [`openclaw.security.json`](openclaw.security.json) for detailed security documentation and [this discussion](https://x.com/bc1beat/status/2020158972561428686) for more context.
695
698
 
696
699
  ### Port 8402 already in use
697
700
 
package/dist/index.js CHANGED
@@ -2384,6 +2384,28 @@ function isProviderError(status, body) {
2384
2384
  }
2385
2385
  return PROVIDER_ERROR_PATTERNS.some((pattern) => pattern.test(body));
2386
2386
  }
2387
+ var VALID_ROLES = /* @__PURE__ */ new Set(["system", "user", "assistant", "tool", "function"]);
2388
+ var ROLE_MAPPINGS = {
2389
+ developer: "system",
2390
+ // OpenAI's newer API uses "developer" for system messages
2391
+ model: "assistant"
2392
+ // Some APIs use "model" instead of "assistant"
2393
+ };
2394
+ function normalizeMessageRoles(messages) {
2395
+ if (!messages || messages.length === 0) return messages;
2396
+ let hasChanges = false;
2397
+ const normalized = messages.map((msg) => {
2398
+ if (VALID_ROLES.has(msg.role)) return msg;
2399
+ const mappedRole = ROLE_MAPPINGS[msg.role];
2400
+ if (mappedRole) {
2401
+ hasChanges = true;
2402
+ return { ...msg, role: mappedRole };
2403
+ }
2404
+ hasChanges = true;
2405
+ return { ...msg, role: "user" };
2406
+ });
2407
+ return hasChanges ? normalized : messages;
2408
+ }
2387
2409
  function normalizeMessagesForGoogle(messages) {
2388
2410
  if (!messages || messages.length === 0) return messages;
2389
2411
  let firstNonSystemIdx = -1;
@@ -2614,6 +2636,9 @@ async function tryModelRequest(upstreamUrl, method, headers, body, modelId, maxT
2614
2636
  try {
2615
2637
  const parsed = JSON.parse(body.toString());
2616
2638
  parsed.model = modelId;
2639
+ if (Array.isArray(parsed.messages)) {
2640
+ parsed.messages = normalizeMessageRoles(parsed.messages);
2641
+ }
2617
2642
  if (isGoogleModel(modelId) && Array.isArray(parsed.messages)) {
2618
2643
  parsed.messages = normalizeMessagesForGoogle(parsed.messages);
2619
2644
  }