mirror of
https://github.com/block/buzz.git
synced 2026-11-01 23:11:58 +00:00
fix(desktop): arm mention-first agent prewake
Signed-off-by: Jitter <d14dfe033ef0f809866f9f984de04821b0d900d7652fd85a54776ee40ca3a68f@buzz.block.builderlab.xyz>
This commit is contained in:
@@ -217,6 +217,7 @@ function MessageComposerImpl({
|
||||
const syncAddressedAgentsFromTextRef = React.useRef<(text: string) => void>(
|
||||
() => {},
|
||||
);
|
||||
const prepareMentionWakeRef = React.useRef<(text: string) => void>(() => {});
|
||||
disabledRef.current = disabled;
|
||||
isSendingRef.current = isSending;
|
||||
isUploadingRef.current = media.isUploading;
|
||||
@@ -274,6 +275,7 @@ function MessageComposerImpl({
|
||||
onUpdate: ({ cursor, linkPreviewContent, text }) => {
|
||||
trackAuthoredContent(text);
|
||||
contentRef.current = text;
|
||||
prepareMentionWakeRef.current(text);
|
||||
setComposerContentFromText(text);
|
||||
setPreviewContent(linkPreviewContent);
|
||||
if (!isSubmitLockedRef.current && !editTargetRef.current) {
|
||||
@@ -373,6 +375,7 @@ function MessageComposerImpl({
|
||||
restoreQueuedAttachments: media.restoreQueuedAttachments,
|
||||
setSpoileredAttachmentUrls,
|
||||
});
|
||||
prepareMentionWakeRef.current = mentionSendFlow.prepareMentionWake;
|
||||
React.useEffect(() => {
|
||||
onDeferredEditPendingChange?.(isDeferredEditPending);
|
||||
return () => onDeferredEditPendingChange?.(false);
|
||||
|
||||
@@ -116,9 +116,8 @@ export function useMentionSendFlow({
|
||||
agents.map((agent) => [normalizePubkey(agent.pubkey), agent]),
|
||||
);
|
||||
}, [managedAgentsQuery.refetch, queryClient]);
|
||||
useMentionWakePreflight({
|
||||
const { prepareMentionWake } = useMentionWakePreflight({
|
||||
channelId,
|
||||
content: contentRef.current,
|
||||
contentRef,
|
||||
enabled:
|
||||
mentionWakeEnabled &&
|
||||
@@ -984,6 +983,7 @@ export function useMentionSendFlow({
|
||||
onInvite: handleInviteNonMembers,
|
||||
open: pendingNonMemberSend !== null,
|
||||
},
|
||||
prepareMentionWake,
|
||||
sendMessageWithMentionFlow,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -72,6 +72,37 @@ test("wake plan rejects non-member managed agents", () => {
|
||||
);
|
||||
});
|
||||
|
||||
test("editor updates arm a mention-first draft without a rerender", async (t) => {
|
||||
t.mock.timers.enable({ apis: ["setTimeout"] });
|
||||
const { act, renderHook } = await import("@testing-library/react");
|
||||
let starts = 0;
|
||||
const contentRef = { current: "@Fizz " };
|
||||
const view = renderHook(() =>
|
||||
useMentionWakePreflight({
|
||||
channelId: "general",
|
||||
contentRef,
|
||||
enabled: true,
|
||||
expectedRelayUrl: "wss://relay.example",
|
||||
expectedSignerPubkey: "c".repeat(64),
|
||||
getDraftMentionRefs: () => [fizzRef],
|
||||
getManagedAgentsByPubkey: async () =>
|
||||
new Map([[AGENT, { pubkey: AGENT, status: "stopped" }]]),
|
||||
isManagedAgentPubkey: () => true,
|
||||
memberPubkeys: new Set([AGENT]),
|
||||
startManagedAgent: async () => {
|
||||
starts += 1;
|
||||
return { pubkey: AGENT, status: "running" };
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
contentRef.current = "@Fizz please investigate";
|
||||
act(() => view.result.current.prepareMentionWake(contentRef.current));
|
||||
await act(async () => t.mock.timers.tick(MENTION_WAKE_DELAY_MS));
|
||||
|
||||
assert.equal(starts, 1);
|
||||
});
|
||||
|
||||
test("unmount prevents a wake after an in-flight lookup resolves", async (t) => {
|
||||
t.mock.timers.enable({ apis: ["setTimeout"] });
|
||||
const { act, renderHook } = await import("@testing-library/react");
|
||||
@@ -84,7 +115,6 @@ test("unmount prevents a wake after an in-flight lookup resolves", async (t) =>
|
||||
const view = renderHook(() =>
|
||||
useMentionWakePreflight({
|
||||
channelId: "general",
|
||||
content: contentRef.current,
|
||||
contentRef,
|
||||
enabled: true,
|
||||
expectedRelayUrl: "wss://relay.example",
|
||||
|
||||
@@ -68,7 +68,6 @@ export function buildMentionWakePlan({
|
||||
|
||||
export function useMentionWakePreflight({
|
||||
channelId,
|
||||
content,
|
||||
contentRef,
|
||||
enabled,
|
||||
expectedRelayUrl,
|
||||
@@ -80,7 +79,6 @@ export function useMentionWakePreflight({
|
||||
startManagedAgent,
|
||||
}: {
|
||||
channelId: string | null;
|
||||
content: string;
|
||||
contentRef: React.MutableRefObject<string>;
|
||||
enabled: boolean;
|
||||
expectedRelayUrl?: string;
|
||||
@@ -196,10 +194,10 @@ export function useMentionWakePreflight({
|
||||
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: contextRef keeps callbacks fresh; these inputs are plan invalidation signals.
|
||||
React.useEffect(() => {
|
||||
prepareMentionWake(content);
|
||||
prepareMentionWake(contentRef.current);
|
||||
}, [
|
||||
channelId,
|
||||
content,
|
||||
contentRef,
|
||||
enabled,
|
||||
expectedRelayUrl,
|
||||
expectedSignerPubkey,
|
||||
@@ -210,4 +208,6 @@ export function useMentionWakePreflight({
|
||||
]);
|
||||
|
||||
React.useEffect(() => cancelMentionWake, [cancelMentionWake]);
|
||||
|
||||
return { prepareMentionWake };
|
||||
}
|
||||
|
||||
@@ -2085,13 +2085,16 @@ test("substantive in-channel managed-agent mentions wake before send", async ({
|
||||
"start_managed_agent",
|
||||
);
|
||||
const input = page.getByTestId("message-input");
|
||||
await input.fill("Hey @fizz");
|
||||
await input.fill("@fizz");
|
||||
|
||||
const dropdown = autocomplete(page);
|
||||
await expect(dropdown.getByText("fizz")).toBeVisible();
|
||||
await expect(dropdown.getByText("agent")).toBeVisible();
|
||||
await input.press("Enter");
|
||||
await page.keyboard.type(" can you help?");
|
||||
await page.keyboard.type(
|
||||
" Can you investigate this? Please report what you find.",
|
||||
{ delay: 75 },
|
||||
);
|
||||
|
||||
await expect
|
||||
.poll(
|
||||
|
||||
Reference in New Issue
Block a user