Merge pull request #619 from rubyrunsstuff/fix/telegram-block-streaming
fix: enable block streaming for Telegram when streamMode is 'block'
This commit is contained in:
@@ -39,6 +39,7 @@
|
|||||||
- Auth: default billing disable backoff to 5h (doubling, 24h cap) and surface disabled/cooldown profiles in `models list` + doctor. (#486) — thanks @steipete
|
- Auth: default billing disable backoff to 5h (doubling, 24h cap) and surface disabled/cooldown profiles in `models list` + doctor. (#486) — thanks @steipete
|
||||||
- Commands: harden slash command registry and list text-only commands in `/commands`.
|
- Commands: harden slash command registry and list text-only commands in `/commands`.
|
||||||
- Models/Auth: show per-agent auth candidates in `/model status`, and add `clawdbot models auth order {get,set,clear}` (per-agent auth rotation overrides). — thanks @steipete
|
- Models/Auth: show per-agent auth candidates in `/model status`, and add `clawdbot models auth order {get,set,clear}` (per-agent auth rotation overrides). — thanks @steipete
|
||||||
|
- Telegram: keep streamMode draft-only; avoid forcing block streaming. (#619) — thanks @rubyrunsstuff
|
||||||
- Debugging: add raw model stream logging flags and document gateway watch mode.
|
- Debugging: add raw model stream logging flags and document gateway watch mode.
|
||||||
- Gateway: decode dns-sd escaped UTF-8 in discovery output and show scan progress immediately. — thanks @steipete
|
- Gateway: decode dns-sd escaped UTF-8 in discovery output and show scan progress immediately. — thanks @steipete
|
||||||
- Agent: add claude-cli/opus-4.5 runner via Claude CLI with resume support (tools disabled).
|
- Agent: add claude-cli/opus-4.5 runner via Claude CLI with resume support (tools disabled).
|
||||||
|
|||||||
@@ -221,6 +221,10 @@ export class EmbeddedBlockChunker {
|
|||||||
if (sentenceIdx >= minChars) return { index: sentenceIdx };
|
if (sentenceIdx >= minChars) return { index: sentenceIdx };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (preference === "newline" && buffer.length < maxChars) {
|
||||||
|
return { index: -1 };
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = window.length - 1; i >= minChars; i--) {
|
for (let i = window.length - 1; i >= minChars; i--) {
|
||||||
if (/\s/.test(window[i]) && isSafeFenceBreak(fenceSpans, i)) {
|
if (/\s/.test(window[i]) && isSafeFenceBreak(fenceSpans, i)) {
|
||||||
return { index: i };
|
return { index: i };
|
||||||
|
|||||||
@@ -273,4 +273,45 @@ describe("block streaming", () => {
|
|||||||
expect(sawAbort).toBe(true);
|
expect(sawAbort).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("does not enable block streaming for telegram streamMode block", async () => {
|
||||||
|
await withTempHome(async (home) => {
|
||||||
|
const onBlockReply = vi.fn().mockResolvedValue(undefined);
|
||||||
|
|
||||||
|
const impl = async () => ({
|
||||||
|
payloads: [{ text: "final" }],
|
||||||
|
meta: {
|
||||||
|
durationMs: 5,
|
||||||
|
agentMeta: { sessionId: "s", provider: "p", model: "m" },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
piEmbeddedMock.runEmbeddedPiAgent.mockImplementation(impl);
|
||||||
|
|
||||||
|
const res = await getReplyFromConfig(
|
||||||
|
{
|
||||||
|
Body: "ping",
|
||||||
|
From: "+1004",
|
||||||
|
To: "+2000",
|
||||||
|
MessageSid: "msg-126",
|
||||||
|
Provider: "telegram",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onBlockReply,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
agents: {
|
||||||
|
defaults: {
|
||||||
|
model: "anthropic/claude-opus-4-5",
|
||||||
|
workspace: path.join(home, "clawd"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
telegram: { allowFrom: ["*"], streamMode: "block" },
|
||||||
|
session: { store: path.join(home, "sessions.json") },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(res?.text).toBe("final");
|
||||||
|
expect(onBlockReply).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -58,9 +58,10 @@ export function resolveBlockStreamingChunking(
|
|||||||
Math.floor(chunkCfg?.maxChars ?? DEFAULT_BLOCK_STREAM_MAX),
|
Math.floor(chunkCfg?.maxChars ?? DEFAULT_BLOCK_STREAM_MAX),
|
||||||
);
|
);
|
||||||
const maxChars = Math.max(1, Math.min(maxRequested, textLimit));
|
const maxChars = Math.max(1, Math.min(maxRequested, textLimit));
|
||||||
|
const minFallback = DEFAULT_BLOCK_STREAM_MIN;
|
||||||
const minRequested = Math.max(
|
const minRequested = Math.max(
|
||||||
1,
|
1,
|
||||||
Math.floor(chunkCfg?.minChars ?? DEFAULT_BLOCK_STREAM_MIN),
|
Math.floor(chunkCfg?.minChars ?? minFallback),
|
||||||
);
|
);
|
||||||
const minChars = Math.min(minRequested, maxChars);
|
const minChars = Math.min(minRequested, maxChars);
|
||||||
const breakPreference =
|
const breakPreference =
|
||||||
@@ -80,7 +81,7 @@ export function resolveBlockStreamingCoalescing(
|
|||||||
maxChars: number;
|
maxChars: number;
|
||||||
breakPreference: "paragraph" | "newline" | "sentence";
|
breakPreference: "paragraph" | "newline" | "sentence";
|
||||||
},
|
},
|
||||||
): BlockStreamingCoalescing {
|
): BlockStreamingCoalescing | undefined {
|
||||||
const providerKey = normalizeChunkProvider(provider);
|
const providerKey = normalizeChunkProvider(provider);
|
||||||
const textLimit = resolveTextChunkLimit(cfg, providerKey, accountId);
|
const textLimit = resolveTextChunkLimit(cfg, providerKey, accountId);
|
||||||
const normalizedAccountId = normalizeAccountId(accountId);
|
const normalizedAccountId = normalizeAccountId(accountId);
|
||||||
|
|||||||
@@ -826,6 +826,12 @@ export function createTelegramBot(opts: TelegramBotOptions) {
|
|||||||
onReplyStart: sendTyping,
|
onReplyStart: sendTyping,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const disableBlockStreaming =
|
||||||
|
Boolean(draftStream) ||
|
||||||
|
(typeof telegramCfg.blockStreaming === "boolean"
|
||||||
|
? !telegramCfg.blockStreaming
|
||||||
|
: undefined);
|
||||||
|
|
||||||
const { queuedFinal } = await dispatchReplyFromConfig({
|
const { queuedFinal } = await dispatchReplyFromConfig({
|
||||||
ctx: ctxPayload,
|
ctx: ctxPayload,
|
||||||
cfg,
|
cfg,
|
||||||
@@ -841,11 +847,7 @@ export function createTelegramBot(opts: TelegramBotOptions) {
|
|||||||
if (payload.text) draftStream.update(payload.text);
|
if (payload.text) draftStream.update(payload.text);
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
disableBlockStreaming:
|
disableBlockStreaming,
|
||||||
Boolean(draftStream) ||
|
|
||||||
(typeof telegramCfg.blockStreaming === "boolean"
|
|
||||||
? !telegramCfg.blockStreaming
|
|
||||||
: undefined),
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
markDispatchIdle();
|
markDispatchIdle();
|
||||||
|
|||||||
Reference in New Issue
Block a user