@copilotkit/react-core 1.55.3-canary.1776243725 → 1.55.3-canary.1776979102
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/{copilotkit-opur-20s.d.mts → copilotkit-3mXoM0Hd.d.mts} +9 -29
- package/dist/copilotkit-3mXoM0Hd.d.mts.map +1 -0
- package/dist/{copilotkit-EfopO2gn.d.cts → copilotkit-BDDjvB-p.d.cts} +9 -29
- package/dist/copilotkit-BDDjvB-p.d.cts.map +1 -0
- package/dist/{copilotkit-BoOnQHlE.cjs → copilotkit-BkcqmpWt.cjs} +162 -280
- package/dist/copilotkit-BkcqmpWt.cjs.map +1 -0
- package/dist/{copilotkit-Bm4ox8G0.mjs → copilotkit-C7n8Umv9.mjs} +164 -276
- package/dist/copilotkit-C7n8Umv9.mjs.map +1 -0
- package/dist/index.cjs +4 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +4 -9
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +143 -230
- package/dist/index.umd.js.map +1 -1
- package/dist/v2/index.cjs +1 -2
- package/dist/v2/index.d.cts +2 -2
- package/dist/v2/index.d.mts +2 -2
- package/dist/v2/index.mjs +2 -2
- package/dist/v2/index.umd.js +165 -279
- package/dist/v2/index.umd.js.map +1 -1
- package/package.json +6 -6
- package/src/components/copilot-provider/copilot-messages.tsx +24 -39
- package/src/components/copilot-provider/copilotkit-props.tsx +5 -9
- package/src/components/copilot-provider/copilotkit.tsx +1 -4
- package/src/hooks/__tests__/use-copilot-chat-internal-connect.test.tsx +16 -27
- package/src/hooks/use-copilot-chat_internal.ts +4 -15
- package/src/v2/__tests__/utils/test-helpers.tsx +7 -40
- package/src/v2/components/chat/CopilotChat.tsx +1 -1
- package/src/v2/components/chat/CopilotChatAssistantMessage.tsx +15 -18
- package/src/v2/components/chat/CopilotChatMessageView.tsx +2 -7
- package/src/v2/components/chat/CopilotChatReasoningMessage.tsx +4 -17
- package/src/v2/components/chat/CopilotChatUserMessage.tsx +10 -13
- package/src/v2/components/chat/__tests__/CopilotChat.e2e.test.tsx +5 -131
- package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.tsx +0 -60
- package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.test.tsx +1 -1
- package/src/v2/components/chat/__tests__/CopilotChatToolRendering.e2e.test.tsx +2 -5
- package/src/v2/components/chat/__tests__/CopilotChatToolRerenders.e2e.test.tsx +2 -5
- package/src/v2/components/chat/__tests__/MCPAppsActivityRenderer.e2e.test.tsx +1 -55
- package/src/v2/hooks/__tests__/use-agent-context-timing.e2e.test.tsx +0 -8
- package/src/v2/hooks/__tests__/use-agent-throttle.test.tsx +10 -10
- package/src/v2/hooks/__tests__/use-agent.e2e.test.tsx +2 -13
- package/src/v2/hooks/__tests__/use-frontend-tool.e2e.test.tsx +4 -23
- package/src/v2/hooks/index.ts +0 -1
- package/src/v2/hooks/use-agent.tsx +10 -157
- package/src/v2/hooks/use-render-activity-message.tsx +3 -9
- package/src/v2/hooks/use-render-custom-messages.tsx +1 -6
- package/src/v2/providers/CopilotKitProvider.tsx +2 -6
- package/dist/copilotkit-Bm4ox8G0.mjs.map +0 -1
- package/dist/copilotkit-BoOnQHlE.cjs.map +0 -1
- package/dist/copilotkit-EfopO2gn.d.cts.map +0 -1
- package/dist/copilotkit-opur-20s.d.mts.map +0 -1
- package/src/components/copilot-provider/__tests__/error-visibility-prod.test.tsx +0 -70
- package/src/v2/components/chat/__tests__/CopilotChatCopyButton.clipboard.test.tsx +0 -241
- package/src/v2/hooks/__tests__/use-agent-thread-isolation.test.tsx +0 -327
- package/src/v2/hooks/__tests__/use-capabilities.test.tsx +0 -76
- package/src/v2/hooks/use-capabilities.tsx +0 -25
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { useCopilotKit } from "../providers/CopilotKitProvider";
|
|
2
|
-
import { useCopilotChatConfiguration } from "../providers/CopilotChatConfigurationProvider";
|
|
3
2
|
import { useMemo, useEffect, useReducer, useRef } from "react";
|
|
4
3
|
import { DEFAULT_AGENT_ID } from "@copilotkit/shared";
|
|
5
|
-
import { AbstractAgent
|
|
4
|
+
import { AbstractAgent } from "@ag-ui/client";
|
|
6
5
|
import {
|
|
7
6
|
ProxiedCopilotRuntimeAgent,
|
|
8
7
|
CopilotKitCoreRuntimeConnectionStatus,
|
|
@@ -22,7 +21,6 @@ const ALL_UPDATES: UseAgentUpdate[] = [
|
|
|
22
21
|
|
|
23
22
|
export interface UseAgentProps {
|
|
24
23
|
agentId?: string;
|
|
25
|
-
threadId?: string;
|
|
26
24
|
updates?: UseAgentUpdate[];
|
|
27
25
|
/**
|
|
28
26
|
* Throttle interval (in milliseconds) for React re-renders triggered by
|
|
@@ -46,96 +44,15 @@ export interface UseAgentProps {
|
|
|
46
44
|
throttleMs?: number;
|
|
47
45
|
}
|
|
48
46
|
|
|
49
|
-
|
|
50
|
-
* Clone a registry agent for per-thread isolation.
|
|
51
|
-
* Copies agent configuration (transport, headers, etc.) but resets conversation
|
|
52
|
-
* state (messages, threadId, state) so each thread starts fresh.
|
|
53
|
-
*/
|
|
54
|
-
function cloneForThread(
|
|
55
|
-
source: AbstractAgent,
|
|
56
|
-
threadId: string,
|
|
57
|
-
headers: Record<string, string>,
|
|
58
|
-
): AbstractAgent {
|
|
59
|
-
const clone = source.clone();
|
|
60
|
-
if (clone === source) {
|
|
61
|
-
throw new Error(
|
|
62
|
-
`useAgent: ${source.constructor.name}.clone() returned the same instance. ` +
|
|
63
|
-
`clone() must return a new, independent object.`,
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
clone.threadId = threadId;
|
|
67
|
-
clone.setMessages([]);
|
|
68
|
-
clone.setState({});
|
|
69
|
-
if (clone instanceof HttpAgent) {
|
|
70
|
-
clone.headers = { ...headers };
|
|
71
|
-
}
|
|
72
|
-
return clone;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Module-level WeakMap: registryAgent → (threadId → clone).
|
|
77
|
-
* Shared across all useAgent() calls so that every component using the same
|
|
78
|
-
* (agentId, threadId) pair receives the same agent instance. Using WeakMap
|
|
79
|
-
* ensures the clone map is garbage-collected when the registry agent is
|
|
80
|
-
* replaced (e.g. after reconnect or hot-reload).
|
|
81
|
-
*/
|
|
82
|
-
export const globalThreadCloneMap = new WeakMap<
|
|
83
|
-
AbstractAgent,
|
|
84
|
-
Map<string, AbstractAgent>
|
|
85
|
-
>();
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Look up an existing per-thread clone without creating one.
|
|
89
|
-
* Returns undefined when no clone has been created yet for this pair.
|
|
90
|
-
*/
|
|
91
|
-
export function getThreadClone(
|
|
92
|
-
registryAgent: AbstractAgent | undefined | null,
|
|
93
|
-
threadId: string | undefined | null,
|
|
94
|
-
): AbstractAgent | undefined {
|
|
95
|
-
if (!registryAgent || !threadId) return undefined;
|
|
96
|
-
return globalThreadCloneMap.get(registryAgent)?.get(threadId);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function getOrCreateThreadClone(
|
|
100
|
-
existing: AbstractAgent,
|
|
101
|
-
threadId: string,
|
|
102
|
-
headers: Record<string, string>,
|
|
103
|
-
): AbstractAgent {
|
|
104
|
-
let byThread = globalThreadCloneMap.get(existing);
|
|
105
|
-
if (!byThread) {
|
|
106
|
-
byThread = new Map();
|
|
107
|
-
globalThreadCloneMap.set(existing, byThread);
|
|
108
|
-
}
|
|
109
|
-
const cached = byThread.get(threadId);
|
|
110
|
-
if (cached) return cached;
|
|
111
|
-
|
|
112
|
-
const clone = cloneForThread(existing, threadId, headers);
|
|
113
|
-
byThread.set(threadId, clone);
|
|
114
|
-
return clone;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export function useAgent({
|
|
118
|
-
agentId,
|
|
119
|
-
threadId,
|
|
120
|
-
updates,
|
|
121
|
-
throttleMs,
|
|
122
|
-
}: UseAgentProps = {}) {
|
|
47
|
+
export function useAgent({ agentId, updates, throttleMs }: UseAgentProps = {}) {
|
|
123
48
|
agentId ??= DEFAULT_AGENT_ID;
|
|
124
49
|
|
|
125
50
|
const { copilotkit } = useCopilotKit();
|
|
126
51
|
const providerThrottleMs = copilotkit.defaultThrottleMs;
|
|
127
|
-
// Fall back to the enclosing CopilotChatConfigurationProvider's threadId so
|
|
128
|
-
// that useAgent() called without explicit threadId (e.g. inside a custom
|
|
129
|
-
// message renderer) automatically uses the same per-thread clone as the
|
|
130
|
-
// CopilotChat component it lives within.
|
|
131
|
-
const chatConfig = useCopilotChatConfiguration();
|
|
132
|
-
threadId ??= chatConfig?.threadId;
|
|
133
52
|
|
|
134
53
|
const effectiveThrottleMs = useMemo(() => {
|
|
135
54
|
const resolved = throttleMs ?? providerThrottleMs ?? 0;
|
|
136
55
|
if (!Number.isFinite(resolved) || resolved < 0) {
|
|
137
|
-
// When both throttleMs and providerThrottleMs are undefined, resolved
|
|
138
|
-
// is 0 which passes validation — so one of them must be defined here.
|
|
139
56
|
const source =
|
|
140
57
|
throttleMs !== undefined
|
|
141
58
|
? "hook-level throttleMs"
|
|
@@ -147,7 +64,6 @@ export function useAgent({
|
|
|
147
64
|
}
|
|
148
65
|
return resolved;
|
|
149
66
|
}, [throttleMs, providerThrottleMs]);
|
|
150
|
-
|
|
151
67
|
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
|
152
68
|
|
|
153
69
|
const updateFlags = useMemo(
|
|
@@ -163,29 +79,11 @@ export function useAgent({
|
|
|
163
79
|
);
|
|
164
80
|
|
|
165
81
|
const agent: AbstractAgent = useMemo(() => {
|
|
166
|
-
// Use a composite key when threadId is provided so that different threads
|
|
167
|
-
// for the same agent get independent instances.
|
|
168
|
-
const cacheKey = threadId ? `${agentId}:${threadId}` : agentId;
|
|
169
|
-
|
|
170
82
|
const existing = copilotkit.getAgent(agentId);
|
|
171
83
|
if (existing) {
|
|
172
|
-
// Real agent found — clear any cached
|
|
173
|
-
// bare agentId key (handles the case where a provisional was created
|
|
174
|
-
// before threadId was available, then the component re-renders with one).
|
|
175
|
-
provisionalAgentCache.current.delete(cacheKey);
|
|
84
|
+
// Real agent found — clear any cached provisional for this ID
|
|
176
85
|
provisionalAgentCache.current.delete(agentId);
|
|
177
|
-
|
|
178
|
-
if (!threadId) {
|
|
179
|
-
// No threadId — return the shared registry agent (original behavior)
|
|
180
|
-
return existing;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// threadId provided — return the shared per-thread clone.
|
|
184
|
-
// The global WeakMap ensures all components using the same
|
|
185
|
-
// (registryAgent, threadId) pair receive the same instance, so state
|
|
186
|
-
// mutations (addMessage, setState) are visible everywhere. The WeakMap
|
|
187
|
-
// entry is GC-collected automatically when the registry agent is replaced.
|
|
188
|
-
return getOrCreateThreadClone(existing, threadId, copilotkit.headers);
|
|
86
|
+
return existing;
|
|
189
87
|
}
|
|
190
88
|
|
|
191
89
|
const isRuntimeConfigured = copilotkit.runtimeUrl !== undefined;
|
|
@@ -198,7 +96,7 @@ export function useAgent({
|
|
|
198
96
|
status === CopilotKitCoreRuntimeConnectionStatus.Connecting)
|
|
199
97
|
) {
|
|
200
98
|
// Return cached provisional if available (keeps reference stable)
|
|
201
|
-
const cached = provisionalAgentCache.current.get(
|
|
99
|
+
const cached = provisionalAgentCache.current.get(agentId);
|
|
202
100
|
if (cached) {
|
|
203
101
|
// Update headers on the cached agent in case they changed
|
|
204
102
|
cached.headers = { ...copilotkit.headers };
|
|
@@ -213,10 +111,7 @@ export function useAgent({
|
|
|
213
111
|
});
|
|
214
112
|
// Apply current headers so runs/connects inherit them
|
|
215
113
|
provisional.headers = { ...copilotkit.headers };
|
|
216
|
-
|
|
217
|
-
provisional.threadId = threadId;
|
|
218
|
-
}
|
|
219
|
-
provisionalAgentCache.current.set(cacheKey, provisional);
|
|
114
|
+
provisionalAgentCache.current.set(agentId, provisional);
|
|
220
115
|
return provisional;
|
|
221
116
|
}
|
|
222
117
|
|
|
@@ -229,14 +124,6 @@ export function useAgent({
|
|
|
229
124
|
isRuntimeConfigured &&
|
|
230
125
|
status === CopilotKitCoreRuntimeConnectionStatus.Error
|
|
231
126
|
) {
|
|
232
|
-
// Cache the provisional so that dep changes while in Error state (e.g.
|
|
233
|
-
// headers update) return the same agent reference, matching the
|
|
234
|
-
// Disconnected/Connecting path and preventing spurious re-subscriptions.
|
|
235
|
-
const cached = provisionalAgentCache.current.get(cacheKey);
|
|
236
|
-
if (cached) {
|
|
237
|
-
cached.headers = { ...copilotkit.headers };
|
|
238
|
-
return cached;
|
|
239
|
-
}
|
|
240
127
|
const provisional = new ProxiedCopilotRuntimeAgent({
|
|
241
128
|
runtimeUrl: copilotkit.runtimeUrl,
|
|
242
129
|
agentId,
|
|
@@ -244,10 +131,6 @@ export function useAgent({
|
|
|
244
131
|
runtimeMode: "pending",
|
|
245
132
|
});
|
|
246
133
|
provisional.headers = { ...copilotkit.headers };
|
|
247
|
-
if (threadId) {
|
|
248
|
-
provisional.threadId = threadId;
|
|
249
|
-
}
|
|
250
|
-
provisionalAgentCache.current.set(cacheKey, provisional);
|
|
251
134
|
return provisional;
|
|
252
135
|
}
|
|
253
136
|
|
|
@@ -266,7 +149,6 @@ export function useAgent({
|
|
|
266
149
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
267
150
|
}, [
|
|
268
151
|
agentId,
|
|
269
|
-
threadId,
|
|
270
152
|
copilotkit.agents,
|
|
271
153
|
copilotkit.runtimeConnectionStatus,
|
|
272
154
|
copilotkit.runtimeUrl,
|
|
@@ -281,25 +163,6 @@ export function useAgent({
|
|
|
281
163
|
let timerId: ReturnType<typeof setTimeout> | null = null;
|
|
282
164
|
let active = true;
|
|
283
165
|
|
|
284
|
-
// Microtask-batched forceUpdate: coalesces multiple synchronous
|
|
285
|
-
// notifications (e.g. OnStateChanged + OnRunStatusChanged firing in the
|
|
286
|
-
// same tick) into a single React re-render. This prevents the scroll
|
|
287
|
-
// jumping described in #3499 where rapid unbatched forceUpdate calls
|
|
288
|
-
// cause brief content height fluctuations during streaming.
|
|
289
|
-
let batchScheduled = false;
|
|
290
|
-
const batchedForceUpdate = () => {
|
|
291
|
-
if (!active) return;
|
|
292
|
-
if (!batchScheduled) {
|
|
293
|
-
batchScheduled = true;
|
|
294
|
-
queueMicrotask(() => {
|
|
295
|
-
batchScheduled = false;
|
|
296
|
-
if (active) {
|
|
297
|
-
forceUpdate();
|
|
298
|
-
}
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
};
|
|
302
|
-
|
|
303
166
|
if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) {
|
|
304
167
|
const ms = effectiveThrottleMs;
|
|
305
168
|
if (ms > 0) {
|
|
@@ -343,13 +206,13 @@ export function useAgent({
|
|
|
343
206
|
}
|
|
344
207
|
|
|
345
208
|
if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) {
|
|
346
|
-
handlers.onStateChanged =
|
|
209
|
+
handlers.onStateChanged = forceUpdate;
|
|
347
210
|
}
|
|
348
211
|
|
|
349
212
|
if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {
|
|
350
|
-
handlers.onRunInitialized =
|
|
351
|
-
handlers.onRunFinalized =
|
|
352
|
-
handlers.onRunFailed =
|
|
213
|
+
handlers.onRunInitialized = forceUpdate;
|
|
214
|
+
handlers.onRunFinalized = forceUpdate;
|
|
215
|
+
handlers.onRunFailed = forceUpdate;
|
|
353
216
|
}
|
|
354
217
|
|
|
355
218
|
const subscription = agent.subscribe(handlers);
|
|
@@ -363,16 +226,6 @@ export function useAgent({
|
|
|
363
226
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
364
227
|
}, [agent, forceUpdate, effectiveThrottleMs, updateFlags]);
|
|
365
228
|
|
|
366
|
-
// Keep HttpAgent headers fresh without mutating inside useMemo, which is
|
|
367
|
-
// unsafe in concurrent mode (React may invoke useMemo multiple times and
|
|
368
|
-
// discard intermediate results, but mutations always land).
|
|
369
|
-
useEffect(() => {
|
|
370
|
-
if (agent instanceof HttpAgent) {
|
|
371
|
-
agent.headers = { ...copilotkit.headers };
|
|
372
|
-
}
|
|
373
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
374
|
-
}, [agent, JSON.stringify(copilotkit.headers)]);
|
|
375
|
-
|
|
376
229
|
return {
|
|
377
230
|
agent,
|
|
378
231
|
};
|
|
@@ -3,7 +3,7 @@ import { DEFAULT_AGENT_ID } from "@copilotkit/shared";
|
|
|
3
3
|
import { useCopilotKit, useCopilotChatConfiguration } from "../providers";
|
|
4
4
|
import { useCallback, useMemo } from "react";
|
|
5
5
|
import { ReactActivityMessageRenderer } from "../types";
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
|
|
8
8
|
export function useRenderActivityMessage() {
|
|
9
9
|
const { copilotkit } = useCopilotKit();
|
|
@@ -52,13 +52,7 @@ export function useRenderActivityMessage() {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
const Component = renderer.render;
|
|
55
|
-
|
|
56
|
-
// calls runAgent on the same agent instance that CopilotChat renders from.
|
|
57
|
-
// Without this, button clicks accumulate messages on the registry agent
|
|
58
|
-
// while CopilotChat displays from the clone — responses appear to vanish.
|
|
59
|
-
const registryAgent = copilotkit.getAgent(agentId);
|
|
60
|
-
const agent =
|
|
61
|
-
getThreadClone(registryAgent, config?.threadId) ?? registryAgent;
|
|
55
|
+
const agent = copilotkit.getAgent(agentId);
|
|
62
56
|
|
|
63
57
|
return (
|
|
64
58
|
<Component
|
|
@@ -70,7 +64,7 @@ export function useRenderActivityMessage() {
|
|
|
70
64
|
/>
|
|
71
65
|
);
|
|
72
66
|
},
|
|
73
|
-
[agentId,
|
|
67
|
+
[agentId, copilotkit, findRenderer],
|
|
74
68
|
);
|
|
75
69
|
|
|
76
70
|
return useMemo(
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { useCopilotChatConfiguration, useCopilotKit } from "../providers";
|
|
2
|
-
import { getThreadClone } from "./use-agent";
|
|
3
2
|
import { ReactCustomMessageRendererPosition } from "../types/react-custom-message-renderer";
|
|
4
3
|
import { Message } from "@ag-ui/core";
|
|
5
4
|
|
|
@@ -39,11 +38,7 @@ export function useRenderCustomMessages() {
|
|
|
39
38
|
copilotkit.getRunIdForMessage(agentId, threadId, message.id) ??
|
|
40
39
|
copilotkit.getRunIdsForThread(agentId, threadId).slice(-1)[0];
|
|
41
40
|
const runId = resolvedRunId ?? `missing-run-id:${message.id}`;
|
|
42
|
-
|
|
43
|
-
// conversation state (messages live on the clone, not the registry agent).
|
|
44
|
-
// Fall back to the registry agent when no clone exists (no threadId).
|
|
45
|
-
const registryAgent = copilotkit.getAgent(agentId);
|
|
46
|
-
const agent = getThreadClone(registryAgent, threadId) ?? registryAgent;
|
|
41
|
+
const agent = copilotkit.getAgent(agentId);
|
|
47
42
|
if (!agent) {
|
|
48
43
|
throw new Error("Agent not found");
|
|
49
44
|
}
|
|
@@ -112,7 +112,7 @@ export const useLicenseContext = (): LicenseContextValue =>
|
|
|
112
112
|
export interface CopilotKitProviderProps {
|
|
113
113
|
children: ReactNode;
|
|
114
114
|
runtimeUrl?: string;
|
|
115
|
-
headers?: Record<string, string
|
|
115
|
+
headers?: Record<string, string>;
|
|
116
116
|
/**
|
|
117
117
|
* Credentials mode for fetch requests (e.g., "include" for HTTP-only cookies in cross-origin requests).
|
|
118
118
|
*/
|
|
@@ -263,7 +263,7 @@ function useStableArrayProp<T>(
|
|
|
263
263
|
export const CopilotKitProvider: React.FC<CopilotKitProviderProps> = ({
|
|
264
264
|
children,
|
|
265
265
|
runtimeUrl,
|
|
266
|
-
headers
|
|
266
|
+
headers = {},
|
|
267
267
|
credentials,
|
|
268
268
|
publicApiKey,
|
|
269
269
|
publicLicenseKey,
|
|
@@ -389,10 +389,6 @@ export const CopilotKitProvider: React.FC<CopilotKitProviderProps> = ({
|
|
|
389
389
|
);
|
|
390
390
|
const hasLocalAgents = mergedAgents && Object.keys(mergedAgents).length > 0;
|
|
391
391
|
|
|
392
|
-
// Resolve headers from function or static object
|
|
393
|
-
const headers =
|
|
394
|
-
typeof headersProp === "function" ? headersProp() : headersProp;
|
|
395
|
-
|
|
396
392
|
// Merge a provided publicApiKey into headers (without overwriting an explicit header).
|
|
397
393
|
const mergedHeaders = useMemo(() => {
|
|
398
394
|
if (!resolvedPublicKey) return headers;
|