fix: delay typing until reply payload
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user