fix: delay typing until reply payload

This commit is contained in:
Peter Steinberger
2025-12-23 13:55:01 +00:00
parent cba12a1abd
commit 863d26558a
2 changed files with 28 additions and 11 deletions

View File

@@ -17,6 +17,7 @@
- Tailscale Funnel now requires password auth (no token-only public exposure).
- Group `/new` resets now work with @mentions so activation guidance appears on fresh sessions.
- Group chat activation context is now injected into the system prompt at session start (and after activation changes), including /new greetings.
- Typing indicators now start only once a reply payload is produced (no "thinking" typing for silent runs).
- Canvas defaults/A2UI auto-nav aligned; debug status overlay centered; redundant await removed in `CanvasManager`.
- Gateway launchd loop fixed by removing redundant `kickstart -k`.
- CLI now hints when Peekaboo is unauthorized.

View File

@@ -201,11 +201,17 @@ export async function getReplyFromConfig(
if (!opts?.onReplyStart) return;
if (typingIntervalMs <= 0) return;
if (typingTimer) return;
await triggerTyping();
await onReplyStart();
typingTimer = setInterval(() => {
void triggerTyping();
}, typingIntervalMs);
};
const startTypingOnText = async (text?: string) => {
const trimmed = text?.trim();
if (!trimmed) return;
if (trimmed === SILENT_REPLY_TOKEN) return;
await startTypingLoop();
};
let transcribedText: string | undefined;
// Optional audio transcription before templating/session handling.
@@ -646,8 +652,6 @@ export async function getReplyFromConfig(
return { text: "⚙️ Agent was aborted." };
}
await startTypingLoop();
const isFirstTurnInSession = isNewSession || !systemSent;
const shouldInjectGroupIntro =
sessionCtx.ChatType === "group" &&
@@ -865,8 +869,6 @@ export async function getReplyFromConfig(
return undefined;
}
await onReplyStart();
try {
const runId = crypto.randomUUID();
const runResult = await runEmbeddedPiAgent({
@@ -884,19 +886,23 @@ export async function getReplyFromConfig(
timeoutMs,
runId,
onPartialReply: opts?.onPartialReply
? (payload) =>
opts.onPartialReply?.({
? async (payload) => {
await startTypingOnText(payload.text);
await opts.onPartialReply?.({
text: payload.text,
mediaUrls: payload.mediaUrls,
})
});
}
: undefined,
shouldEmitToolResult,
onToolResult: opts?.onToolResult
? (payload) =>
opts.onToolResult?.({
? async (payload) => {
await startTypingOnText(payload.text);
await opts.onToolResult?.({
text: payload.text,
mediaUrls: payload.mediaUrls,
})
});
}
: undefined,
});
@@ -915,6 +921,16 @@ export async function getReplyFromConfig(
const payloadArray = runResult.payloads ?? [];
if (payloadArray.length === 0) return undefined;
const shouldSignalTyping = payloadArray.some((payload) => {
const trimmed = payload.text?.trim();
if (trimmed && trimmed !== SILENT_REPLY_TOKEN) return true;
if (payload.mediaUrl) return true;
if (payload.mediaUrls && payload.mediaUrls.length > 0) return true;
return false;
});
if (shouldSignalTyping) {
await onReplyStart();
}
if (sessionStore && sessionKey) {
const usage = runResult.meta.agentMeta?.usage;