@copilotkit/react-core 1.57.3 → 1.58.0-canary.thread-id-propagation
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/LICENSE +21 -0
- package/dist/{copilotkit-CtXcs1ea.cjs → copilotkit-B4ouY7qC.cjs} +14 -3
- package/dist/copilotkit-B4ouY7qC.cjs.map +1 -0
- package/dist/copilotkit-BK9CVq9A.d.cts.map +1 -1
- package/dist/{copilotkit-CC8DjOiC.mjs → copilotkit-L4mM_JqG.mjs} +14 -3
- package/dist/copilotkit-L4mM_JqG.mjs.map +1 -0
- package/dist/copilotkit-WlmeVijs.d.mts.map +1 -1
- package/dist/index.cjs +3 -77
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +3 -77
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +15 -78
- package/dist/index.umd.js.map +1 -1
- package/dist/v2/headless.cjs +11 -0
- package/dist/v2/headless.cjs.map +1 -1
- package/dist/v2/headless.d.cts.map +1 -1
- package/dist/v2/headless.d.mts.map +1 -1
- package/dist/v2/headless.mjs +11 -0
- package/dist/v2/headless.mjs.map +1 -1
- package/dist/v2/index.cjs +1 -1
- package/dist/v2/index.mjs +1 -1
- package/dist/v2/index.umd.js +13 -2
- package/dist/v2/index.umd.js.map +1 -1
- package/package.json +12 -13
- package/skills/react-core/SKILL.md +108 -0
- package/skills/react-core/references/agent-access.md +288 -0
- package/skills/react-core/references/attachments.md +291 -0
- package/skills/react-core/references/capabilities.md +138 -0
- package/skills/react-core/references/chat-components.md +221 -0
- package/skills/react-core/references/client-side-tools.md +358 -0
- package/skills/react-core/references/custom-message-renderers.md +226 -0
- package/skills/react-core/references/debug-mode.md +153 -0
- package/skills/react-core/references/human-in-the-loop.md +312 -0
- package/skills/react-core/references/provider-setup.md +326 -0
- package/skills/react-core/references/rendering-activity-messages.md +207 -0
- package/skills/react-core/references/rendering-tool-calls.md +319 -0
- package/skills/react-core/references/suggestions.md +211 -0
- package/skills/react-core/references/switching-agents-recipes.md +160 -0
- package/skills/react-core/references/switching-agents.md +231 -0
- package/skills/react-core/references/threads.md +226 -0
- package/.attw.json +0 -3
- package/CHANGELOG.md +0 -5043
- package/dist/copilotkit-CC8DjOiC.mjs.map +0 -1
- package/dist/copilotkit-CtXcs1ea.cjs.map +0 -1
- package/scripts/scope-preflight.mjs +0 -100
- package/src/components/CopilotListeners.tsx +0 -137
- package/src/components/__tests__/CopilotListeners.test.tsx +0 -38
- package/src/components/copilot-provider/__tests__/copilot-messages-key.test.tsx +0 -92
- package/src/components/copilot-provider/__tests__/copilotkit-error.test.tsx +0 -77
- package/src/components/copilot-provider/__tests__/error-visibility-prod.test.tsx +0 -70
- package/src/components/copilot-provider/__tests__/v1-explicit-threadid-bridge.test.tsx +0 -107
- package/src/components/copilot-provider/copilot-messages.tsx +0 -314
- package/src/components/copilot-provider/copilotkit-props.tsx +0 -214
- package/src/components/copilot-provider/copilotkit.tsx +0 -853
- package/src/components/copilot-provider/index.ts +0 -3
- package/src/components/dev-console/console-trigger.tsx +0 -283
- package/src/components/dev-console/developer-console-modal.tsx +0 -1016
- package/src/components/dev-console/icons.tsx +0 -106
- package/src/components/error-boundary/error-boundary.tsx +0 -99
- package/src/components/error-boundary/error-utils.tsx +0 -105
- package/src/components/index.ts +0 -1
- package/src/components/toast/exclamation-mark-icon.tsx +0 -27
- package/src/components/toast/toast-provider.tsx +0 -448
- package/src/components/usage-banner.tsx +0 -266
- package/src/context/__tests__/threads-context.test.tsx +0 -141
- package/src/context/coagent-state-renders-context.tsx +0 -89
- package/src/context/copilot-context.tsx +0 -365
- package/src/context/copilot-messages-context.tsx +0 -35
- package/src/context/index.ts +0 -22
- package/src/context/threads-context.tsx +0 -69
- package/src/hooks/__tests__/use-coagent-config.test.ts +0 -352
- package/src/hooks/__tests__/use-coagent-state-render-bridge.helpers.test.ts +0 -107
- package/src/hooks/__tests__/use-coagent-state-render.e2e.test.tsx +0 -1209
- package/src/hooks/__tests__/use-coagent-state-render.test.tsx +0 -356
- package/src/hooks/__tests__/use-copilot-chat-internal-connect.test.tsx +0 -241
- package/src/hooks/__tests__/use-frontend-tool-available.test.tsx +0 -72
- package/src/hooks/__tests__/use-frontend-tool-remount.e2e.test.tsx +0 -102
- package/src/hooks/index.ts +0 -33
- package/src/hooks/use-agent-nodename.ts +0 -33
- package/src/hooks/use-coagent-state-render-bridge.helpers.ts +0 -345
- package/src/hooks/use-coagent-state-render-bridge.tsx +0 -222
- package/src/hooks/use-coagent-state-render-registry.ts +0 -230
- package/src/hooks/use-coagent-state-render.ts +0 -163
- package/src/hooks/use-coagent.ts +0 -377
- package/src/hooks/use-configure-chat-suggestions.tsx +0 -96
- package/src/hooks/use-copilot-action.ts +0 -245
- package/src/hooks/use-copilot-additional-instructions.ts +0 -98
- package/src/hooks/use-copilot-authenticated-action.ts +0 -73
- package/src/hooks/use-copilot-chat-headless_c.ts +0 -264
- package/src/hooks/use-copilot-chat-suggestions.tsx +0 -134
- package/src/hooks/use-copilot-chat.ts +0 -132
- package/src/hooks/use-copilot-chat_internal.ts +0 -875
- package/src/hooks/use-copilot-readable.ts +0 -135
- package/src/hooks/use-copilot-runtime-client.ts +0 -178
- package/src/hooks/use-default-tool.ts +0 -13
- package/src/hooks/use-flat-category-store.ts +0 -109
- package/src/hooks/use-frontend-tool.ts +0 -113
- package/src/hooks/use-human-in-the-loop.ts +0 -138
- package/src/hooks/use-langgraph-interrupt.ts +0 -103
- package/src/hooks/use-lazy-tool-renderer.tsx +0 -30
- package/src/hooks/use-make-copilot-document-readable.ts +0 -30
- package/src/hooks/use-render-tool-call.ts +0 -89
- package/src/hooks/use-tree.ts +0 -222
- package/src/index.tsx +0 -7
- package/src/lib/copilot-task.ts +0 -215
- package/src/lib/index.ts +0 -1
- package/src/lib/status-checker.ts +0 -67
- package/src/setupTests.ts +0 -37
- package/src/test-helpers/copilot-context.ts +0 -91
- package/src/types/chat-suggestion-configuration.ts +0 -23
- package/src/types/coagent-action.ts +0 -35
- package/src/types/coagent-state.ts +0 -13
- package/src/types/crew.ts +0 -89
- package/src/types/document-pointer.ts +0 -7
- package/src/types/frontend-action.ts +0 -213
- package/src/types/index.ts +0 -17
- package/src/types/interrupt-action.ts +0 -58
- package/src/types/system-message.ts +0 -4
- package/src/utils/dev-console.ts +0 -19
- package/src/utils/index.ts +0 -2
- package/src/utils/suggestions-constants.ts +0 -8
- package/src/utils/utils.test.ts +0 -7
- package/src/utils/utils.ts +0 -6
- package/src/v2/__tests__/A2UIMessageRenderer.test.tsx +0 -240
- package/src/v2/__tests__/globalSetup.ts +0 -14
- package/src/v2/__tests__/setup.ts +0 -93
- package/src/v2/__tests__/utils/test-helpers.tsx +0 -570
- package/src/v2/a2ui/A2UICatalogContext.tsx +0 -79
- package/src/v2/a2ui/A2UIMessageRenderer.tsx +0 -294
- package/src/v2/a2ui/A2UIToolCallRenderer.tsx +0 -290
- package/src/v2/components/CopilotKitInspector.tsx +0 -52
- package/src/v2/components/MCPAppsActivityRenderer.tsx +0 -815
- package/src/v2/components/OpenGenerativeUIRenderer.tsx +0 -598
- package/src/v2/components/WildcardToolCallRender.tsx +0 -86
- package/src/v2/components/__tests__/OpenGenerativeUIRenderer.test.tsx +0 -665
- package/src/v2/components/chat/CopilotChat.tsx +0 -664
- package/src/v2/components/chat/CopilotChatAssistantMessage.tsx +0 -393
- package/src/v2/components/chat/CopilotChatAttachmentQueue.tsx +0 -374
- package/src/v2/components/chat/CopilotChatAttachmentRenderer.tsx +0 -159
- package/src/v2/components/chat/CopilotChatAudioRecorder.tsx +0 -350
- package/src/v2/components/chat/CopilotChatInput.tsx +0 -1412
- package/src/v2/components/chat/CopilotChatMessageView.tsx +0 -716
- package/src/v2/components/chat/CopilotChatReasoningMessage.tsx +0 -265
- package/src/v2/components/chat/CopilotChatSuggestionPill.tsx +0 -59
- package/src/v2/components/chat/CopilotChatSuggestionView.tsx +0 -134
- package/src/v2/components/chat/CopilotChatToggleButton.tsx +0 -171
- package/src/v2/components/chat/CopilotChatToolCallsView.tsx +0 -40
- package/src/v2/components/chat/CopilotChatUserMessage.tsx +0 -445
- package/src/v2/components/chat/CopilotChatView.tsx +0 -890
- package/src/v2/components/chat/CopilotModalHeader.tsx +0 -129
- package/src/v2/components/chat/CopilotPopup.tsx +0 -81
- package/src/v2/components/chat/CopilotPopupView.tsx +0 -317
- package/src/v2/components/chat/CopilotSidebar.tsx +0 -80
- package/src/v2/components/chat/CopilotSidebarView.tsx +0 -269
- package/src/v2/components/chat/Lightbox.tsx +0 -103
- package/src/v2/components/chat/__tests__/CopilotChat.absentThreadConnect.test.tsx +0 -66
- package/src/v2/components/chat/__tests__/CopilotChat.attachments.test.tsx +0 -168
- package/src/v2/components/chat/__tests__/CopilotChat.e2e.test.tsx +0 -1239
- package/src/v2/components/chat/__tests__/CopilotChat.onError.test.tsx +0 -73
- package/src/v2/components/chat/__tests__/CopilotChat.slots.e2e.test.tsx +0 -432
- package/src/v2/components/chat/__tests__/CopilotChat.suggestionsAlways.test.tsx +0 -183
- package/src/v2/components/chat/__tests__/CopilotChat.welcomeGate.test.tsx +0 -184
- package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.tsx +0 -649
- package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.slots.e2e.test.tsx +0 -624
- package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.test.tsx +0 -702
- package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.thumbs.test.tsx +0 -72
- package/src/v2/components/chat/__tests__/CopilotChatCopyButton.clipboard.test.tsx +0 -241
- package/src/v2/components/chat/__tests__/CopilotChatCssClasses.test.tsx +0 -107
- package/src/v2/components/chat/__tests__/CopilotChatInput.slots.e2e.test.tsx +0 -929
- package/src/v2/components/chat/__tests__/CopilotChatInput.test.tsx +0 -1567
- package/src/v2/components/chat/__tests__/CopilotChatMessageView.slots.e2e.test.tsx +0 -1004
- package/src/v2/components/chat/__tests__/CopilotChatMessageView.test.tsx +0 -279
- package/src/v2/components/chat/__tests__/CopilotChatPerf.e2e.test.tsx +0 -336
- package/src/v2/components/chat/__tests__/CopilotChatPropsRerender.e2e.test.tsx +0 -249
- package/src/v2/components/chat/__tests__/CopilotChatSuggestionView.slots.e2e.test.tsx +0 -530
- package/src/v2/components/chat/__tests__/CopilotChatToolRendering.e2e.test.tsx +0 -785
- package/src/v2/components/chat/__tests__/CopilotChatToolRerenders.e2e.test.tsx +0 -2416
- package/src/v2/components/chat/__tests__/CopilotChatUserMessage.slots.e2e.test.tsx +0 -621
- package/src/v2/components/chat/__tests__/CopilotChatView.connectingGate.test.tsx +0 -56
- package/src/v2/components/chat/__tests__/CopilotChatView.inputOverlay.test.tsx +0 -264
- package/src/v2/components/chat/__tests__/CopilotChatView.onClick.e2e.test.tsx +0 -853
- package/src/v2/components/chat/__tests__/CopilotChatView.pinToSend.test.tsx +0 -94
- package/src/v2/components/chat/__tests__/CopilotChatView.slots.e2e.test.tsx +0 -1050
- package/src/v2/components/chat/__tests__/CopilotModalHeader.slots.e2e.test.tsx +0 -484
- package/src/v2/components/chat/__tests__/CopilotPopupView.slots.e2e.test.tsx +0 -612
- package/src/v2/components/chat/__tests__/CopilotSidebarView.position.test.tsx +0 -159
- package/src/v2/components/chat/__tests__/CopilotSidebarView.slots.e2e.test.tsx +0 -502
- package/src/v2/components/chat/__tests__/MCPAppsActivityRenderer.e2e.test.tsx +0 -1068
- package/src/v2/components/chat/__tests__/MCPAppsProxy.e2e.test.tsx +0 -589
- package/src/v2/components/chat/__tests__/MCPAppsUiMessage.e2e.test.tsx +0 -403
- package/src/v2/components/chat/__tests__/copilot-chat-throttle.test.tsx +0 -137
- package/src/v2/components/chat/__tests__/normalize-auto-scroll.test.ts +0 -37
- package/src/v2/components/chat/__tests__/setup.ts +0 -1
- package/src/v2/components/chat/index.ts +0 -90
- package/src/v2/components/chat/last-user-message-context.ts +0 -21
- package/src/v2/components/chat/normalize-auto-scroll.ts +0 -17
- package/src/v2/components/chat/scroll-element-context.ts +0 -13
- package/src/v2/components/index.ts +0 -8
- package/src/v2/components/intelligence-indicator/IntelligenceIndicator.tsx +0 -286
- package/src/v2/components/intelligence-indicator/__tests__/IntelligenceIndicator.e2e.test.tsx +0 -464
- package/src/v2/components/intelligence-indicator/index.ts +0 -2
- package/src/v2/components/license-warning-banner.tsx +0 -217
- package/src/v2/components/ui/button.tsx +0 -124
- package/src/v2/components/ui/dropdown-menu.tsx +0 -258
- package/src/v2/components/ui/tooltip.tsx +0 -60
- package/src/v2/context.ts +0 -62
- package/src/v2/headless.ts +0 -64
- package/src/v2/hooks/__tests__/standard-schema-types.test.tsx +0 -152
- package/src/v2/hooks/__tests__/standard-schema.test.tsx +0 -282
- package/src/v2/hooks/__tests__/use-agent-context-timing.e2e.test.tsx +0 -140
- package/src/v2/hooks/__tests__/use-agent-context.test.tsx +0 -401
- package/src/v2/hooks/__tests__/use-agent-error-state.test.tsx +0 -44
- package/src/v2/hooks/__tests__/use-agent-stability.test.tsx +0 -211
- package/src/v2/hooks/__tests__/use-agent-throttle.test.tsx +0 -1029
- package/src/v2/hooks/__tests__/use-agent.e2e.test.tsx +0 -159
- package/src/v2/hooks/__tests__/use-attachments.test.tsx +0 -169
- package/src/v2/hooks/__tests__/use-capabilities.test.tsx +0 -76
- package/src/v2/hooks/__tests__/use-component.test.tsx +0 -126
- package/src/v2/hooks/__tests__/use-configure-suggestions.e2e.test.tsx +0 -696
- package/src/v2/hooks/__tests__/use-default-render-tool.test.tsx +0 -153
- package/src/v2/hooks/__tests__/use-frontend-tool-available.test.tsx +0 -167
- package/src/v2/hooks/__tests__/use-frontend-tool.e2e.test.tsx +0 -2148
- package/src/v2/hooks/__tests__/use-human-in-the-loop.e2e.test.tsx +0 -1261
- package/src/v2/hooks/__tests__/use-interrupt.test.tsx +0 -397
- package/src/v2/hooks/__tests__/use-katex-styles.test.tsx +0 -56
- package/src/v2/hooks/__tests__/use-keyboard-height.test.tsx +0 -192
- package/src/v2/hooks/__tests__/use-pin-to-send.test.tsx +0 -219
- package/src/v2/hooks/__tests__/use-render-custom-messages.test.tsx +0 -55
- package/src/v2/hooks/__tests__/use-render-tool.test.tsx +0 -259
- package/src/v2/hooks/__tests__/use-suggestions.e2e.test.tsx +0 -524
- package/src/v2/hooks/__tests__/use-threads.test.tsx +0 -757
- package/src/v2/hooks/__tests__/zod-regression.test.tsx +0 -311
- package/src/v2/hooks/index.ts +0 -24
- package/src/v2/hooks/use-agent-context.tsx +0 -45
- package/src/v2/hooks/use-agent.tsx +0 -227
- package/src/v2/hooks/use-attachments.tsx +0 -269
- package/src/v2/hooks/use-capabilities.tsx +0 -25
- package/src/v2/hooks/use-component.tsx +0 -91
- package/src/v2/hooks/use-configure-suggestions.tsx +0 -236
- package/src/v2/hooks/use-default-render-tool.tsx +0 -271
- package/src/v2/hooks/use-frontend-tool.tsx +0 -46
- package/src/v2/hooks/use-human-in-the-loop.tsx +0 -81
- package/src/v2/hooks/use-interrupt.tsx +0 -305
- package/src/v2/hooks/use-keyboard-height.tsx +0 -67
- package/src/v2/hooks/use-pin-to-send.ts +0 -94
- package/src/v2/hooks/use-render-activity-message.tsx +0 -72
- package/src/v2/hooks/use-render-custom-messages.tsx +0 -93
- package/src/v2/hooks/use-render-tool-call.tsx +0 -208
- package/src/v2/hooks/use-render-tool.tsx +0 -184
- package/src/v2/hooks/use-suggestions.tsx +0 -91
- package/src/v2/hooks/use-threads.tsx +0 -325
- package/src/v2/hooks/useKatexStyles.ts +0 -27
- package/src/v2/index.css +0 -1
- package/src/v2/index.ts +0 -27
- package/src/v2/lib/__tests__/completePartialMarkdown.test.ts +0 -495
- package/src/v2/lib/__tests__/processPartialHtml.test.ts +0 -112
- package/src/v2/lib/__tests__/renderSlot.test.tsx +0 -588
- package/src/v2/lib/__tests__/slots.test.ts +0 -56
- package/src/v2/lib/processPartialHtml.ts +0 -45
- package/src/v2/lib/react-core.ts +0 -156
- package/src/v2/lib/slots.tsx +0 -184
- package/src/v2/lib/transcription-client.ts +0 -184
- package/src/v2/lib/utils.ts +0 -8
- package/src/v2/providers/CopilotChatConfigurationProvider.tsx +0 -196
- package/src/v2/providers/CopilotKitProvider.tsx +0 -800
- package/src/v2/providers/SandboxFunctionsContext.ts +0 -10
- package/src/v2/providers/__tests__/CopilotChatConfigurationProvider.test.tsx +0 -652
- package/src/v2/providers/__tests__/CopilotKitProvider.license.test.tsx +0 -101
- package/src/v2/providers/__tests__/CopilotKitProvider.onError.test.tsx +0 -69
- package/src/v2/providers/__tests__/CopilotKitProvider.renderCustomMessages.e2e.test.tsx +0 -881
- package/src/v2/providers/__tests__/CopilotKitProvider.sandboxFunctions.test.tsx +0 -198
- package/src/v2/providers/__tests__/CopilotKitProvider.stability.test.tsx +0 -740
- package/src/v2/providers/__tests__/CopilotKitProvider.test.tsx +0 -713
- package/src/v2/providers/__tests__/CopilotKitProvider.wildcard.test.tsx +0 -294
- package/src/v2/providers/index.ts +0 -21
- package/src/v2/styles/globals.css +0 -349
- package/src/v2/types/__tests__/defineToolCallRenderer.test.tsx +0 -525
- package/src/v2/types/defineToolCallRenderer.ts +0 -68
- package/src/v2/types/frontend-tool.ts +0 -8
- package/src/v2/types/human-in-the-loop.ts +0 -33
- package/src/v2/types/index.ts +0 -8
- package/src/v2/types/interrupt.ts +0 -15
- package/src/v2/types/react-activity-message-renderer.ts +0 -27
- package/src/v2/types/react-custom-message-renderer.ts +0 -17
- package/src/v2/types/react-tool-call-renderer.ts +0 -35
- package/src/v2/types/sandbox-function.ts +0 -11
- package/tsconfig.json +0 -8
- package/tsdown.config.ts +0 -193
- package/typedoc.json +0 -4
- package/vitest.config.mjs +0 -31
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { createContext, useContext } from "react";
|
|
2
|
-
import type { SandboxFunction } from "../types/sandbox-function";
|
|
3
|
-
|
|
4
|
-
export const SandboxFunctionsContext = createContext<
|
|
5
|
-
readonly SandboxFunction[]
|
|
6
|
-
>([]);
|
|
7
|
-
|
|
8
|
-
export function useSandboxFunctions(): readonly SandboxFunction[] {
|
|
9
|
-
return useContext(SandboxFunctionsContext);
|
|
10
|
-
}
|
|
@@ -1,652 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { render, screen, fireEvent, act } from "@testing-library/react";
|
|
3
|
-
import { describe, it, expect } from "vitest";
|
|
4
|
-
import {
|
|
5
|
-
CopilotChatConfigurationProvider,
|
|
6
|
-
CopilotChatDefaultLabels,
|
|
7
|
-
useCopilotChatConfiguration,
|
|
8
|
-
} from "../CopilotChatConfigurationProvider";
|
|
9
|
-
import { DEFAULT_AGENT_ID } from "@copilotkit/shared";
|
|
10
|
-
import { CopilotKitProvider } from "../CopilotKitProvider";
|
|
11
|
-
import { MockStepwiseAgent } from "../../__tests__/utils/test-helpers";
|
|
12
|
-
import { CopilotChat } from "../../components/chat/CopilotChat";
|
|
13
|
-
|
|
14
|
-
// Test component to access configuration
|
|
15
|
-
function ConfigurationDisplay() {
|
|
16
|
-
const config = useCopilotChatConfiguration();
|
|
17
|
-
return (
|
|
18
|
-
<div>
|
|
19
|
-
<div data-testid="agentId">{config?.agentId || "no-config"}</div>
|
|
20
|
-
<div data-testid="threadId">{config?.threadId || "no-config"}</div>
|
|
21
|
-
<div data-testid="placeholder">
|
|
22
|
-
{config?.labels.chatInputPlaceholder || "no-config"}
|
|
23
|
-
</div>
|
|
24
|
-
<div data-testid="copyLabel">
|
|
25
|
-
{config?.labels.assistantMessageToolbarCopyMessageLabel || "no-config"}
|
|
26
|
-
</div>
|
|
27
|
-
</div>
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
describe("CopilotChatConfigurationProvider", () => {
|
|
32
|
-
describe("Basic functionality", () => {
|
|
33
|
-
it("should provide default configuration", () => {
|
|
34
|
-
render(
|
|
35
|
-
<CopilotChatConfigurationProvider threadId="test-thread">
|
|
36
|
-
<ConfigurationDisplay />
|
|
37
|
-
</CopilotChatConfigurationProvider>,
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
expect(screen.getByTestId("agentId").textContent).toBe(DEFAULT_AGENT_ID);
|
|
41
|
-
expect(screen.getByTestId("threadId").textContent).toBe("test-thread");
|
|
42
|
-
expect(screen.getByTestId("placeholder").textContent).toBe(
|
|
43
|
-
CopilotChatDefaultLabels.chatInputPlaceholder,
|
|
44
|
-
);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it("should accept custom agentId", () => {
|
|
48
|
-
render(
|
|
49
|
-
<CopilotChatConfigurationProvider
|
|
50
|
-
threadId="test-thread"
|
|
51
|
-
agentId="custom-agent"
|
|
52
|
-
>
|
|
53
|
-
<ConfigurationDisplay />
|
|
54
|
-
</CopilotChatConfigurationProvider>,
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
expect(screen.getByTestId("agentId").textContent).toBe("custom-agent");
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it("should merge custom labels with defaults", () => {
|
|
61
|
-
const customLabels = {
|
|
62
|
-
chatInputPlaceholder: "Custom placeholder",
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
render(
|
|
66
|
-
<CopilotChatConfigurationProvider
|
|
67
|
-
threadId="test-thread"
|
|
68
|
-
labels={customLabels}
|
|
69
|
-
>
|
|
70
|
-
<ConfigurationDisplay />
|
|
71
|
-
</CopilotChatConfigurationProvider>,
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
expect(screen.getByTestId("placeholder").textContent).toBe(
|
|
75
|
-
"Custom placeholder",
|
|
76
|
-
);
|
|
77
|
-
// Other labels should still have defaults
|
|
78
|
-
expect(screen.getByTestId("copyLabel").textContent).toBe(
|
|
79
|
-
CopilotChatDefaultLabels.assistantMessageToolbarCopyMessageLabel,
|
|
80
|
-
);
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
describe("Hook behavior", () => {
|
|
85
|
-
it("should return null when no provider exists", () => {
|
|
86
|
-
render(<ConfigurationDisplay />);
|
|
87
|
-
|
|
88
|
-
expect(screen.getByTestId("agentId").textContent).toBe("no-config");
|
|
89
|
-
expect(screen.getByTestId("threadId").textContent).toBe("no-config");
|
|
90
|
-
expect(screen.getByTestId("placeholder").textContent).toBe("no-config");
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
describe("CopilotChat priority merging", () => {
|
|
95
|
-
it("should use defaults when no provider exists and no props passed", () => {
|
|
96
|
-
// CopilotChat creates its own provider, so we need to check inside it
|
|
97
|
-
// We'll check the input placeholder which uses the configuration
|
|
98
|
-
const { container } = render(
|
|
99
|
-
<CopilotKitProvider
|
|
100
|
-
agents__unsafe_dev_only={{
|
|
101
|
-
[DEFAULT_AGENT_ID]: new MockStepwiseAgent(),
|
|
102
|
-
}}
|
|
103
|
-
>
|
|
104
|
-
<CopilotChat />
|
|
105
|
-
</CopilotKitProvider>,
|
|
106
|
-
);
|
|
107
|
-
|
|
108
|
-
// Find the input element and check its placeholder
|
|
109
|
-
const input = container.querySelector('textarea, input[type="text"]');
|
|
110
|
-
expect(input?.getAttribute("placeholder")).toBe(
|
|
111
|
-
CopilotChatDefaultLabels.chatInputPlaceholder,
|
|
112
|
-
);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it("should inherit from existing provider when CopilotChat has no props", () => {
|
|
116
|
-
const { container } = render(
|
|
117
|
-
<CopilotKitProvider
|
|
118
|
-
agents__unsafe_dev_only={{
|
|
119
|
-
"outer-agent": new MockStepwiseAgent({ agentId: "outer-agent" }),
|
|
120
|
-
}}
|
|
121
|
-
>
|
|
122
|
-
<CopilotChatConfigurationProvider
|
|
123
|
-
threadId="outer-thread"
|
|
124
|
-
agentId="outer-agent"
|
|
125
|
-
labels={{ chatInputPlaceholder: "Outer placeholder" }}
|
|
126
|
-
>
|
|
127
|
-
<CopilotChat />
|
|
128
|
-
</CopilotChatConfigurationProvider>
|
|
129
|
-
</CopilotKitProvider>,
|
|
130
|
-
);
|
|
131
|
-
|
|
132
|
-
// Check that the input inherits the outer placeholder
|
|
133
|
-
const input = container.querySelector('textarea, input[type="text"]');
|
|
134
|
-
expect(input?.getAttribute("placeholder")).toBe("Outer placeholder");
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it("should override existing provider with CopilotChat props", () => {
|
|
138
|
-
const { container } = render(
|
|
139
|
-
<CopilotKitProvider
|
|
140
|
-
agents__unsafe_dev_only={{
|
|
141
|
-
"inner-agent": new MockStepwiseAgent({ agentId: "inner-agent" }),
|
|
142
|
-
}}
|
|
143
|
-
>
|
|
144
|
-
<CopilotChatConfigurationProvider
|
|
145
|
-
threadId="outer-thread"
|
|
146
|
-
agentId="outer-agent"
|
|
147
|
-
labels={{ chatInputPlaceholder: "Outer placeholder" }}
|
|
148
|
-
>
|
|
149
|
-
<CopilotChat
|
|
150
|
-
agentId="inner-agent"
|
|
151
|
-
threadId="inner-thread"
|
|
152
|
-
labels={{ chatInputPlaceholder: "Inner placeholder" }}
|
|
153
|
-
/>
|
|
154
|
-
</CopilotChatConfigurationProvider>
|
|
155
|
-
</CopilotKitProvider>,
|
|
156
|
-
);
|
|
157
|
-
|
|
158
|
-
// CopilotChat props should win - check the input placeholder
|
|
159
|
-
const input = container.querySelector('textarea, input[type="text"]');
|
|
160
|
-
expect(input?.getAttribute("placeholder")).toBe("Inner placeholder");
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
it("should merge labels correctly with priority: default < existing < props", () => {
|
|
164
|
-
const { container } = render(
|
|
165
|
-
<CopilotKitProvider
|
|
166
|
-
agents__unsafe_dev_only={{
|
|
167
|
-
[DEFAULT_AGENT_ID]: new MockStepwiseAgent(),
|
|
168
|
-
}}
|
|
169
|
-
>
|
|
170
|
-
<CopilotChatConfigurationProvider
|
|
171
|
-
threadId="outer-thread"
|
|
172
|
-
labels={{
|
|
173
|
-
chatInputPlaceholder: "Outer placeholder",
|
|
174
|
-
assistantMessageToolbarCopyMessageLabel: "Outer copy",
|
|
175
|
-
}}
|
|
176
|
-
>
|
|
177
|
-
<CopilotChat
|
|
178
|
-
labels={{
|
|
179
|
-
chatInputPlaceholder: "Inner placeholder",
|
|
180
|
-
// Not overriding copyLabel, should inherit from outer
|
|
181
|
-
}}
|
|
182
|
-
/>
|
|
183
|
-
</CopilotChatConfigurationProvider>
|
|
184
|
-
</CopilotKitProvider>,
|
|
185
|
-
);
|
|
186
|
-
|
|
187
|
-
const input = container.querySelector('textarea, input[type="text"]');
|
|
188
|
-
expect(input?.getAttribute("placeholder")).toBe("Inner placeholder");
|
|
189
|
-
// The copy label would be tested if we had assistant messages
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
it("should handle partial overrides correctly", () => {
|
|
193
|
-
const { container } = render(
|
|
194
|
-
<CopilotKitProvider
|
|
195
|
-
agents__unsafe_dev_only={{
|
|
196
|
-
"outer-agent": new MockStepwiseAgent({ agentId: "outer-agent" }),
|
|
197
|
-
}}
|
|
198
|
-
>
|
|
199
|
-
<CopilotChatConfigurationProvider
|
|
200
|
-
threadId="outer-thread"
|
|
201
|
-
agentId="outer-agent"
|
|
202
|
-
labels={{ chatInputPlaceholder: "Outer placeholder" }}
|
|
203
|
-
>
|
|
204
|
-
<CopilotChat
|
|
205
|
-
// Only override threadId and some labels, not agentId
|
|
206
|
-
threadId="inner-thread"
|
|
207
|
-
labels={{
|
|
208
|
-
chatInputPlaceholder: "Inner placeholder",
|
|
209
|
-
}}
|
|
210
|
-
/>
|
|
211
|
-
</CopilotChatConfigurationProvider>
|
|
212
|
-
</CopilotKitProvider>,
|
|
213
|
-
);
|
|
214
|
-
|
|
215
|
-
// Check the placeholder was overridden
|
|
216
|
-
const input = container.querySelector('textarea, input[type="text"]');
|
|
217
|
-
expect(input?.getAttribute("placeholder")).toBe("Inner placeholder");
|
|
218
|
-
// agentId and other properties would be tested through agent behavior
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
it("should allow accessing configuration outside CopilotChat in same provider", () => {
|
|
222
|
-
// This shows that ConfigurationDisplay outside CopilotChat
|
|
223
|
-
// sees the outer provider values, not the inner merged ones
|
|
224
|
-
render(
|
|
225
|
-
<CopilotKitProvider
|
|
226
|
-
agents__unsafe_dev_only={{
|
|
227
|
-
"outer-agent": new MockStepwiseAgent({ agentId: "outer-agent" }),
|
|
228
|
-
}}
|
|
229
|
-
>
|
|
230
|
-
<CopilotChatConfigurationProvider
|
|
231
|
-
threadId="outer-thread"
|
|
232
|
-
agentId="outer-agent"
|
|
233
|
-
labels={{ chatInputPlaceholder: "Outer placeholder" }}
|
|
234
|
-
>
|
|
235
|
-
<CopilotChat
|
|
236
|
-
threadId="inner-thread"
|
|
237
|
-
labels={{ chatInputPlaceholder: "Inner placeholder" }}
|
|
238
|
-
/>
|
|
239
|
-
<ConfigurationDisplay />
|
|
240
|
-
</CopilotChatConfigurationProvider>
|
|
241
|
-
</CopilotKitProvider>,
|
|
242
|
-
);
|
|
243
|
-
|
|
244
|
-
// ConfigurationDisplay is outside CopilotChat, so it sees outer values
|
|
245
|
-
expect(screen.getByTestId("agentId").textContent).toBe("outer-agent");
|
|
246
|
-
expect(screen.getByTestId("threadId").textContent).toBe("outer-thread");
|
|
247
|
-
expect(screen.getByTestId("placeholder").textContent).toBe(
|
|
248
|
-
"Outer placeholder",
|
|
249
|
-
);
|
|
250
|
-
});
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
describe("Modal state", () => {
|
|
254
|
-
it("should always provide setModalOpen and isModalOpen even without isModalDefaultOpen", () => {
|
|
255
|
-
function ModalStateDisplay() {
|
|
256
|
-
const config = useCopilotChatConfiguration();
|
|
257
|
-
return (
|
|
258
|
-
<div>
|
|
259
|
-
<div data-testid="hasSetModalOpen">
|
|
260
|
-
{config?.setModalOpen ? "yes" : "no"}
|
|
261
|
-
</div>
|
|
262
|
-
<div data-testid="hasIsModalOpen">
|
|
263
|
-
{config?.isModalOpen !== undefined ? "yes" : "no"}
|
|
264
|
-
</div>
|
|
265
|
-
</div>
|
|
266
|
-
);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
render(
|
|
270
|
-
<CopilotChatConfigurationProvider threadId="test-thread">
|
|
271
|
-
<ModalStateDisplay />
|
|
272
|
-
</CopilotChatConfigurationProvider>,
|
|
273
|
-
);
|
|
274
|
-
|
|
275
|
-
expect(screen.getByTestId("hasSetModalOpen").textContent).toBe("yes");
|
|
276
|
-
expect(screen.getByTestId("hasIsModalOpen").textContent).toBe("yes");
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
it("should respect isModalDefaultOpen when provided", () => {
|
|
280
|
-
function ModalStateDisplay() {
|
|
281
|
-
const config = useCopilotChatConfiguration();
|
|
282
|
-
return (
|
|
283
|
-
<div>
|
|
284
|
-
<div data-testid="isModalOpen">
|
|
285
|
-
{config?.isModalOpen ? "open" : "closed"}
|
|
286
|
-
</div>
|
|
287
|
-
</div>
|
|
288
|
-
);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
render(
|
|
292
|
-
<CopilotChatConfigurationProvider
|
|
293
|
-
threadId="test-thread"
|
|
294
|
-
isModalDefaultOpen={false}
|
|
295
|
-
>
|
|
296
|
-
<ModalStateDisplay />
|
|
297
|
-
</CopilotChatConfigurationProvider>,
|
|
298
|
-
);
|
|
299
|
-
|
|
300
|
-
expect(screen.getByTestId("isModalOpen").textContent).toBe("closed");
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
it("should inherit parent modal state when child has no isModalDefaultOpen", () => {
|
|
304
|
-
function ModalStateDisplay() {
|
|
305
|
-
const config = useCopilotChatConfiguration();
|
|
306
|
-
return (
|
|
307
|
-
<div>
|
|
308
|
-
<div data-testid="isModalOpen">
|
|
309
|
-
{config?.isModalOpen ? "open" : "closed"}
|
|
310
|
-
</div>
|
|
311
|
-
<div data-testid="hasSetModalOpen">
|
|
312
|
-
{config?.setModalOpen ? "yes" : "no"}
|
|
313
|
-
</div>
|
|
314
|
-
</div>
|
|
315
|
-
);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
render(
|
|
319
|
-
<CopilotChatConfigurationProvider
|
|
320
|
-
threadId="outer-thread"
|
|
321
|
-
isModalDefaultOpen={false}
|
|
322
|
-
>
|
|
323
|
-
<CopilotChatConfigurationProvider threadId="inner-thread">
|
|
324
|
-
<ModalStateDisplay />
|
|
325
|
-
</CopilotChatConfigurationProvider>
|
|
326
|
-
</CopilotChatConfigurationProvider>,
|
|
327
|
-
);
|
|
328
|
-
|
|
329
|
-
// Child should inherit parent's modal state (closed)
|
|
330
|
-
expect(screen.getByTestId("isModalOpen").textContent).toBe("closed");
|
|
331
|
-
expect(screen.getByTestId("hasSetModalOpen").textContent).toBe("yes");
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
it("should allow nested provider to override parent modal state with explicit isModalDefaultOpen", () => {
|
|
335
|
-
function ModalStateDisplay() {
|
|
336
|
-
const config = useCopilotChatConfiguration();
|
|
337
|
-
return (
|
|
338
|
-
<div>
|
|
339
|
-
<div data-testid="isModalOpen">
|
|
340
|
-
{config?.isModalOpen ? "open" : "closed"}
|
|
341
|
-
</div>
|
|
342
|
-
</div>
|
|
343
|
-
);
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
render(
|
|
347
|
-
<CopilotChatConfigurationProvider
|
|
348
|
-
threadId="outer-thread"
|
|
349
|
-
isModalDefaultOpen={true}
|
|
350
|
-
>
|
|
351
|
-
<CopilotChatConfigurationProvider
|
|
352
|
-
threadId="inner-thread"
|
|
353
|
-
isModalDefaultOpen={false}
|
|
354
|
-
>
|
|
355
|
-
<ModalStateDisplay />
|
|
356
|
-
</CopilotChatConfigurationProvider>
|
|
357
|
-
</CopilotChatConfigurationProvider>,
|
|
358
|
-
);
|
|
359
|
-
|
|
360
|
-
expect(screen.getByTestId("isModalOpen").textContent).toBe("closed");
|
|
361
|
-
});
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
/**
|
|
365
|
-
* CPK-7152: Bidirectional sync between nested providers.
|
|
366
|
-
*
|
|
367
|
-
* The fix must satisfy both:
|
|
368
|
-
* Behavior A — child provider respects its own isModalDefaultOpen even
|
|
369
|
-
* when a parent provider exists (covered by the existing
|
|
370
|
-
* "allow nested provider to override" test above).
|
|
371
|
-
* Behavior B — state changes in the inner provider propagate outward so
|
|
372
|
-
* that hooks reading from an outer provider stay in sync.
|
|
373
|
-
*
|
|
374
|
-
* Scenarios mirror the reproduction cases in:
|
|
375
|
-
* https://github.com/CopilotKit/deep-agent-cpk-experiments/tree/main/app/client/src/tickets/tkt-modal-default-open
|
|
376
|
-
*/
|
|
377
|
-
describe("Bidirectional sync (CPK-7152)", () => {
|
|
378
|
-
// Reusable probe/control component that reads the closest provider.
|
|
379
|
-
function ModalControls({ id }: { id: string }) {
|
|
380
|
-
const config = useCopilotChatConfiguration();
|
|
381
|
-
return (
|
|
382
|
-
<>
|
|
383
|
-
<div data-testid={`${id}-state`}>{String(config?.isModalOpen)}</div>
|
|
384
|
-
<button
|
|
385
|
-
data-testid={`${id}-open`}
|
|
386
|
-
onClick={() => config?.setModalOpen(true)}
|
|
387
|
-
>
|
|
388
|
-
open
|
|
389
|
-
</button>
|
|
390
|
-
<button
|
|
391
|
-
data-testid={`${id}-close`}
|
|
392
|
-
onClick={() => config?.setModalOpen(false)}
|
|
393
|
-
>
|
|
394
|
-
close
|
|
395
|
-
</button>
|
|
396
|
-
</>
|
|
397
|
-
);
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
it("scenario-sidebar-outer-hook: inner setModalOpen propagates to outer hook (Behavior B)", () => {
|
|
401
|
-
// Abe.Hu's layout: outer bare provider, inner provider owns explicit state.
|
|
402
|
-
// Toggling via the inner provider should update the outer hook.
|
|
403
|
-
render(
|
|
404
|
-
<CopilotChatConfigurationProvider threadId="outer">
|
|
405
|
-
{/* OuterProbe sits outside the inner provider — reads outer context */}
|
|
406
|
-
<ModalControls id="outer" />
|
|
407
|
-
<CopilotChatConfigurationProvider
|
|
408
|
-
threadId="inner"
|
|
409
|
-
isModalDefaultOpen={true}
|
|
410
|
-
>
|
|
411
|
-
<ModalControls id="inner" />
|
|
412
|
-
</CopilotChatConfigurationProvider>
|
|
413
|
-
</CopilotChatConfigurationProvider>,
|
|
414
|
-
);
|
|
415
|
-
|
|
416
|
-
expect(screen.getByTestId("outer-state").textContent).toBe("true");
|
|
417
|
-
expect(screen.getByTestId("inner-state").textContent).toBe("true");
|
|
418
|
-
|
|
419
|
-
act(() => {
|
|
420
|
-
fireEvent.click(screen.getByTestId("inner-close"));
|
|
421
|
-
});
|
|
422
|
-
|
|
423
|
-
// Inner closed — outer hook must reflect the change.
|
|
424
|
-
expect(screen.getByTestId("inner-state").textContent).toBe("false");
|
|
425
|
-
expect(screen.getByTestId("outer-state").textContent).toBe("false");
|
|
426
|
-
});
|
|
427
|
-
|
|
428
|
-
it("scenario-sidebar-outer-hook: outer setModalOpen propagates to inner (parent→child sync)", () => {
|
|
429
|
-
// If the user calls setModalOpen from the outer hook, the inner
|
|
430
|
-
// provider (and therefore the sidebar) must respond.
|
|
431
|
-
render(
|
|
432
|
-
<CopilotChatConfigurationProvider
|
|
433
|
-
threadId="outer"
|
|
434
|
-
isModalDefaultOpen={false}
|
|
435
|
-
>
|
|
436
|
-
<ModalControls id="outer" />
|
|
437
|
-
<CopilotChatConfigurationProvider
|
|
438
|
-
threadId="inner"
|
|
439
|
-
isModalDefaultOpen={false}
|
|
440
|
-
>
|
|
441
|
-
<ModalControls id="inner" />
|
|
442
|
-
</CopilotChatConfigurationProvider>
|
|
443
|
-
</CopilotChatConfigurationProvider>,
|
|
444
|
-
);
|
|
445
|
-
|
|
446
|
-
expect(screen.getByTestId("outer-state").textContent).toBe("false");
|
|
447
|
-
expect(screen.getByTestId("inner-state").textContent).toBe("false");
|
|
448
|
-
|
|
449
|
-
act(() => {
|
|
450
|
-
fireEvent.click(screen.getByTestId("outer-open"));
|
|
451
|
-
});
|
|
452
|
-
|
|
453
|
-
// Outer opened — inner must follow.
|
|
454
|
-
expect(screen.getByTestId("outer-state").textContent).toBe("true");
|
|
455
|
-
expect(screen.getByTestId("inner-state").textContent).toBe("true");
|
|
456
|
-
});
|
|
457
|
-
|
|
458
|
-
it("scenario-nested-provider: three-level chain propagates through middle provider", () => {
|
|
459
|
-
// Mirrors the real provider stack:
|
|
460
|
-
// Provider 1 (user's outer, no isModalDefaultOpen)
|
|
461
|
-
// └── Provider 2 (CopilotChat's, no isModalDefaultOpen) — "middle"
|
|
462
|
-
// └── Provider 3 (CopilotSidebarView's, explicit isModalDefaultOpen)
|
|
463
|
-
//
|
|
464
|
-
// Toggling P3 must reach P1 even though P2 has no explicit default.
|
|
465
|
-
render(
|
|
466
|
-
<CopilotChatConfigurationProvider threadId="p1">
|
|
467
|
-
<ModalControls id="p1" />
|
|
468
|
-
<CopilotChatConfigurationProvider threadId="p2">
|
|
469
|
-
{/* p2 has no isModalDefaultOpen — proxies p1's state */}
|
|
470
|
-
<CopilotChatConfigurationProvider
|
|
471
|
-
threadId="p3"
|
|
472
|
-
isModalDefaultOpen={true}
|
|
473
|
-
>
|
|
474
|
-
<ModalControls id="p3" />
|
|
475
|
-
</CopilotChatConfigurationProvider>
|
|
476
|
-
</CopilotChatConfigurationProvider>
|
|
477
|
-
</CopilotChatConfigurationProvider>,
|
|
478
|
-
);
|
|
479
|
-
|
|
480
|
-
expect(screen.getByTestId("p1-state").textContent).toBe("true");
|
|
481
|
-
expect(screen.getByTestId("p3-state").textContent).toBe("true");
|
|
482
|
-
|
|
483
|
-
act(() => {
|
|
484
|
-
fireEvent.click(screen.getByTestId("p3-close"));
|
|
485
|
-
});
|
|
486
|
-
|
|
487
|
-
expect(screen.getByTestId("p3-state").textContent).toBe("false");
|
|
488
|
-
expect(screen.getByTestId("p1-state").textContent).toBe("false");
|
|
489
|
-
});
|
|
490
|
-
|
|
491
|
-
it("scenario-nested-provider: Behavior A still holds after sync fix (no regression)", () => {
|
|
492
|
-
// Explicit isModalDefaultOpen on a child must still override the
|
|
493
|
-
// parent's current value on initial render — the sync effect must
|
|
494
|
-
// not overwrite the child's own initial state.
|
|
495
|
-
render(
|
|
496
|
-
<CopilotChatConfigurationProvider
|
|
497
|
-
threadId="outer"
|
|
498
|
-
isModalDefaultOpen={true}
|
|
499
|
-
>
|
|
500
|
-
<ModalControls id="outer" />
|
|
501
|
-
<CopilotChatConfigurationProvider
|
|
502
|
-
threadId="inner"
|
|
503
|
-
isModalDefaultOpen={false}
|
|
504
|
-
>
|
|
505
|
-
<ModalControls id="inner" />
|
|
506
|
-
</CopilotChatConfigurationProvider>
|
|
507
|
-
</CopilotChatConfigurationProvider>,
|
|
508
|
-
);
|
|
509
|
-
|
|
510
|
-
// Inner must start closed despite outer being open.
|
|
511
|
-
expect(screen.getByTestId("outer-state").textContent).toBe("true");
|
|
512
|
-
expect(screen.getByTestId("inner-state").textContent).toBe("false");
|
|
513
|
-
});
|
|
514
|
-
});
|
|
515
|
-
|
|
516
|
-
/**
|
|
517
|
-
* Regression coverage for the welcome-screen / /connect 404 bug
|
|
518
|
-
* (fix/welcome-not-showing-at-all). `hasExplicitThreadId` distinguishes a
|
|
519
|
-
* caller-chosen thread from a UUID auto-minted inside the provider chain —
|
|
520
|
-
* consumers that only make sense against a real backend thread (/connect,
|
|
521
|
-
* switch-flash suppression) must gate on this signal, not on !!threadId.
|
|
522
|
-
*/
|
|
523
|
-
describe("hasExplicitThreadId", () => {
|
|
524
|
-
function ExplicitProbe({ id = "probe" }: { id?: string } = {}) {
|
|
525
|
-
const config = useCopilotChatConfiguration();
|
|
526
|
-
return (
|
|
527
|
-
<div data-testid={`${id}-explicit`}>
|
|
528
|
-
{String(config?.hasExplicitThreadId)}
|
|
529
|
-
</div>
|
|
530
|
-
);
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
it("infers true when threadId prop is supplied and hasExplicitThreadId is omitted", () => {
|
|
534
|
-
render(
|
|
535
|
-
<CopilotChatConfigurationProvider threadId="customer-thread">
|
|
536
|
-
<ExplicitProbe />
|
|
537
|
-
</CopilotChatConfigurationProvider>,
|
|
538
|
-
);
|
|
539
|
-
|
|
540
|
-
expect(screen.getByTestId("probe-explicit").textContent).toBe("true");
|
|
541
|
-
});
|
|
542
|
-
|
|
543
|
-
it("infers false when no threadId prop is supplied and hasExplicitThreadId is omitted", () => {
|
|
544
|
-
render(
|
|
545
|
-
<CopilotChatConfigurationProvider>
|
|
546
|
-
<ExplicitProbe />
|
|
547
|
-
</CopilotChatConfigurationProvider>,
|
|
548
|
-
);
|
|
549
|
-
|
|
550
|
-
expect(screen.getByTestId("probe-explicit").textContent).toBe("false");
|
|
551
|
-
});
|
|
552
|
-
|
|
553
|
-
it("respects hasExplicitThreadId={false} even when a threadId prop is present (v1 bridge case)", () => {
|
|
554
|
-
// The v1 <CopilotKit> wrapper always pipes a UUID through as `threadId`
|
|
555
|
-
// (from ThreadsProvider). Without this override the provider would
|
|
556
|
-
// mis-infer the UUID as explicit, causing /connect to 404 and the
|
|
557
|
-
// welcome screen to stay hidden for fresh empty chats.
|
|
558
|
-
render(
|
|
559
|
-
<CopilotChatConfigurationProvider
|
|
560
|
-
threadId="auto-minted-uuid"
|
|
561
|
-
hasExplicitThreadId={false}
|
|
562
|
-
>
|
|
563
|
-
<ExplicitProbe />
|
|
564
|
-
</CopilotChatConfigurationProvider>,
|
|
565
|
-
);
|
|
566
|
-
|
|
567
|
-
expect(screen.getByTestId("probe-explicit").textContent).toBe("false");
|
|
568
|
-
});
|
|
569
|
-
|
|
570
|
-
it("parent=true overrides child's hasExplicitThreadId={false} via OR inheritance", () => {
|
|
571
|
-
// resolvedHasExplicitThreadId = ownHasExplicit || parentHasExplicit.
|
|
572
|
-
// Once an ancestor has marked the thread as caller-chosen, descendants
|
|
573
|
-
// cannot mask that — pinning the contract so "try to hide explicitness
|
|
574
|
-
// from a child" doesn't silently work.
|
|
575
|
-
render(
|
|
576
|
-
<CopilotChatConfigurationProvider threadId="real-thread">
|
|
577
|
-
<CopilotChatConfigurationProvider
|
|
578
|
-
threadId="other-uuid"
|
|
579
|
-
hasExplicitThreadId={false}
|
|
580
|
-
>
|
|
581
|
-
<ExplicitProbe />
|
|
582
|
-
</CopilotChatConfigurationProvider>
|
|
583
|
-
</CopilotChatConfigurationProvider>,
|
|
584
|
-
);
|
|
585
|
-
|
|
586
|
-
expect(screen.getByTestId("probe-explicit").textContent).toBe("true");
|
|
587
|
-
});
|
|
588
|
-
|
|
589
|
-
it("propagates through a three-level chain where the middle provider is bare", () => {
|
|
590
|
-
// Matches the real stack: outer layout provider (no threadId) →
|
|
591
|
-
// CopilotChat's own provider (no threadId) → inner feature provider
|
|
592
|
-
// (explicit threadId). Explicitness must cross the empty middle.
|
|
593
|
-
render(
|
|
594
|
-
<CopilotChatConfigurationProvider>
|
|
595
|
-
<CopilotChatConfigurationProvider>
|
|
596
|
-
<CopilotChatConfigurationProvider threadId="deeply-picked-thread">
|
|
597
|
-
<ExplicitProbe />
|
|
598
|
-
</CopilotChatConfigurationProvider>
|
|
599
|
-
</CopilotChatConfigurationProvider>
|
|
600
|
-
</CopilotChatConfigurationProvider>,
|
|
601
|
-
);
|
|
602
|
-
|
|
603
|
-
expect(screen.getByTestId("probe-explicit").textContent).toBe("true");
|
|
604
|
-
});
|
|
605
|
-
|
|
606
|
-
it("non-explicit parent does not taint an explicit child", () => {
|
|
607
|
-
render(
|
|
608
|
-
<CopilotChatConfigurationProvider
|
|
609
|
-
threadId="auto-uuid"
|
|
610
|
-
hasExplicitThreadId={false}
|
|
611
|
-
>
|
|
612
|
-
<CopilotChatConfigurationProvider threadId="user-picked">
|
|
613
|
-
<ExplicitProbe />
|
|
614
|
-
</CopilotChatConfigurationProvider>
|
|
615
|
-
</CopilotChatConfigurationProvider>,
|
|
616
|
-
);
|
|
617
|
-
|
|
618
|
-
expect(screen.getByTestId("probe-explicit").textContent).toBe("true");
|
|
619
|
-
});
|
|
620
|
-
});
|
|
621
|
-
|
|
622
|
-
describe("Nested providers", () => {
|
|
623
|
-
it("should handle multiple nested providers correctly", () => {
|
|
624
|
-
render(
|
|
625
|
-
<CopilotChatConfigurationProvider
|
|
626
|
-
threadId="outer-thread"
|
|
627
|
-
agentId="outer-agent"
|
|
628
|
-
labels={{ chatInputPlaceholder: "Outer" }}
|
|
629
|
-
>
|
|
630
|
-
<CopilotChatConfigurationProvider
|
|
631
|
-
threadId="middle-thread"
|
|
632
|
-
agentId="middle-agent"
|
|
633
|
-
labels={{ chatInputPlaceholder: "Middle" }}
|
|
634
|
-
>
|
|
635
|
-
<CopilotChatConfigurationProvider
|
|
636
|
-
threadId="inner-thread"
|
|
637
|
-
agentId="inner-agent"
|
|
638
|
-
labels={{ chatInputPlaceholder: "Inner" }}
|
|
639
|
-
>
|
|
640
|
-
<ConfigurationDisplay />
|
|
641
|
-
</CopilotChatConfigurationProvider>
|
|
642
|
-
</CopilotChatConfigurationProvider>
|
|
643
|
-
</CopilotChatConfigurationProvider>,
|
|
644
|
-
);
|
|
645
|
-
|
|
646
|
-
// Innermost provider should win
|
|
647
|
-
expect(screen.getByTestId("agentId").textContent).toBe("inner-agent");
|
|
648
|
-
expect(screen.getByTestId("threadId").textContent).toBe("inner-thread");
|
|
649
|
-
expect(screen.getByTestId("placeholder").textContent).toBe("Inner");
|
|
650
|
-
});
|
|
651
|
-
});
|
|
652
|
-
});
|