@blocksdiy/react-common 1.47.0 → 1.48.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 +13 -6
- package/dist/components/new-agent-chat.d.ts.map +1 -1
- package/dist/components/new-agent-chat.js +55 -6
- 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,9 @@ 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 MessageRunIds } from "../utils/message-run-ids.js";
|
|
5
|
+
import { type MessageRunIds, type RunStartedAt } from "../utils/message-run-ids.js";
|
|
6
6
|
export { useTextGrowthAnimating } from "../hooks/text-growth-animation.js";
|
|
7
|
-
export { MESSAGE_RUN_IDS_EVENT_NAME, messageIdsOfRun, type MessageRunIds } from "../utils/message-run-ids.js";
|
|
7
|
+
export { MESSAGE_RUN_IDS_EVENT_NAME, messageIdsOfRun, type MessageRunIds, type RunStartedAt, } from "../utils/message-run-ids.js";
|
|
8
8
|
export { type Message, type AssistantMessage, type UserMessage } from "@ag-ui/client";
|
|
9
9
|
export { useRenderTool, useDefaultRenderTool, useHumanInTheLoop, useFrontendTool, ToolCallStatus, } from "@copilotkit/react-core/v2";
|
|
10
10
|
export interface Attachment {
|
|
@@ -61,12 +61,19 @@ export interface AgentChatContextValue {
|
|
|
61
61
|
}[];
|
|
62
62
|
messageById: Map<string, Message>;
|
|
63
63
|
/**
|
|
64
|
-
* The agent run (turn) that produced each
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
* (previews, stubs) need not state it; absent reads as
|
|
64
|
+
* The agent run (turn) that produced each message — the `agentRunId` the rows it wrote
|
|
65
|
+
* carry. Replayed messages come attributed by the connect replay, live ones by the run
|
|
66
|
+
* that streams them; messages from before run attribution have no entry. Optional so
|
|
67
|
+
* contexts a host builds by hand (previews, stubs) need not state it; absent reads as
|
|
68
|
+
* "no run known".
|
|
68
69
|
*/
|
|
69
70
|
runIdByMessageId?: MessageRunIds;
|
|
71
|
+
/**
|
|
72
|
+
* When each run in `runIdByMessageId` started (epoch ms) — the time of a turn, which is
|
|
73
|
+
* what a chat shows under a message. A live run is stamped as it starts; a replayed
|
|
74
|
+
* one comes with the server's time. Runs from before run times have no entry.
|
|
75
|
+
*/
|
|
76
|
+
runStartedAt?: RunStartedAt;
|
|
70
77
|
toolMessages: ToolMessage[];
|
|
71
78
|
renderToolCall: ReturnType<typeof useRenderToolCall>;
|
|
72
79
|
sendMessage: (message: Omit<UserMessage, "id" | "role">) => Promise<void>;
|
|
@@ -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,9 @@ 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 { EMPTY_MESSAGE_RUN_IDS, findMessageGroupElement,
|
|
9
|
+
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
10
|
export { useTextGrowthAnimating } from "../hooks/text-growth-animation.js";
|
|
11
|
-
export { MESSAGE_RUN_IDS_EVENT_NAME, messageIdsOfRun } from "../utils/message-run-ids.js";
|
|
11
|
+
export { MESSAGE_RUN_IDS_EVENT_NAME, messageIdsOfRun, } from "../utils/message-run-ids.js";
|
|
12
12
|
export { useRenderTool, useDefaultRenderTool, useHumanInTheLoop, useFrontendTool, ToolCallStatus, } from "@copilotkit/react-core/v2";
|
|
13
13
|
// Client-only `useLayoutEffect`, falls back to `useEffect` during SSR.
|
|
14
14
|
// Needed so the `agent.threadId` mirror commits before CopilotKit's
|
|
@@ -311,22 +311,69 @@ const ChatInitializer = ({ agentBlock, agentChatBlock, chatId, token, appId, com
|
|
|
311
311
|
});
|
|
312
312
|
return groups;
|
|
313
313
|
}, [copilotMessages]);
|
|
314
|
-
// Which run produced each
|
|
315
|
-
//
|
|
314
|
+
// Which run produced each message, and when it started (see utils/message-run-ids).
|
|
315
|
+
// Replayed messages: the connect replay sends both as one CUSTOM event, and its word is
|
|
316
|
+
// final — it overwrites what the session recorded. Live messages: RUN_STARTED names the
|
|
317
|
+
// run (the server mints the id, so the one in the event, not the one we sent), times it,
|
|
318
|
+
// and shows the transcript as it stood — the run's input is what sits after the last
|
|
319
|
+
// reply. All of that is recorded with the FIRST message the run streams, and each
|
|
320
|
+
// message it streams is its; first claim wins, as on the server. A run that streams
|
|
321
|
+
// nothing leaves no trace: connect (a reconnect sees the whole transcript, and must not
|
|
322
|
+
// adopt an old unanswered message), or a run that fails before its first token. Cleared
|
|
323
|
+
// with the transcript on a swap.
|
|
316
324
|
const [runIdByMessageId, setRunIdByMessageId] = useState(EMPTY_MESSAGE_RUN_IDS);
|
|
325
|
+
const [runStartedAt, setRunStartedAt] = useState(EMPTY_RUN_STARTED_AT);
|
|
326
|
+
const liveRunRef = useRef(null);
|
|
317
327
|
useEffect(() => {
|
|
318
328
|
if (!copilotAgent) {
|
|
319
329
|
return;
|
|
320
330
|
}
|
|
331
|
+
const claimLive = (messageId) => {
|
|
332
|
+
const run = liveRunRef.current;
|
|
333
|
+
if (!run) {
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
const { runId, startedAt, input } = run;
|
|
337
|
+
run.input = null;
|
|
338
|
+
if (input) {
|
|
339
|
+
setRunStartedAt((previous) => mergeEntries(previous, { [runId]: startedAt }));
|
|
340
|
+
}
|
|
341
|
+
setRunIdByMessageId((previous) => {
|
|
342
|
+
const claims = input ? claimRunInput(input, previous, runId) : {};
|
|
343
|
+
if (!previous.has(messageId)) {
|
|
344
|
+
claims[messageId] = runId;
|
|
345
|
+
}
|
|
346
|
+
return mergeEntries(previous, claims);
|
|
347
|
+
});
|
|
348
|
+
};
|
|
321
349
|
const { unsubscribe } = copilotAgent.subscribe({
|
|
350
|
+
onRunStartedEvent: ({ event, messages }) => {
|
|
351
|
+
liveRunRef.current = { runId: event.runId, startedAt: event.timestamp ?? Date.now(), input: messages };
|
|
352
|
+
},
|
|
353
|
+
onTextMessageStartEvent: ({ event }) => claimLive(event.messageId),
|
|
354
|
+
// A tool-call-only reply is created by its first tool call, under `parentMessageId`
|
|
355
|
+
// when the server names one and the tool call's own id otherwise (the client's rule).
|
|
356
|
+
onToolCallStartEvent: ({ event }) => claimLive(event.parentMessageId ?? event.toolCallId),
|
|
357
|
+
onRunFinalized: () => {
|
|
358
|
+
liveRunRef.current = null;
|
|
359
|
+
},
|
|
322
360
|
onCustomEvent: ({ event }) => {
|
|
323
361
|
const runIds = readMessageRunIdsEvent(event);
|
|
324
362
|
if (runIds) {
|
|
325
|
-
setRunIdByMessageId((previous) =>
|
|
363
|
+
setRunIdByMessageId((previous) => mergeEntries(previous, runIds));
|
|
364
|
+
}
|
|
365
|
+
const startedAt = readRunStartedAtEvent(event);
|
|
366
|
+
if (startedAt) {
|
|
367
|
+
setRunStartedAt((previous) => mergeEntries(previous, startedAt));
|
|
326
368
|
}
|
|
327
369
|
},
|
|
328
370
|
});
|
|
329
|
-
return
|
|
371
|
+
return () => {
|
|
372
|
+
unsubscribe();
|
|
373
|
+
// A run in flight on the agent we leave finalizes without us; it must not claim
|
|
374
|
+
// the next agent's messages.
|
|
375
|
+
liveRunRef.current = null;
|
|
376
|
+
};
|
|
330
377
|
}, [copilotAgent]);
|
|
331
378
|
const interruptAnswersRef = useRef(new Map());
|
|
332
379
|
// Mirror `currentThreadId` onto the agent instance — the `<CopilotKit>`
|
|
@@ -360,6 +407,7 @@ const ChatInitializer = ({ agentBlock, agentChatBlock, chatId, token, appId, com
|
|
|
360
407
|
prevConversationKeyRef.current = conversationKey;
|
|
361
408
|
copilotAgent?.setMessages?.([]);
|
|
362
409
|
setRunIdByMessageId(EMPTY_MESSAGE_RUN_IDS);
|
|
410
|
+
setRunStartedAt(EMPTY_RUN_STARTED_AT);
|
|
363
411
|
setPrompt("");
|
|
364
412
|
setAttachments([]);
|
|
365
413
|
// The clear above runs in the layout phase, but the previous conversation's run is
|
|
@@ -776,6 +824,7 @@ const ChatInitializer = ({ agentBlock, agentChatBlock, chatId, token, appId, com
|
|
|
776
824
|
renderToolCall,
|
|
777
825
|
messageById,
|
|
778
826
|
runIdByMessageId,
|
|
827
|
+
runStartedAt,
|
|
779
828
|
toolMessages,
|
|
780
829
|
prompt,
|
|
781
830
|
attachments,
|
|
@@ -1,20 +1,40 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Which agent run (turn) produced each message of a conversation
|
|
2
|
+
* Which agent run (turn) produced each message of a conversation, and when that run
|
|
3
|
+
* started.
|
|
3
4
|
*
|
|
4
5
|
* A row an app agent writes records the run that wrote it (`agentRunId`). On
|
|
5
6
|
* `agent/connect` the server replays the transcript and then sends one AG-UI CUSTOM
|
|
6
7
|
* event, `blocks.message_run_ids`, carrying `{ runIds: { [messageId]: runId } }` for
|
|
7
|
-
* the replayed messages it can attribute (older messages have none)
|
|
8
|
+
* the replayed messages it can attribute (older messages have none), plus
|
|
9
|
+
* `runStartedAt: { [runId]: epochMs }` for the runs it has a time for. The run id
|
|
8
10
|
* rides in an event rather than on the messages because the AG-UI client validates
|
|
9
11
|
* snapshot messages against a strict schema that drops unknown fields.
|
|
12
|
+
*
|
|
13
|
+
* A LIVE run is attributed here, from its own events: RUN_STARTED names the run and
|
|
14
|
+
* is its time, the messages it adds are its. The server records the same run id and
|
|
15
|
+
* its own clock, so a reload agrees with what the session showed.
|
|
10
16
|
*/
|
|
11
17
|
export declare const MESSAGE_RUN_IDS_EVENT_NAME = "blocks.message_run_ids";
|
|
12
18
|
export type MessageRunIds = ReadonlyMap<string, string>;
|
|
19
|
+
/** Run id → when the run started, in epoch ms. */
|
|
20
|
+
export type RunStartedAt = ReadonlyMap<string, number>;
|
|
13
21
|
export declare const EMPTY_MESSAGE_RUN_IDS: MessageRunIds;
|
|
22
|
+
export declare const EMPTY_RUN_STARTED_AT: RunStartedAt;
|
|
14
23
|
/** The `{ messageId: runId }` payload of a run-ids CUSTOM event, or null for any other event. */
|
|
15
24
|
export declare const readMessageRunIdsEvent: (event: unknown) => Record<string, string> | null;
|
|
25
|
+
/** The `{ runId: epochMs }` payload of a run-ids CUSTOM event, or null when it carries none. */
|
|
26
|
+
export declare const readRunStartedAtEvent: (event: unknown) => Record<string, number> | null;
|
|
16
27
|
/** `previous` plus `incoming`; returns `previous` itself when nothing changes (no re-render). */
|
|
17
|
-
export declare const
|
|
28
|
+
export declare const mergeEntries: <V>(previous: ReadonlyMap<string, V>, incoming: Record<string, V>) => ReadonlyMap<string, V>;
|
|
29
|
+
/**
|
|
30
|
+
* The messages a run that just started takes as its input — the unattributed ones after
|
|
31
|
+
* the last assistant message (the user's message, a tool's answer). Unattributed messages
|
|
32
|
+
* before that are older history and stay so. The server's `claim_run_input` rule.
|
|
33
|
+
*/
|
|
34
|
+
export declare const claimRunInput: (messages: readonly {
|
|
35
|
+
id: string;
|
|
36
|
+
role: string;
|
|
37
|
+
}[], known: MessageRunIds, runId: string) => Record<string, string>;
|
|
18
38
|
/** Ids of the messages `runId` produced, in transcript order (empty when the run isn't in it). */
|
|
19
39
|
export declare const messageIdsOfRun: (messages: readonly {
|
|
20
40
|
id: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-run-ids.d.ts","sourceRoot":"","sources":["../../src/utils/message-run-ids.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"message-run-ids.d.ts","sourceRoot":"","sources":["../../src/utils/message-run-ids.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,eAAO,MAAM,0BAA0B,2BAA2B,CAAC;AAEnE,MAAM,MAAM,aAAa,GAAG,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACxD,kDAAkD;AAClD,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEvD,eAAO,MAAM,qBAAqB,EAAE,aAAyB,CAAC;AAC9D,eAAO,MAAM,oBAAoB,EAAE,YAAwB,CAAC;AA0B5D,iGAAiG;AACjG,eAAO,MAAM,sBAAsB,GAAI,OAAO,OAAO,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IACqB,CAAC;AAEvG,gGAAgG;AAChG,eAAO,MAAM,qBAAqB,GAAI,OAAO,OAAO,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IACsC,CAAC;AAEvH,iGAAiG;AACjG,eAAO,MAAM,YAAY,GAAI,CAAC,EAC5B,UAAU,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,EAChC,UAAU,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,KAC1B,WAAW,CAAC,MAAM,EAAE,CAAC,CAUvB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,GACxB,UAAU,SAAS;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,EACjD,OAAO,aAAa,EACpB,OAAO,MAAM,KACZ,MAAM,CAAC,MAAM,EAAE,MAAM,CAYvB,CAAC;AAEF,kGAAkG;AAClG,eAAO,MAAM,eAAe,GAC1B,UAAU,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EAAE,EACnC,QAAQ,aAAa,EACrB,OAAO,MAAM,GAAG,SAAS,KACxB,MAAM,EAKR,CAAC;AAEF,8FAA8F;AAC9F,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AAExD,+EAA+E;AAC/E,eAAO,MAAM,uBAAuB,GAAI,MAAM,UAAU,GAAG,IAAI,EAAE,WAAW,MAAM,KAAG,WAAW,GAAG,IAYlG,CAAC"}
|
|
@@ -1,45 +1,77 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Which agent run (turn) produced each message of a conversation
|
|
2
|
+
* Which agent run (turn) produced each message of a conversation, and when that run
|
|
3
|
+
* started.
|
|
3
4
|
*
|
|
4
5
|
* A row an app agent writes records the run that wrote it (`agentRunId`). On
|
|
5
6
|
* `agent/connect` the server replays the transcript and then sends one AG-UI CUSTOM
|
|
6
7
|
* event, `blocks.message_run_ids`, carrying `{ runIds: { [messageId]: runId } }` for
|
|
7
|
-
* the replayed messages it can attribute (older messages have none)
|
|
8
|
+
* the replayed messages it can attribute (older messages have none), plus
|
|
9
|
+
* `runStartedAt: { [runId]: epochMs }` for the runs it has a time for. The run id
|
|
8
10
|
* rides in an event rather than on the messages because the AG-UI client validates
|
|
9
11
|
* snapshot messages against a strict schema that drops unknown fields.
|
|
12
|
+
*
|
|
13
|
+
* A LIVE run is attributed here, from its own events: RUN_STARTED names the run and
|
|
14
|
+
* is its time, the messages it adds are its. The server records the same run id and
|
|
15
|
+
* its own clock, so a reload agrees with what the session showed.
|
|
10
16
|
*/
|
|
11
17
|
export const MESSAGE_RUN_IDS_EVENT_NAME = "blocks.message_run_ids";
|
|
12
18
|
export const EMPTY_MESSAGE_RUN_IDS = new Map();
|
|
19
|
+
export const EMPTY_RUN_STARTED_AT = new Map();
|
|
13
20
|
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
14
|
-
/**
|
|
15
|
-
|
|
21
|
+
/**
|
|
22
|
+
* One map of the run-ids CUSTOM event, keeping the entries whose value `isValue`; null for
|
|
23
|
+
* any other event, or when the event lacks that map (a server, or a thread, from before it).
|
|
24
|
+
*/
|
|
25
|
+
const readEventMap = (event, key, isValue) => {
|
|
16
26
|
if (!isRecord(event) || event.name !== MESSAGE_RUN_IDS_EVENT_NAME || !isRecord(event.value)) {
|
|
17
27
|
return null;
|
|
18
28
|
}
|
|
19
|
-
const
|
|
20
|
-
if (!isRecord(
|
|
29
|
+
const entries = event.value[key];
|
|
30
|
+
if (!isRecord(entries)) {
|
|
21
31
|
return null;
|
|
22
32
|
}
|
|
23
33
|
const out = {};
|
|
24
|
-
for (const [
|
|
25
|
-
if (
|
|
26
|
-
out[
|
|
34
|
+
for (const [entryKey, value] of Object.entries(entries)) {
|
|
35
|
+
if (entryKey && isValue(value)) {
|
|
36
|
+
out[entryKey] = value;
|
|
27
37
|
}
|
|
28
38
|
}
|
|
29
39
|
return out;
|
|
30
40
|
};
|
|
41
|
+
/** The `{ messageId: runId }` payload of a run-ids CUSTOM event, or null for any other event. */
|
|
42
|
+
export const readMessageRunIdsEvent = (event) => readEventMap(event, "runIds", (value) => typeof value === "string" && value !== "");
|
|
43
|
+
/** The `{ runId: epochMs }` payload of a run-ids CUSTOM event, or null when it carries none. */
|
|
44
|
+
export const readRunStartedAtEvent = (event) => readEventMap(event, "runStartedAt", (value) => typeof value === "number" && Number.isFinite(value));
|
|
31
45
|
/** `previous` plus `incoming`; returns `previous` itself when nothing changes (no re-render). */
|
|
32
|
-
export const
|
|
46
|
+
export const mergeEntries = (previous, incoming) => {
|
|
33
47
|
let next = null;
|
|
34
|
-
for (const [
|
|
35
|
-
if (previous.get(
|
|
48
|
+
for (const [key, value] of Object.entries(incoming)) {
|
|
49
|
+
if (previous.get(key) === value) {
|
|
36
50
|
continue;
|
|
37
51
|
}
|
|
38
52
|
next ??= new Map(previous);
|
|
39
|
-
next.set(
|
|
53
|
+
next.set(key, value);
|
|
40
54
|
}
|
|
41
55
|
return next ?? previous;
|
|
42
56
|
};
|
|
57
|
+
/**
|
|
58
|
+
* The messages a run that just started takes as its input — the unattributed ones after
|
|
59
|
+
* the last assistant message (the user's message, a tool's answer). Unattributed messages
|
|
60
|
+
* before that are older history and stay so. The server's `claim_run_input` rule.
|
|
61
|
+
*/
|
|
62
|
+
export const claimRunInput = (messages, known, runId) => {
|
|
63
|
+
const out = {};
|
|
64
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
65
|
+
const message = messages[index];
|
|
66
|
+
if (message.role === "assistant") {
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
if (!known.has(message.id)) {
|
|
70
|
+
out[message.id] = runId;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return out;
|
|
74
|
+
};
|
|
43
75
|
/** Ids of the messages `runId` produced, in transcript order (empty when the run isn't in it). */
|
|
44
76
|
export const messageIdsOfRun = (messages, runIds, runId) => {
|
|
45
77
|
if (!runId) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocksdiy/react-common",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.48.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "React common",
|
|
6
6
|
"keywords": [],
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"penpal": "^8.0.0",
|
|
40
40
|
"react": "^19.2.8",
|
|
41
41
|
"use-stick-to-bottom": "1.1.4",
|
|
42
|
-
"@blocksdiy/blocks-client-api": "1.
|
|
42
|
+
"@blocksdiy/blocks-client-api": "1.5.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@types/react": "^19.2.18",
|