Skip to content

Commit 9ca89fe

Browse files
authored
Merge branch 'main' into fix/issue-101224-tmp-dir-perm-mutation
2 parents 3e4fcf0 + 6192b03 commit 9ca89fe

34 files changed

Lines changed: 1153 additions & 91 deletions

.agents/skills/openclaw-ci-limits/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ These are intentionally guarded by `test/scripts/ci-workflow-guards.test.ts`:
132132
- `runner-admission` on `ubuntu-24.04` with
133133
`OPENCLAW_MAIN_CI_DEBOUNCE_SECONDS=90`.
134134
- `preflight` and `security-fast` needing `runner-admission`.
135-
- CI matrix caps: fast/check lanes at 12, Node test shards at 24, Windows and
135+
- CI matrix caps: fast/check lanes at 12, Node test shards at 28, Windows and
136136
Android at 2.
137137
- `build-artifacts` on `blacksmith-16vcpu-ubuntu-2404`.
138138
- lower-weight Node/check shards on `blacksmith-4vcpu-ubuntu-2404`.

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1139,7 +1139,7 @@ jobs:
11391139
fail-fast: false
11401140
# The canonical main path waits for the admission debounce above, so
11411141
# widen this large matrix within the current runner-registration budget.
1142-
max-parallel: 24
1142+
max-parallel: 28
11431143
matrix: ${{ fromJson(needs.preflight.outputs.checks_node_core_nondist_matrix) }}
11441144
steps:
11451145
- *linux_node_checkout_step

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Docs: https://docs.openclaw.ai
2727
- **Android hardware keyboard chat:** send with unmodified Enter on physical keyboards while preserving Shift+Enter and other modified Enter combinations for multiline input. (#101239) Thanks @3ninyt3nin-creator.
2828
- **CJK Markdown emphasis:** render adjacent Chinese, Japanese, and Korean emphasis punctuation through the shared Markdown pipeline instead of leaking literal markers across channels. (#101230, #101120) Thanks @nicknmorty.
2929
- **Codex yielded native subagents:** keep the parent app-server subscription and shared client alive until yielded native subagent completion delivery settles, preventing lost wakeups and leaked one-shot cleanup.
30+
- **Delivery recovery pacing:** pace eligible outbound and restart-continuation replays after gateway startup so outage backlogs do not burst into channel rate limits, while preserving the wall-clock recovery budget. (#101118, #101058) Thanks @ZengWen-DT.
3031
- **Discord streamed finals:** send completion replies as fresh messages so inactive channels become unread, while preserving targeted mentions without escalating `@everyone` or `@here`. (#99711, #99662) Thanks @davelutztx.
3132
- **OpenAI-compatible SSE parsing:** recognize event streams mislabeled as JSON without prepending a second `data:` prefix, preserving valid streamed responses from non-conforming providers. (#96503) Thanks @ZengWen-DT.
3233
- **LM Studio embedding preload:** honor model- and provider-level context-window limits when preloading embedding models, preventing avoidable GPU out-of-memory failures. (#100750) Thanks @zak-li, @ZOOWH, and @hxz398.

docs/ci.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ The slowest Node test families are split or balanced so each job stays small wit
103103
- `check-additional-*` stripes the supplemental boundary guard list (`scripts/run-additional-boundary-checks.mjs`) into one prompt-heavy shard (`check-additional-boundaries-a`, which includes the Codex prompt snapshot drift check) and one combined shard for the remaining stripes (`check-additional-boundaries-bcd`), each running independent guards concurrently and printing per-check timings. Package-boundary compile/canary work stays together, and runtime topology architecture runs separately from the gateway watch coverage embedded in `build-artifacts`.
104104
- Gateway watch, channel tests, and the core support-boundary shard run concurrently inside `build-artifacts` after `dist/` and `dist-runtime/` are already built.
105105

106-
Once admitted, canonical Linux CI permits up to 24 concurrent Node test jobs and
106+
Once admitted, canonical Linux CI permits up to 28 concurrent Node test jobs and
107107
12 for the smaller fast/check lanes; Windows and Android stay at two because
108108
those runner pools are narrower. Compact whole-config batches run with a
109109
120-minute batch timeout, while include-pattern groups share the same bounded

docs/plugins/voice-call.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ Voice-call credentials accept SecretRefs. `plugins.entries.voice-call.config.twi
121121
twilio: {
122122
accountSid: "ACxxxxxxxx",
123123
authToken: "...",
124+
// region: "ie1", // optional: us1 | ie1 | au1; defaults to us1
124125
},
125126
telnyx: {
126127
apiKey: "...",
@@ -187,6 +188,11 @@ Top-level keys under `plugins.entries.voice-call.config` not shown above:
187188
| `responseSystemPrompt` | generated | Custom system prompt for classic responses. |
188189
| `responseTimeoutMs` | `30000` | Timeout for classic response generation (ms). |
189190

191+
Twilio defaults to its US1 REST endpoint. To process calls in a supported
192+
non-US Region, set `twilio.region` to `ie1` or `au1` and use credentials from
193+
that Region. See
194+
[Twilio's non-US REST API guide](https://www.twilio.com/docs/global-infrastructure/using-the-twilio-rest-api-in-a-non-us-region).
195+
190196
<AccordionGroup>
191197
<Accordion title="Provider exposure and security notes">
192198
- Twilio, Telnyx, and Plivo all require a **publicly reachable** webhook URL.

extensions/feishu/src/bot.card-action.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,30 @@ describe("Feishu Card Action Handler", () => {
511511
expect(handleMessage().chat_type).toBe("p2p");
512512
});
513513

514+
it("keeps Feishu chat lookup error logs UTF-16 safe at the truncation boundary", async () => {
515+
const log = vi.fn();
516+
createFeishuClientMock.mockReturnValueOnce({
517+
im: {
518+
chat: {
519+
get: vi
520+
.fn()
521+
.mockResolvedValue({ code: 99, msg: `${"x".repeat(499)}😀tail` }),
522+
},
523+
},
524+
});
525+
const event = createCardActionEvent({
526+
token: "tok9d-utf16",
527+
chatId: "oc_unknown_chat_utf16",
528+
actionValue: { text: "/help" },
529+
});
530+
531+
await handleFeishuCardAction({ cfg, event, runtime: { ...runtime, log } });
532+
533+
expect(log).toHaveBeenCalledWith(
534+
`feishu[mock-account]: failed to resolve chat type: ${"x".repeat(499)}; defaulting to p2p`,
535+
);
536+
});
537+
514538
it("falls back to p2p when Feishu chat API throws", async () => {
515539
createFeishuClientMock.mockReturnValueOnce({
516540
im: {

extensions/feishu/src/card-action.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
isFutureDateTimestampMs,
55
resolveExpiresAtMsFromDurationMs,
66
} from "openclaw/plugin-sdk/number-runtime";
7+
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
78
import type { ClawdbotConfig, PluginRuntime, RuntimeEnv } from "../runtime-api.js";
89
import { resolveFeishuRuntimeAccount } from "./accounts.js";
910
import { handleFeishuMessage, type FeishuMessageEvent } from "./bot.js";
@@ -244,7 +245,7 @@ function pruneChatTypeCache(now: number): void {
244245
}
245246

246247
function sanitizeLogValue(v: string): string {
247-
return v.replace(/[\r\n]/g, " ").slice(0, 500);
248+
return truncateUtf16Safe(v.replace(/[\r\n]/g, " "), 500);
248249
}
249250

250251
function resolveFeishuApprovalCardExpiresAt(nowRaw = Date.now()): number | undefined {

extensions/feishu/src/monitor.cleanup.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,38 @@ describe("feishu websocket cleanup", () => {
376376
expect(errorMessage).not.toContain("secret_token");
377377
});
378378

379+
it("keeps websocket close error logs UTF-16 safe at the truncation boundary", async () => {
380+
const wsClient = createWsClient();
381+
wsClient.close.mockImplementationOnce(() => {
382+
throw new Error(`${"x".repeat(499)}😀tail`);
383+
});
384+
createFeishuWSClientMock.mockReturnValue(wsClient);
385+
386+
const abortController = new AbortController();
387+
const runtime = {
388+
log: vi.fn(),
389+
error: vi.fn(),
390+
exit: vi.fn(),
391+
};
392+
const monitorPromise = monitorWebSocket({
393+
account: createAccount("close-error-utf16"),
394+
accountId: "close-error-utf16",
395+
runtime,
396+
abortSignal: abortController.signal,
397+
eventDispatcher: {} as never,
398+
});
399+
400+
await vi.waitFor(() => {
401+
expect(wsClient.start).toHaveBeenCalledTimes(1);
402+
});
403+
abortController.abort();
404+
await monitorPromise;
405+
406+
expect(firstRuntimeError(runtime)).toBe(
407+
`feishu[close-error-utf16]: error closing WebSocket client: ${"x".repeat(499)}...`,
408+
);
409+
});
410+
379411
it("closes targeted websocket clients during stop cleanup", async () => {
380412
const alphaClient = createWsClient();
381413
const betaClient = createWsClient();

extensions/feishu/src/monitor.transport.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import crypto from "node:crypto";
33
import * as http from "node:http";
44
import * as Lark from "@larksuiteoapi/node-sdk";
5+
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
56
import { waitForAbortableDelay } from "./async.js";
67
import { createFeishuWSClient } from "./client.js";
78
import {
@@ -151,7 +152,7 @@ function formatFeishuWsErrorForLog(err: unknown): string {
151152
if (redacted.length <= FEISHU_WS_LOG_ERROR_MAX_LENGTH) {
152153
return redacted;
153154
}
154-
return `${redacted.slice(0, FEISHU_WS_LOG_ERROR_MAX_LENGTH)}...`;
155+
return `${truncateUtf16Safe(redacted, FEISHU_WS_LOG_ERROR_MAX_LENGTH)}...`;
155156
}
156157

157158
function isFeishuWsTerminalError(err: Error): boolean {

extensions/voice-call/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ Put under `plugins.entries.voice-call.config`:
9898
Notes:
9999

100100
- Twilio/Telnyx/Plivo require a **publicly reachable** webhook URL.
101+
- Twilio defaults to US1. For a non-US Region, set `twilio.region` to `ie1` or `au1` and use credentials created in that Region; see [Twilio's regional REST API guide](https://www.twilio.com/docs/global-infrastructure/using-the-twilio-rest-api-in-a-non-us-region).
101102
- `mock` is a local dev provider (no network calls).
102103
- Telnyx requires `telnyx.publicKey` (or `TELNYX_PUBLIC_KEY`) unless `skipSignatureVerification` is true.
103104
- If older configs still use `provider: "log"`, `twilio.from`, or legacy `streaming.*` OpenAI keys, run `openclaw doctor --fix` to rewrite them.

0 commit comments

Comments
 (0)