auto: sync OpenClaw config 2026-09-09 16:13

This commit is contained in:
2026-09-09 16:13:31 +08:00
parent c79d73c0fe
commit 0aa13d3cf0
440 changed files with 51636 additions and 13 deletions
@@ -0,0 +1,138 @@
"use strict";
/**
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*
* Generic throttled flush controller.
*
* A pure scheduling primitive that manages timer-based throttling,
* mutex-guarded flushing, and reflush-on-conflict. Contains no
* business logic — the actual flush work is provided via a callback.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.FlushController = void 0;
const reply_dispatcher_types_1 = require("./reply-dispatcher-types.js");
// ---------------------------------------------------------------------------
// FlushController
// ---------------------------------------------------------------------------
class FlushController {
doFlush;
flushInProgress = false;
flushResolvers = [];
needsReflush = false;
pendingFlushTimer = null;
lastUpdateTime = 0;
isCompleted = false;
constructor(doFlush) {
this.doFlush = doFlush;
}
/** Mark the controller as completed — no more flushes after current one. */
complete() {
this.isCompleted = true;
}
/** Cancel any pending deferred flush timer. */
cancelPendingFlush() {
if (this.pendingFlushTimer) {
clearTimeout(this.pendingFlushTimer);
this.pendingFlushTimer = null;
}
}
/** Wait for any in-progress flush to finish. */
waitForFlush() {
if (!this.flushInProgress)
return Promise.resolve();
return new Promise((resolve) => this.flushResolvers.push(resolve));
}
/**
* Execute a flush (mutex-guarded, with reflush on conflict).
*
* If a flush is already in progress, marks needsReflush so a
* follow-up flush fires immediately after the current one completes.
*/
async flush() {
if (!this.cardMessageReady() || this.flushInProgress || this.isCompleted) {
if (this.flushInProgress && !this.isCompleted)
this.needsReflush = true;
return;
}
this.flushInProgress = true;
this.needsReflush = false;
// Update timestamp BEFORE the API call to prevent concurrent callers
// from also entering the flush (race condition fix).
this.lastUpdateTime = Date.now();
try {
await this.doFlush();
this.lastUpdateTime = Date.now();
}
finally {
this.flushInProgress = false;
const resolvers = this.flushResolvers;
this.flushResolvers = [];
for (const resolve of resolvers)
resolve();
// If events arrived while the API call was in flight,
// schedule an immediate follow-up flush.
if (this.needsReflush && !this.isCompleted && !this.pendingFlushTimer) {
this.needsReflush = false;
this.pendingFlushTimer = setTimeout(() => {
this.pendingFlushTimer = null;
void this.flush();
}, 0);
}
}
}
/**
* Throttled update entry point.
*
* @param throttleMs - Minimum interval between flushes (varies by
* CardKit vs IM patch mode). Passed in by the caller so this
* controller remains business-logic-free.
*/
async throttledUpdate(throttleMs) {
if (!this.cardMessageReady())
return;
const now = Date.now();
const elapsed = now - this.lastUpdateTime;
if (elapsed >= throttleMs) {
this.cancelPendingFlush();
if (elapsed > reply_dispatcher_types_1.THROTTLE_CONSTANTS.LONG_GAP_THRESHOLD_MS) {
// After a long gap, batch briefly so the first visible update
// contains meaningful text rather than just 1-2 characters.
this.lastUpdateTime = now;
this.pendingFlushTimer = setTimeout(() => {
this.pendingFlushTimer = null;
void this.flush();
}, reply_dispatcher_types_1.THROTTLE_CONSTANTS.BATCH_AFTER_GAP_MS);
}
else {
await this.flush();
}
}
else if (!this.pendingFlushTimer) {
// Inside throttle window — schedule a deferred flush
const delay = throttleMs - elapsed;
this.pendingFlushTimer = setTimeout(() => {
this.pendingFlushTimer = null;
void this.flush();
}, delay);
}
}
// ------------------------------------------------------------------
// Internal
// ------------------------------------------------------------------
/** Overridable gate: subclasses / consumers can set via setCardMessageReady. */
_cardMessageReady = false;
cardMessageReady() {
return this._cardMessageReady;
}
setCardMessageReady(ready) {
this._cardMessageReady = ready;
if (ready) {
// Initialize the timestamp so the first throttledUpdate sees a
// small elapsed time (matching original behavior where
// lastCardUpdateTime = Date.now() was set during card creation).
this.lastUpdateTime = Date.now();
}
}
}
exports.FlushController = FlushController;