Typing: keep indicators active during tool runs
Closes #450 Closes #447
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
- Memory: allow custom OpenAI-compatible embedding endpoints for memory search (remote baseUrl/apiKey/headers). (#819 — thanks @mukhtharcm)
|
- Memory: allow custom OpenAI-compatible embedding endpoints for memory search (remote baseUrl/apiKey/headers). (#819 — thanks @mukhtharcm)
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
- Typing: keep typing indicators alive during tool execution. (#450, #447 — thanks @thewilloftheshadow)
|
||||||
- Cron: coerce enabled patches so disabling jobs persists correctly. (#205 — thanks @thewilloftheshadow)
|
- Cron: coerce enabled patches so disabling jobs persists correctly. (#205 — thanks @thewilloftheshadow)
|
||||||
- Control UI: keep chat scroll position unless user is near the bottom. (#217 — thanks @thewilloftheshadow)
|
- Control UI: keep chat scroll position unless user is near the bottom. (#217 — thanks @thewilloftheshadow)
|
||||||
- Fallback: treat credential validation failures ("no credentials found", "no API key found") as auth errors that trigger model fallback. (#822 — thanks @sebslight)
|
- Fallback: treat credential validation failures ("no credentials found", "no API key found") as auth errors that trigger model fallback. (#822 — thanks @sebslight)
|
||||||
|
|||||||
@@ -704,7 +704,7 @@ export async function runReplyAgent(params: {
|
|||||||
if (evt.stream === "tool") {
|
if (evt.stream === "tool") {
|
||||||
const phase =
|
const phase =
|
||||||
typeof evt.data.phase === "string" ? evt.data.phase : "";
|
typeof evt.data.phase === "string" ? evt.data.phase : "";
|
||||||
if (phase === "start") {
|
if (phase === "start" || phase === "update") {
|
||||||
void typingSignals.signalToolStart();
|
void typingSignals.signalToolStart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ describe("createTypingSignaler", () => {
|
|||||||
expect(typing.startTypingOnText).not.toHaveBeenCalled();
|
expect(typing.startTypingOnText).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not start typing on tool start when inactive", async () => {
|
it("starts typing on tool start when inactive", async () => {
|
||||||
const typing = createMockTypingController();
|
const typing = createMockTypingController();
|
||||||
const signaler = createTypingSignaler({
|
const signaler = createTypingSignaler({
|
||||||
typing,
|
typing,
|
||||||
@@ -133,8 +133,8 @@ describe("createTypingSignaler", () => {
|
|||||||
|
|
||||||
await signaler.signalToolStart();
|
await signaler.signalToolStart();
|
||||||
|
|
||||||
expect(typing.refreshTypingTtl).not.toHaveBeenCalled();
|
expect(typing.startTypingLoop).toHaveBeenCalled();
|
||||||
expect(typing.startTypingLoop).not.toHaveBeenCalled();
|
expect(typing.refreshTypingTtl).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("refreshes ttl on tool start when active", async () => {
|
it("refreshes ttl on tool start when active", async () => {
|
||||||
|
|||||||
@@ -68,7 +68,11 @@ export function createTypingSignaler(params: {
|
|||||||
|
|
||||||
const signalToolStart = async () => {
|
const signalToolStart = async () => {
|
||||||
if (disabled) return;
|
if (disabled) return;
|
||||||
if (!typing.isActive()) return;
|
if (!typing.isActive()) {
|
||||||
|
await typing.startTypingLoop();
|
||||||
|
typing.refreshTypingTtl();
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Keep typing indicator alive during tool execution without changing mode semantics.
|
// Keep typing indicator alive during tool execution without changing mode semantics.
|
||||||
typing.refreshTypingTtl();
|
typing.refreshTypingTtl();
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user