@blocksdiy/react-common 1.47.0 → 1.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/new-agent-chat.d.ts +14 -24
- package/dist/components/new-agent-chat.d.ts.map +1 -1
- package/dist/components/new-agent-chat.js +120 -74
- package/dist/hooks/agent-conversation-context.d.ts +32 -0
- package/dist/hooks/agent-conversation-context.d.ts.map +1 -0
- package/dist/hooks/agent-conversation-context.js +39 -0
- package/dist/hooks/agent-thread-live-update.d.ts +35 -64
- package/dist/hooks/agent-thread-live-update.d.ts.map +1 -1
- package/dist/hooks/agent-thread-live-update.js +81 -64
- package/dist/hooks/use-agent-conversation.d.ts +105 -0
- package/dist/hooks/use-agent-conversation.d.ts.map +1 -0
- package/dist/hooks/use-agent-conversation.js +204 -0
- package/dist/hooks/use-agent-threads.d.ts +3 -50
- package/dist/hooks/use-agent-threads.d.ts.map +1 -1
- package/dist/hooks/use-agent-threads.js +53 -150
- package/dist/utils/composer-message.d.ts +57 -0
- package/dist/utils/composer-message.d.ts.map +1 -0
- package/dist/utils/composer-message.js +96 -0
- package/dist/utils/message-run-ids.d.ts +23 -3
- package/dist/utils/message-run-ids.d.ts.map +1 -1
- package/dist/utils/message-run-ids.js +45 -13
- package/package.json +2 -2
|
@@ -2,9 +2,11 @@ import { type Message, ToolMessage, type UserMessage } from "@ag-ui/client";
|
|
|
2
2
|
import { useRenderToolCall } from "@copilotkit/react-core/v2";
|
|
3
3
|
import { ReactNode, SetStateAction } from "react";
|
|
4
4
|
import { type RenderProp } from "../utils/compose-render.js";
|
|
5
|
-
import { type
|
|
5
|
+
import { type ComposerMessageMeta } from "../utils/composer-message.js";
|
|
6
|
+
import { type MessageRunIds, type RunStartedAt } from "../utils/message-run-ids.js";
|
|
6
7
|
export { useTextGrowthAnimating } from "../hooks/text-growth-animation.js";
|
|
7
|
-
export {
|
|
8
|
+
export { type ComposerMessageMeta, FEEDBACK_MESSAGE_NAME, type FeedbackDraft, type FeedbackRate, feedbackComposerMeta, feedbackDraftOf, feedbackMessage, feedbackThreadId, isFeedbackMessage, isFeedbackTag, parseFeedbackContent, parseFeedbackTag, type ParsedFeedback, } from "../utils/composer-message.js";
|
|
9
|
+
export { MESSAGE_RUN_IDS_EVENT_NAME, messageIdsOfRun, type MessageRunIds, type RunStartedAt, } from "../utils/message-run-ids.js";
|
|
8
10
|
export { type Message, type AssistantMessage, type UserMessage } from "@ag-ui/client";
|
|
9
11
|
export { useRenderTool, useDefaultRenderTool, useHumanInTheLoop, useFrontendTool, ToolCallStatus, } from "@copilotkit/react-core/v2";
|
|
10
12
|
export interface Attachment {
|
|
@@ -43,6 +45,7 @@ export interface Agent {
|
|
|
43
45
|
voiceId?: string;
|
|
44
46
|
harness?: string;
|
|
45
47
|
}
|
|
48
|
+
export type OnUserMessageSent = (text: string, message: Omit<UserMessage, "id" | "role">) => void;
|
|
46
49
|
export interface AgentChatContextValue {
|
|
47
50
|
messages: Message[];
|
|
48
51
|
attachments: Attachment[];
|
|
@@ -60,33 +63,14 @@ export interface AgentChatContextValue {
|
|
|
60
63
|
role: "assistant" | "user";
|
|
61
64
|
}[];
|
|
62
65
|
messageById: Map<string, Message>;
|
|
63
|
-
/**
|
|
64
|
-
* The agent run (turn) that produced each replayed message — the `agentRunId` the rows
|
|
65
|
-
* it wrote carry. Filled from the connect replay; messages from before run attribution
|
|
66
|
-
* (and live-streamed ones) have no entry. Optional so contexts a host builds by hand
|
|
67
|
-
* (previews, stubs) need not state it; absent reads as "no run known".
|
|
68
|
-
*/
|
|
69
66
|
runIdByMessageId?: MessageRunIds;
|
|
67
|
+
runStartedAt?: RunStartedAt;
|
|
70
68
|
toolMessages: ToolMessage[];
|
|
71
69
|
renderToolCall: ReturnType<typeof useRenderToolCall>;
|
|
72
70
|
sendMessage: (message: Omit<UserMessage, "id" | "role">) => Promise<void>;
|
|
73
71
|
sendFromInputs: () => Promise<void>;
|
|
74
|
-
/**
|
|
75
|
-
* Replay this conversation's transcript from the server, in place.
|
|
76
|
-
*
|
|
77
|
-
* The same round-trip a fresh mount does — the connect endpoint reads the checkpoint and
|
|
78
|
-
* answers with a MESSAGES_SNAPSHOT, which replaces the mirrored list. For turns that ran
|
|
79
|
-
* SERVER-SIDE, which no client streamed and so no client has: without this they appear only
|
|
80
|
-
* after a reload or a conversation switch.
|
|
81
|
-
*
|
|
82
|
-
* A no-op while a run is in flight: that run's own stream is the authoritative view of the
|
|
83
|
-
* conversation, and replacing the list underneath it would fight the events still arriving.
|
|
84
|
-
*/
|
|
85
72
|
reloadMessages: () => Promise<void>;
|
|
86
|
-
/** Resumes a run parked on a server-side interrupt. Rejects if the resume fails. */
|
|
87
|
-
/** Resolves false when a run was already in flight, so nothing was sent. */
|
|
88
73
|
resolveInterrupt: (resume: unknown) => Promise<boolean>;
|
|
89
|
-
/** Answers one parked card; resumes once every card of the turn is answered. */
|
|
90
74
|
answerInterrupt: (answer: {
|
|
91
75
|
toolCallId: string;
|
|
92
76
|
answer: unknown;
|
|
@@ -99,6 +83,10 @@ export interface AgentChatContextValue {
|
|
|
99
83
|
setAttachments: React.Dispatch<SetStateAction<Attachment[]>>;
|
|
100
84
|
setIsDraggingFiles: React.Dispatch<SetStateAction<boolean>>;
|
|
101
85
|
setCurrentThreadId: (currentThreadId: string) => void;
|
|
86
|
+
/** Arms the next send; cleared by send and conversation switch. */
|
|
87
|
+
composerMessageMeta?: ComposerMessageMeta | null;
|
|
88
|
+
setComposerMessageMeta?: (meta: ComposerMessageMeta | null) => void;
|
|
89
|
+
setRunningElsewhere?: (runId: string | null) => void;
|
|
102
90
|
}
|
|
103
91
|
export declare const AgentChatContext: import("react").Context<AgentChatContextValue | null>;
|
|
104
92
|
export declare const useAgentChat: () => AgentChatContextValue;
|
|
@@ -140,9 +128,11 @@ export interface AgentChatRootProps {
|
|
|
140
128
|
* Fires once a user send has been added to the conversation, with its text (empty
|
|
141
129
|
* string for attachment-only sends) — the seam for ChatGPT-style optimistic thread
|
|
142
130
|
* listing: hosts pair it with useAgentThreads' notifyThreadActivity. Covers sends
|
|
143
|
-
* routed through `sendMessage`, not the auto-sent `initialPrompt`.
|
|
131
|
+
* routed through `sendMessage`, not the auto-sent `initialPrompt`. The second argument
|
|
132
|
+
* is the message as sent, for hosts that treat a protocol send (one carrying a `name`)
|
|
133
|
+
* differently from an ordinary turn.
|
|
144
134
|
*/
|
|
145
|
-
onUserMessageSent?:
|
|
135
|
+
onUserMessageSent?: OnUserMessageSent;
|
|
146
136
|
/**
|
|
147
137
|
* Skip the agent-chat block's `initialPrompt` auto-send. For surfaces that mint a fresh
|
|
148
138
|
* thread per conversation (an inbox's "New chat"): the auto-send fires once PER THREAD,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"new-agent-chat.d.ts","sourceRoot":"","sources":["../../src/components/new-agent-chat.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAI5E,OAAO,EAAiB,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,EAEL,SAAS,EACT,cAAc,EAQf,MAAM,OAAO,CAAC;AAGf,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,
|
|
1
|
+
{"version":3,"file":"new-agent-chat.d.ts","sourceRoot":"","sources":["../../src/components/new-agent-chat.tsx"],"names":[],"mappings":"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"}
|
|
@@ -6,9 +6,11 @@ import { useCopilotKit, useRenderToolCall } from "@copilotkit/react-core/v2";
|
|
|
6
6
|
import { createContext, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, } from "react";
|
|
7
7
|
import { useStickToBottom } from "use-stick-to-bottom";
|
|
8
8
|
import { ComposeRender } from "../utils/compose-render.js";
|
|
9
|
-
import {
|
|
9
|
+
import { buildArmedMessageContent, userTextOfContent } from "../utils/composer-message.js";
|
|
10
|
+
import { claimRunInput, EMPTY_MESSAGE_RUN_IDS, EMPTY_RUN_STARTED_AT, findMessageGroupElement, mergeEntries, MESSAGE_IDS_ATTRIBUTE, messageIdsOfRun, readMessageRunIdsEvent, readRunStartedAtEvent, } from "../utils/message-run-ids.js";
|
|
10
11
|
export { useTextGrowthAnimating } from "../hooks/text-growth-animation.js";
|
|
11
|
-
export {
|
|
12
|
+
export { FEEDBACK_MESSAGE_NAME, feedbackComposerMeta, feedbackDraftOf, feedbackMessage, feedbackThreadId, isFeedbackMessage, isFeedbackTag, parseFeedbackContent, parseFeedbackTag, } from "../utils/composer-message.js";
|
|
13
|
+
export { MESSAGE_RUN_IDS_EVENT_NAME, messageIdsOfRun, } from "../utils/message-run-ids.js";
|
|
12
14
|
export { useRenderTool, useDefaultRenderTool, useHumanInTheLoop, useFrontendTool, ToolCallStatus, } from "@copilotkit/react-core/v2";
|
|
13
15
|
// Client-only `useLayoutEffect`, falls back to `useEffect` during SSR.
|
|
14
16
|
// Needed so the `agent.threadId` mirror commits before CopilotKit's
|
|
@@ -173,9 +175,9 @@ const uploadAttachments = async ({ attachments, appId, token, }) => {
|
|
|
173
175
|
};
|
|
174
176
|
}));
|
|
175
177
|
};
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
178
|
+
// An armed send needs text: the composer is the comment path — a rating alone goes out as
|
|
179
|
+
// `feedbackMessage` — and an unrated marker on its own is an ordinary turn on the server.
|
|
180
|
+
const hasSendableInput = (prompt, attachments, meta) => prompt.trim().length > 0 || (!meta && attachments.length > 0);
|
|
179
181
|
const isRecord = (value) => {
|
|
180
182
|
return typeof value === "object" && value !== null;
|
|
181
183
|
};
|
|
@@ -311,22 +313,57 @@ const ChatInitializer = ({ agentBlock, agentChatBlock, chatId, token, appId, com
|
|
|
311
313
|
});
|
|
312
314
|
return groups;
|
|
313
315
|
}, [copilotMessages]);
|
|
314
|
-
// Which run produced each replayed message: the connect replay sends it as a CUSTOM
|
|
315
|
-
// event (see utils/message-run-ids). Cleared with the transcript on a conversation swap.
|
|
316
316
|
const [runIdByMessageId, setRunIdByMessageId] = useState(EMPTY_MESSAGE_RUN_IDS);
|
|
317
|
+
const [runStartedAt, setRunStartedAt] = useState(EMPTY_RUN_STARTED_AT);
|
|
318
|
+
const liveRunRef = useRef(null);
|
|
319
|
+
const ownRunIdsRef = useRef(new Set());
|
|
317
320
|
useEffect(() => {
|
|
318
321
|
if (!copilotAgent) {
|
|
319
322
|
return;
|
|
320
323
|
}
|
|
324
|
+
const claimLive = (messageId) => {
|
|
325
|
+
const run = liveRunRef.current;
|
|
326
|
+
if (!run) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
const { runId, startedAt, input } = run;
|
|
330
|
+
run.input = null;
|
|
331
|
+
if (input) {
|
|
332
|
+
setRunStartedAt((previous) => mergeEntries(previous, { [runId]: startedAt }));
|
|
333
|
+
}
|
|
334
|
+
setRunIdByMessageId((previous) => {
|
|
335
|
+
const claims = input ? claimRunInput(input, previous, runId) : {};
|
|
336
|
+
if (!previous.has(messageId)) {
|
|
337
|
+
claims[messageId] = runId;
|
|
338
|
+
}
|
|
339
|
+
return mergeEntries(previous, claims);
|
|
340
|
+
});
|
|
341
|
+
};
|
|
321
342
|
const { unsubscribe } = copilotAgent.subscribe({
|
|
343
|
+
onRunStartedEvent: ({ event, messages }) => {
|
|
344
|
+
liveRunRef.current = { runId: event.runId, startedAt: event.timestamp ?? Date.now(), input: messages };
|
|
345
|
+
ownRunIdsRef.current.add(event.runId);
|
|
346
|
+
},
|
|
347
|
+
onTextMessageStartEvent: ({ event }) => claimLive(event.messageId),
|
|
348
|
+
onToolCallStartEvent: ({ event }) => claimLive(event.parentMessageId ?? event.toolCallId),
|
|
349
|
+
onRunFinalized: () => {
|
|
350
|
+
liveRunRef.current = null;
|
|
351
|
+
},
|
|
322
352
|
onCustomEvent: ({ event }) => {
|
|
323
353
|
const runIds = readMessageRunIdsEvent(event);
|
|
324
354
|
if (runIds) {
|
|
325
|
-
setRunIdByMessageId((previous) =>
|
|
355
|
+
setRunIdByMessageId((previous) => mergeEntries(previous, runIds));
|
|
356
|
+
}
|
|
357
|
+
const startedAt = readRunStartedAtEvent(event);
|
|
358
|
+
if (startedAt) {
|
|
359
|
+
setRunStartedAt((previous) => mergeEntries(previous, startedAt));
|
|
326
360
|
}
|
|
327
361
|
},
|
|
328
362
|
});
|
|
329
|
-
return
|
|
363
|
+
return () => {
|
|
364
|
+
unsubscribe();
|
|
365
|
+
liveRunRef.current = null;
|
|
366
|
+
};
|
|
330
367
|
}, [copilotAgent]);
|
|
331
368
|
const interruptAnswersRef = useRef(new Map());
|
|
332
369
|
// Mirror `currentThreadId` onto the agent instance — the `<CopilotKit>`
|
|
@@ -346,11 +383,13 @@ const ChatInitializer = ({ agentBlock, agentChatBlock, chatId, token, appId, com
|
|
|
346
383
|
}, [copilotAgent, currentThreadId]);
|
|
347
384
|
const [prompt, setPrompt] = useState("");
|
|
348
385
|
const [attachments, setAttachments] = useState([]);
|
|
349
|
-
|
|
350
|
-
//
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
386
|
+
const [composerMessageMeta, setComposerMessageMeta] = useState(null);
|
|
387
|
+
// setRunningElsewhere: a run elsewhere reads as this chat's own; own runs match RUN_STARTED id; refused at send time via ref (upload awaits).
|
|
388
|
+
const [runningElsewhereRunId, setRunningElsewhere] = useState(null);
|
|
389
|
+
const [ownRunInFlight, setOwnRunInFlight] = useState(false);
|
|
390
|
+
const isRunningElsewhere = runningElsewhereRunId !== null && !ownRunInFlight && !ownRunIdsRef.current.has(runningElsewhereRunId);
|
|
391
|
+
const isRunningElsewhereRef = useRef(isRunningElsewhere);
|
|
392
|
+
isRunningElsewhereRef.current = isRunningElsewhere;
|
|
354
393
|
const conversationKey = `${chatId ?? ""}|${currentThreadId ?? ""}`;
|
|
355
394
|
const prevConversationKeyRef = useRef(conversationKey);
|
|
356
395
|
useIsomorphicLayoutEffect(() => {
|
|
@@ -360,16 +399,11 @@ const ChatInitializer = ({ agentBlock, agentChatBlock, chatId, token, appId, com
|
|
|
360
399
|
prevConversationKeyRef.current = conversationKey;
|
|
361
400
|
copilotAgent?.setMessages?.([]);
|
|
362
401
|
setRunIdByMessageId(EMPTY_MESSAGE_RUN_IDS);
|
|
402
|
+
setRunStartedAt(EMPTY_RUN_STARTED_AT);
|
|
363
403
|
setPrompt("");
|
|
364
404
|
setAttachments([]);
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
// apply pipeline keep applying, each reassigning `agent.messages` WHOLESALE. One late
|
|
368
|
-
// chunk would resurrect the entire previous transcript (and re-arm its auto-executing
|
|
369
|
-
// tool-call follow-ups) under the new conversation's header. Detach here too and
|
|
370
|
-
// re-clear once the drain settles; the reconnect that follows replays on top of the
|
|
371
|
-
// (guaranteed-empty) mirror. On threadId switches the core's fresh-restore re-clears
|
|
372
|
-
// as well — harmless overlap — but on chatId-only switches this is the only re-clear.
|
|
405
|
+
setComposerMessageMeta(null);
|
|
406
|
+
setOwnRunInFlight(false);
|
|
373
407
|
const detachable = copilotAgent;
|
|
374
408
|
const drained = detachable?.detachActiveRun?.();
|
|
375
409
|
if (drained) {
|
|
@@ -381,15 +415,6 @@ const ChatInitializer = ({ agentBlock, agentChatBlock, chatId, token, appId, com
|
|
|
381
415
|
});
|
|
382
416
|
}
|
|
383
417
|
}, [conversationKey]);
|
|
384
|
-
// CopilotKit reconnects only when its threadId changes — but a conversation is the
|
|
385
|
-
// (chatId, threadId) PAIR, and rows written by surfaces that use the fixed default
|
|
386
|
-
// thread id differ only by chatId. On such a chatId-only switch the library's connect
|
|
387
|
-
// effect sees unchanged deps and does nothing, which would leave the (just cleared)
|
|
388
|
-
// transcript empty forever. Reconnect manually, replicating the core's fresh-restore
|
|
389
|
-
// steps: reset state and drop the replay cursor — cursors are keyed by threadId, so
|
|
390
|
-
// the shared id makes the previous conversation's cursor actively wrong here — then
|
|
391
|
-
// connect (the core detaches any in-flight run itself). The core reads `properties`
|
|
392
|
-
// after an await, so the new chatId is already synced by the time the request builds.
|
|
393
418
|
const prevConnectionRef = useRef({ chatId, threadId: currentThreadId });
|
|
394
419
|
useEffect(() => {
|
|
395
420
|
const previous = prevConnectionRef.current;
|
|
@@ -401,23 +426,16 @@ const ChatInitializer = ({ agentBlock, agentChatBlock, chatId, token, appId, com
|
|
|
401
426
|
}
|
|
402
427
|
copilotAgent.setState?.({});
|
|
403
428
|
copilotAgent.clearReplayCursor?.(currentThreadId);
|
|
404
|
-
// Same guard convention as the composer send path: a failed reconnect already
|
|
405
|
-
// surfaces through the availability state; the rejection carries no extra signal.
|
|
406
429
|
void copilotkit.connectAgent({ agent: copilotAgent }).catch(() => undefined);
|
|
407
430
|
}, [chatId, currentThreadId, copilotAgent, copilotkit]);
|
|
408
431
|
const [isDraggingFiles, setIsDraggingFiles] = useState(false);
|
|
409
432
|
const attachmentsEnabled = agentChat ? agentChat.disableAttachments !== true : false;
|
|
410
|
-
const canSendMessage = Boolean(agentChatBlock && agentChat && agent && isConfigLoaded && isAgentReady && !isAgentRunning);
|
|
433
|
+
const canSendMessage = Boolean(agentChatBlock && agentChat && agent && isConfigLoaded && isAgentReady && !isAgentRunning && !isRunningElsewhere);
|
|
411
434
|
const isFetchingMessages = !isConfigLoaded || (!isAgentReady && copilotMessages.length === 0);
|
|
412
|
-
|
|
413
|
-
// thinking once the bootstrap connect phase has completed — and that needs the readiness
|
|
414
|
-
// latch, not just `isFetchingMessages`, which goes false as soon as ONE replayed message
|
|
415
|
-
// exists: without `isAgentReady`, thinking leaks true for the tail of every replay, and
|
|
416
|
-
// every load or thread switch flashes the typing dots under the transcript. Real runs are
|
|
417
|
-
// unaffected — sending requires readiness (canSendMessage), so the latch is already set.
|
|
418
|
-
const isThinking = isAgentRunning && !isFetchingMessages && isAgentReady;
|
|
435
|
+
const isThinking = (isAgentRunning || isRunningElsewhere) && !isFetchingMessages && isAgentReady;
|
|
419
436
|
const runAgentWithRetry = useCallback(async (agentToRun, messageCountAtRunStart, forwardedProps) => {
|
|
420
|
-
|
|
437
|
+
// A run elsewhere is on this conversation's checkpoint too: ours would race it.
|
|
438
|
+
if (agentToRun.isRunning || isRunningElsewhereRef.current) {
|
|
421
439
|
return false;
|
|
422
440
|
}
|
|
423
441
|
const runAgentAndThrowError = async () => {
|
|
@@ -440,8 +458,13 @@ const ChatInitializer = ({ agentBlock, agentChatBlock, chatId, token, appId, com
|
|
|
440
458
|
unsubscribe();
|
|
441
459
|
}
|
|
442
460
|
};
|
|
461
|
+
// In flight until the run ends, whichever way (see `runningElsewhereRunId`) — unless
|
|
462
|
+
// the conversation switched under it, which resets this itself.
|
|
463
|
+
const ranOn = prevConversationKeyRef.current;
|
|
464
|
+
setOwnRunInFlight(true);
|
|
443
465
|
try {
|
|
444
466
|
await runAgentAndThrowError();
|
|
467
|
+
return true;
|
|
445
468
|
}
|
|
446
469
|
catch (error) {
|
|
447
470
|
const hasAgentStartedResponding = agentToRun.messages.length > messageCountAtRunStart;
|
|
@@ -452,24 +475,19 @@ const ChatInitializer = ({ agentBlock, agentChatBlock, chatId, token, appId, com
|
|
|
452
475
|
}
|
|
453
476
|
throw error;
|
|
454
477
|
}
|
|
455
|
-
|
|
478
|
+
finally {
|
|
479
|
+
if (prevConversationKeyRef.current === ranOn) {
|
|
480
|
+
setOwnRunInFlight(false);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
456
483
|
}, [copilotkit]);
|
|
457
484
|
const sendMessage = useCallback(async (message) => {
|
|
458
|
-
if (!canSendMessage || !copilotAgent || copilotAgent.isRunning) {
|
|
485
|
+
if (!canSendMessage || !copilotAgent || copilotAgent.isRunning || isRunningElsewhereRef.current) {
|
|
459
486
|
return;
|
|
460
487
|
}
|
|
461
488
|
copilotAgent.addMessage({ ...message, id: generateId(), role: "user" });
|
|
462
|
-
// The send seam, fired once the message is IN the conversation, so hosts can react
|
|
463
|
-
// to it (e.g. list the thread optimistically). Covers every send routed through
|
|
464
|
-
// `sendMessage` — composer, empty-state heroes, user-generated chat components —
|
|
465
|
-
// but deliberately NOT the auto-sent `initialPrompt` below, whose hidden variant is
|
|
466
|
-
// a primer rather than something the user wrote.
|
|
467
489
|
if (onUserMessageSent) {
|
|
468
|
-
|
|
469
|
-
const textPart = Array.isArray(content)
|
|
470
|
-
? content.find((part) => part.type === "text")
|
|
471
|
-
: undefined;
|
|
472
|
-
onUserMessageSent(typeof content === "string" ? content : (textPart?.text ?? ""));
|
|
490
|
+
onUserMessageSent(userTextOfContent(message.content), message);
|
|
473
491
|
}
|
|
474
492
|
await runAgentWithRetry(copilotAgent, copilotAgent.messages.length);
|
|
475
493
|
}, [canSendMessage, copilotAgent, runAgentWithRetry, onUserMessageSent]);
|
|
@@ -477,14 +495,7 @@ const ChatInitializer = ({ agentBlock, agentChatBlock, chatId, token, appId, com
|
|
|
477
495
|
if (!copilotAgent || copilotAgent.isRunning) {
|
|
478
496
|
return;
|
|
479
497
|
}
|
|
480
|
-
// Replay cursors are keyed by threadId and record what has already been replayed, so a
|
|
481
|
-
// stale one makes connect a no-op — exactly the case here, where the thread is unchanged
|
|
482
|
-
// and only the server-side content moved. Messages are NOT cleared first: connect answers
|
|
483
|
-
// with a full snapshot that replaces them, and clearing would blank the transcript for the
|
|
484
|
-
// round-trip.
|
|
485
498
|
copilotAgent.clearReplayCursor?.(currentThreadId);
|
|
486
|
-
// Same guard convention as the composer send path: a failed reconnect already surfaces
|
|
487
|
-
// through the availability state; the rejection carries no extra signal.
|
|
488
499
|
await copilotkit.connectAgent({ agent: copilotAgent }).catch(() => undefined);
|
|
489
500
|
}, [copilotAgent, copilotkit, currentThreadId]);
|
|
490
501
|
// Not sourced from `useInterrupt`: that hook only hands `resolve` to its own
|
|
@@ -687,17 +698,44 @@ const ChatInitializer = ({ agentBlock, agentChatBlock, chatId, token, appId, com
|
|
|
687
698
|
return contentArray;
|
|
688
699
|
};
|
|
689
700
|
const sendFromInputs = async () => {
|
|
690
|
-
|
|
701
|
+
const currentMeta = composerMessageMeta;
|
|
702
|
+
if (!canSendMessage || !hasSendableInput(prompt, attachments, currentMeta)) {
|
|
691
703
|
return;
|
|
692
704
|
}
|
|
693
705
|
const currentPrompt = prompt;
|
|
694
|
-
const
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
706
|
+
const composedOn = prevConversationKeyRef.current;
|
|
707
|
+
if (currentMeta) {
|
|
708
|
+
setComposerMessageMeta(null);
|
|
709
|
+
}
|
|
710
|
+
let uploadedAttachments;
|
|
711
|
+
try {
|
|
712
|
+
uploadedAttachments = await uploadAttachments({
|
|
713
|
+
attachments,
|
|
714
|
+
appId,
|
|
715
|
+
token,
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
catch (error) {
|
|
719
|
+
// Failed upload: re-arm unless the conversation switched.
|
|
720
|
+
if (currentMeta && prevConversationKeyRef.current === composedOn) {
|
|
721
|
+
setComposerMessageMeta((armed) => armed ?? currentMeta);
|
|
722
|
+
}
|
|
723
|
+
throw error;
|
|
724
|
+
}
|
|
725
|
+
// Post-upload: conversation switch → stop; run elsewhere → keep input and re-arm; failed upload handled above.
|
|
726
|
+
if (prevConversationKeyRef.current !== composedOn) {
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
if (isRunningElsewhereRef.current || copilotAgent?.isRunning) {
|
|
730
|
+
if (currentMeta) {
|
|
731
|
+
setComposerMessageMeta((armed) => armed ?? currentMeta);
|
|
732
|
+
}
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
const composed = buildMessageContentFromInput(currentPrompt, uploadedAttachments ?? []);
|
|
736
|
+
const messageContent = currentMeta
|
|
737
|
+
? buildArmedMessageContent(currentMeta, composed)
|
|
738
|
+
: composed;
|
|
701
739
|
setPrompt("");
|
|
702
740
|
setAttachments([]);
|
|
703
741
|
// Auto-skip any frontend user-choice tool call that's still waiting.
|
|
@@ -743,7 +781,7 @@ const ChatInitializer = ({ agentBlock, agentChatBlock, chatId, token, appId, com
|
|
|
743
781
|
});
|
|
744
782
|
}
|
|
745
783
|
}
|
|
746
|
-
await sendMessage({ content: messageContent }).catch(() => undefined);
|
|
784
|
+
await sendMessage(currentMeta?.name ? { content: messageContent, name: currentMeta.name } : { content: messageContent }).catch(() => undefined);
|
|
747
785
|
};
|
|
748
786
|
const addAttachments = (attachments) => {
|
|
749
787
|
if (!attachmentsEnabled) {
|
|
@@ -776,6 +814,7 @@ const ChatInitializer = ({ agentBlock, agentChatBlock, chatId, token, appId, com
|
|
|
776
814
|
renderToolCall,
|
|
777
815
|
messageById,
|
|
778
816
|
runIdByMessageId,
|
|
817
|
+
runStartedAt,
|
|
779
818
|
toolMessages,
|
|
780
819
|
prompt,
|
|
781
820
|
attachments,
|
|
@@ -792,6 +831,9 @@ const ChatInitializer = ({ agentBlock, agentChatBlock, chatId, token, appId, com
|
|
|
792
831
|
setAttachments: setChatAttachments,
|
|
793
832
|
setIsDraggingFiles: setChatIsDraggingFiles,
|
|
794
833
|
setCurrentThreadId,
|
|
834
|
+
composerMessageMeta,
|
|
835
|
+
setComposerMessageMeta,
|
|
836
|
+
setRunningElsewhere,
|
|
795
837
|
isDraggingFiles,
|
|
796
838
|
isFetchingMessages,
|
|
797
839
|
isThinking,
|
|
@@ -1057,10 +1099,10 @@ export function AgentChatFetching({ asChild = false, render, ...props }) {
|
|
|
1057
1099
|
return (_jsx(ComposeRender, { render: render, asChild: asChild, defaultTag: "div", "data-state": isFetchingMessages ? "open" : "closed", "data-slot": "agent-chat-fetching", ...props }));
|
|
1058
1100
|
}
|
|
1059
1101
|
export function AgentChatInput({ asChild = false, render, onChange, onKeyDown, onPaste, onDragOver, onDragLeave, onDrop, onSubmit, ...props }) {
|
|
1060
|
-
const { setIsDraggingFiles, addAttachments, attachments, prompt, setPrompt, sendFromInputs, isThinking, isAgentReady, isFetchingMessages, agentChat, } = useAgentChat();
|
|
1102
|
+
const { setIsDraggingFiles, addAttachments, attachments, prompt, setPrompt, sendFromInputs, isThinking, isAgentReady, isFetchingMessages, agentChat, composerMessageMeta, } = useAgentChat();
|
|
1061
1103
|
const attachmentsEnabled = agentChat ? agentChat.disableAttachments !== true : false;
|
|
1062
1104
|
const isDisabled = props.disabled || isThinking || !isAgentReady || isFetchingMessages;
|
|
1063
|
-
const isSubmitDisabled = isDisabled || !hasSendableInput(prompt, attachmentsEnabled ? attachments : []);
|
|
1105
|
+
const isSubmitDisabled = isDisabled || !hasSendableInput(prompt, attachmentsEnabled ? attachments : [], composerMessageMeta);
|
|
1064
1106
|
const handleDragOver = useCallback((e) => {
|
|
1065
1107
|
if (!attachmentsEnabled) {
|
|
1066
1108
|
return;
|
|
@@ -1150,10 +1192,14 @@ export function AgentChatInput({ asChild = false, render, onChange, onKeyDown, o
|
|
|
1150
1192
|
: onDrop, "data-slot": "agent-chat-input", ...props }));
|
|
1151
1193
|
}
|
|
1152
1194
|
export function AgentChatSendTrigger({ asChild = false, render, onClick, disabled, ...props }) {
|
|
1153
|
-
const { attachments, prompt, isThinking, isAgentReady, isFetchingMessages, sendFromInputs,
|
|
1195
|
+
const { attachments, prompt, isThinking, isAgentReady, isFetchingMessages, sendFromInputs, composerMessageMeta,
|
|
1154
1196
|
/* , stopGeneration */
|
|
1155
1197
|
} = useAgentChat();
|
|
1156
|
-
const isDisabled = Boolean(disabled ||
|
|
1198
|
+
const isDisabled = Boolean(disabled ||
|
|
1199
|
+
isThinking ||
|
|
1200
|
+
!isAgentReady ||
|
|
1201
|
+
isFetchingMessages ||
|
|
1202
|
+
!hasSendableInput(prompt, attachments, composerMessageMeta));
|
|
1157
1203
|
return (_jsx(ComposeRender, { render: render, asChild: asChild, defaultTag: "button", onClick: (e) => {
|
|
1158
1204
|
if (isDisabled) {
|
|
1159
1205
|
e.preventDefault();
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { AgentThreadItem } from "./agent-thread-live-update.js";
|
|
3
|
+
import { type AgentConversationChat, type AgentConversationRef, type UseAgentConversationResult } from "./use-agent-conversation.js";
|
|
4
|
+
import { type UseAgentThreadsOptions, type UseAgentThreadsResult } from "./use-agent-threads.js";
|
|
5
|
+
export type AgentThreadFilters = Pick<UseAgentThreadsOptions, "status" | "source">;
|
|
6
|
+
export interface AgentConversationContextValue {
|
|
7
|
+
agentId: string;
|
|
8
|
+
conversation: AgentConversationRef;
|
|
9
|
+
/** The new chat, nothing sent on it yet. */
|
|
10
|
+
isDraft: boolean;
|
|
11
|
+
/** The index under `filters`; its `renameThread` also keeps the open conversation's remembered title current. */
|
|
12
|
+
threads: UseAgentThreadsResult;
|
|
13
|
+
/** The open conversation's row: listed, else the last listed, else a stand-in (`isStandIn`). */
|
|
14
|
+
row: AgentThreadItem;
|
|
15
|
+
isStandIn: boolean;
|
|
16
|
+
filters: AgentThreadFilters;
|
|
17
|
+
setFilters: (filters: AgentThreadFilters) => void;
|
|
18
|
+
hasActiveFilters: boolean;
|
|
19
|
+
/** After this client sends on the conversation (the chat root's onUserMessageSent). */
|
|
20
|
+
notifyMessageSent: UseAgentConversationResult["notifyMessageSent"];
|
|
21
|
+
}
|
|
22
|
+
export interface AgentConversationProviderProps extends Pick<UseAgentThreadsOptions, "token" | "headers" | "baseUrl"> {
|
|
23
|
+
agentId: string;
|
|
24
|
+
conversation: AgentConversationRef;
|
|
25
|
+
isDraft: boolean;
|
|
26
|
+
/** The chat runtime's side of the bridge (react-common's useAgentChat). */
|
|
27
|
+
chat: AgentConversationChat;
|
|
28
|
+
children?: ReactNode;
|
|
29
|
+
}
|
|
30
|
+
export declare function AgentConversationProvider({ agentId, conversation, isDraft, chat, token, headers, baseUrl, children, }: AgentConversationProviderProps): import("react").JSX.Element;
|
|
31
|
+
export declare const useAgentConversationContext: () => AgentConversationContextValue;
|
|
32
|
+
//# sourceMappingURL=agent-conversation-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-conversation-context.d.ts","sourceRoot":"","sources":["../../src/hooks/agent-conversation-context.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAiB,KAAK,SAAS,EAAwB,MAAM,OAAO,CAAC;AAE5E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EAEzB,KAAK,0BAA0B,EAChC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAmB,KAAK,sBAAsB,EAAE,KAAK,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAE/G,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,sBAAsB,EAAE,QAAQ,GAAG,QAAQ,CAAC,CAAC;AAEnF,MAAM,WAAW,6BAA6B;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,oBAAoB,CAAC;IACnC,4CAA4C;IAC5C,OAAO,EAAE,OAAO,CAAC;IACjB,iHAAiH;IACjH,OAAO,EAAE,qBAAqB,CAAC;IAC/B,gGAAgG;IAChG,GAAG,EAAE,eAAe,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,UAAU,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAClD,gBAAgB,EAAE,OAAO,CAAC;IAC1B,uFAAuF;IACvF,iBAAiB,EAAE,0BAA0B,CAAC,mBAAmB,CAAC,CAAC;CACpE;AAID,MAAM,WAAW,8BAA+B,SAAQ,IAAI,CAAC,sBAAsB,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;IACnH,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,oBAAoB,CAAC;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,2EAA2E;IAC3E,IAAI,EAAE,qBAAqB,CAAC;IAC5B,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,wBAAgB,yBAAyB,CAAC,EACxC,OAAO,EACP,YAAY,EACZ,OAAO,EACP,IAAI,EACJ,KAAK,EACL,OAAO,EACP,OAAO,EACP,QAAQ,GACT,EAAE,8BAA8B,+BA4BhC;AAED,eAAO,MAAM,2BAA2B,QAAO,6BAM9C,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// The headless Root of an agent conversation surface: one provider that owns the conversation
|
|
3
|
+
// index (useAgentThreads) under the surface's filters and the open conversation's bridge to the
|
|
4
|
+
// chat (useAgentConversation), for parts to read through useAgentConversationContext. The
|
|
5
|
+
// agent-layout registry item renders it; a custom UI over the same behaviour can too.
|
|
6
|
+
import { createContext, useContext, useState } from "react";
|
|
7
|
+
import { useAgentConversation, } from "./use-agent-conversation.js";
|
|
8
|
+
import { useAgentThreads } from "./use-agent-threads.js";
|
|
9
|
+
const AgentConversationContext = createContext(null);
|
|
10
|
+
export function AgentConversationProvider({ agentId, conversation, isDraft, chat, token, headers, baseUrl, children, }) {
|
|
11
|
+
const [filters, setFilters] = useState({});
|
|
12
|
+
const threads = useAgentThreads({ agentId, status: filters.status, source: filters.source, token, headers, baseUrl });
|
|
13
|
+
const { row, isStandIn, renameThread, notifyMessageSent } = useAgentConversation({
|
|
14
|
+
threads,
|
|
15
|
+
agentId,
|
|
16
|
+
conversation,
|
|
17
|
+
isDraft,
|
|
18
|
+
chat,
|
|
19
|
+
});
|
|
20
|
+
return (_jsx(AgentConversationContext.Provider, { value: {
|
|
21
|
+
agentId,
|
|
22
|
+
conversation,
|
|
23
|
+
isDraft,
|
|
24
|
+
threads: { ...threads, renameThread },
|
|
25
|
+
row,
|
|
26
|
+
isStandIn,
|
|
27
|
+
filters,
|
|
28
|
+
setFilters,
|
|
29
|
+
hasActiveFilters: Boolean(filters.status ?? filters.source),
|
|
30
|
+
notifyMessageSent,
|
|
31
|
+
}, children: children }));
|
|
32
|
+
}
|
|
33
|
+
export const useAgentConversationContext = () => {
|
|
34
|
+
const context = useContext(AgentConversationContext);
|
|
35
|
+
if (!context) {
|
|
36
|
+
throw new Error("useAgentConversationContext must be used within <AgentConversationProvider>.");
|
|
37
|
+
}
|
|
38
|
+
return context;
|
|
39
|
+
};
|