harness: throttle bubble edits — cap 12/bubble, min 8s interval
Element X chokes loading rooms with long m.replace edit chains (the tool bubble got an edit per tool call — dozens per turn). Throttle pushes; the final state still flushes via the reply/closing path.
This commit is contained in:
1 parent
890970de81
commit
df4d00ee29
1 file changed
+12
@@ -201,6 +201,8 @@ const PROGRESS_ARG_CHARS = 120;
|
||||
const PROGRESS_RET_CHARS = 400;
|
||||
/// Char cap for the bubble body (edits re-send the full body every time).
|
||||
const PROGRESS_MAX_CHARS = 3500;
|
||||
/// Edit throttling: Element X chokes on long m.replace edit chains.
|
||||
const PROGRESS_MAX_EDITS = 12;
|
||||
|
||||
const Progress = struct {
|
||||
alloc: std.mem.Allocator,
|
||||
@@ -212,6 +214,8 @@ const Progress = struct {
|
||||
reply_event_id: ?[]u8 = null, // the streamed-reply message (edited live)
|
||||
reply: std.ArrayListUnmanaged(u8) = .empty, // accumulated reply text
|
||||
replied: bool = false, // true once the full reply was edited in
|
||||
last_edit_ms: i64 = 0,
|
||||
edits_done: usize = 0,
|
||||
|
||||
fn deinit(self: *Progress) void {
|
||||
if (self.event_id) |e| self.alloc.free(e);
|
||||
@@ -309,6 +313,14 @@ const Progress = struct {
|
||||
}
|
||||
|
||||
fn push(self: *Progress) void {
|
||||
// Throttle: Element X chokes on long m.replace edit chains, so cap
|
||||
// total edits per bubble and rate-limit to ~1 per 8 seconds. The
|
||||
// final state is always flushed by the caller (flush()).
|
||||
const now_ms: i64 = @intCast(@divTrunc(std.Io.Clock.now(.real, self.io).nanoseconds, std.time.ns_per_ms));
|
||||
if (self.edits_done >= PROGRESS_MAX_EDITS) return;
|
||||
if (now_ms - self.last_edit_ms < 8000 and self.edits_done > 0) return;
|
||||
self.last_edit_ms = now_ms;
|
||||
self.edits_done += 1;
|
||||
const id = self.event_id orelse {
|
||||
std.debug.print("DBG push: no event_id, blocks={d}\n", .{self.blocks.items.len});
|
||||
return;
|
||||
|
||||
Reference in new issue
Block a user