@mgamadeus/ddd-agents 0.1.0-alpha.23 → 0.1.0-alpha.24
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/chat.js +71 -827
- package/dist/chat.js.map +1 -1
- package/dist/chunks/ConversationMessageInputComposerWidgets-BxyaFBA6.js +631 -0
- package/dist/chunks/ConversationMessageInputComposerWidgets-BxyaFBA6.js.map +1 -0
- package/dist/chunks/{WebSearchResultsConversationWidget-DRBQvycE.js → WebSearchResultsConversationWidget-as3p5bHw.js} +92 -85
- package/dist/chunks/WebSearchResultsConversationWidget-as3p5bHw.js.map +1 -0
- package/dist/chunks/{decide-canvas-open-DBWoWtAC.js → canvas-behaviours-AvzKSYyv.js} +3 -19
- package/dist/chunks/canvas-behaviours-AvzKSYyv.js.map +1 -0
- package/dist/chunks/canvas-reducers-Bfp_i7lc.js +88 -0
- package/dist/chunks/canvas-reducers-Bfp_i7lc.js.map +1 -0
- package/dist/chunks/{canvasBodies-DLjDkviP.js → canvasBodies-Cvu3l38p.js} +6 -3
- package/dist/chunks/{canvasBodies-DLjDkviP.js.map → canvasBodies-Cvu3l38p.js.map} +1 -1
- package/dist/chunks/canvasStorage-EvQsGdto.js +65 -0
- package/dist/chunks/canvasStorage-EvQsGdto.js.map +1 -0
- package/dist/chunks/contract-BxmMxYPF.js +96 -0
- package/dist/chunks/contract-BxmMxYPF.js.map +1 -0
- package/dist/chunks/conversation-BEF0aesf.js +31 -0
- package/dist/chunks/conversation-BEF0aesf.js.map +1 -0
- package/dist/chunks/{ConversationMarkdown-CJhAnuVa.js → widget-click-signal-sources-DulRkNvZ.js} +22 -77
- package/dist/chunks/widget-click-signal-sources-DulRkNvZ.js.map +1 -0
- package/dist/chunks/{widget-name-resolver-C8SfpiR5.js → widget-name-resolver-BGN3HpoG.js} +61 -30
- package/dist/chunks/widget-name-resolver-BGN3HpoG.js.map +1 -0
- package/dist/chunks/{withPollingChangeSubscription-BLDAWF-o.js → withPollingChangeSubscription-B16htQGd.js} +2 -2
- package/dist/chunks/{withPollingChangeSubscription-BLDAWF-o.js.map → withPollingChangeSubscription-B16htQGd.js.map} +1 -1
- package/dist/client-testing.js +28 -6
- package/dist/client-testing.js.map +1 -1
- package/dist/client.js +1 -1
- package/dist/contract.js +8 -27
- package/dist/contract.js.map +1 -1
- package/dist/image-render.js +8 -8
- package/dist/index.js +6 -5
- package/dist/kit.js +2 -2
- package/dist/preview.js +44 -16
- package/dist/preview.js.map +1 -1
- package/dist/renderer.js +62 -57
- package/dist/renderer.js.map +1 -1
- package/dist/styles.css +55 -22
- package/dist/types/client/testing/widget-hydration-stand-ins.d.ts +12 -3
- package/dist/types/entries/chat.d.ts +2 -0
- package/dist/types/entries/client-testing.d.ts +2 -0
- package/dist/types/entries/contract.d.ts +1 -0
- package/dist/types/entries/index.d.ts +1 -1
- package/dist/types/entries/preview.d.ts +1 -0
- package/dist/types/entries/renderer.d.ts +3 -1
- package/dist/types/kit/components/data/chart-model.d.ts +2 -2
- package/dist/types/kit/components/data/use-chart-palette.d.ts +2 -2
- package/dist/types/kit/components/map/use-google-maps-auth-failure.d.ts +18 -0
- package/dist/types/kit/entity-detail/entity-detail-bodies.d.ts +2 -0
- package/dist/types/renderer/canvas/entity-detail-instance.d.ts +5 -3
- package/dist/types/renderer/widget-hydration/use-widget-hydration.d.ts +5 -0
- package/dist/types/widgets/EntityMentionConversationWidget/stories/EntityMentionAskFlowStory.d.ts +8 -0
- package/dist/widgets.js +33 -33
- package/package.json +1 -1
- package/public-api.json +19 -1
- package/dist/chunks/ConversationMarkdown-CJhAnuVa.js.map +0 -1
- package/dist/chunks/WebSearchResultsConversationWidget-DRBQvycE.js.map +0 -1
- package/dist/chunks/decide-canvas-open-DBWoWtAC.js.map +0 -1
- package/dist/chunks/widget-name-resolver-C8SfpiR5.js.map +0 -1
|
@@ -0,0 +1,631 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback, useSyncExternalStore, useContext, createContext, useMemo, useState, useRef, useEffect } from "react";
|
|
4
|
+
import { a3 as useAgentsEnvironment, a6 as useAgentsStateDispatch, a7 as useAgentsStateSelector, z as classNames } from "./index-7Qc_3GbG.js";
|
|
5
|
+
import { e as applySetCanvasCreatedEntityId, a as applyClearCanvas, d as applyResetCanvasForNewTurn, b as applyCloseCanvas, c as applyOpenCanvas } from "./canvas-reducers-Bfp_i7lc.js";
|
|
6
|
+
import { T as CANVAS_VIABLE_MIN_WIDTH, h as ConversationWidgetContext, E as useConversationWidgetContext } from "./WebSearchResultsConversationWidget-as3p5bHw.js";
|
|
7
|
+
import { s as storeOpenCanvas, c as clearStoredCanvas } from "./canvasStorage-EvQsGdto.js";
|
|
8
|
+
import { j as conversationWidgetRegistry } from "./widget-name-resolver-BGN3HpoG.js";
|
|
9
|
+
const EMPTY_AGENTS_CHAT_OPENING_REQUEST = {
|
|
10
|
+
userMessage: null,
|
|
11
|
+
startSignalText: null,
|
|
12
|
+
entryPointKey: null,
|
|
13
|
+
deepLinkedWidgetName: null
|
|
14
|
+
};
|
|
15
|
+
const INITIAL_AGENTS_CHAT_STATE = {
|
|
16
|
+
conversation: null,
|
|
17
|
+
messages: null,
|
|
18
|
+
conversationLoading: false,
|
|
19
|
+
conversationLoaded: false,
|
|
20
|
+
hasMoreOlder: false,
|
|
21
|
+
aiThinking: false,
|
|
22
|
+
error: null,
|
|
23
|
+
rateLimitRetryAfterSeconds: null,
|
|
24
|
+
requestedConversationId: null,
|
|
25
|
+
startingNewConversation: false,
|
|
26
|
+
pendingStartToken: null,
|
|
27
|
+
startTokenCount: 0,
|
|
28
|
+
openingRequest: EMPTY_AGENTS_CHAT_OPENING_REQUEST,
|
|
29
|
+
canvas: null,
|
|
30
|
+
lastClosedCanvas: null,
|
|
31
|
+
canvasMountCount: 0
|
|
32
|
+
};
|
|
33
|
+
const ConversationErrorType = {
|
|
34
|
+
AI_BUDGET: "AI_BUDGET",
|
|
35
|
+
/**
|
|
36
|
+
* HTTP 429 from an AI endpoint — a per-minute/hour/day usage quota was hit. Distinct from AI_BUDGET (monthly budget):
|
|
37
|
+
* this one clears on its own after the Retry-After window.
|
|
38
|
+
*/
|
|
39
|
+
RATE_LIMIT: "RATE_LIMIT",
|
|
40
|
+
NETWORK_ERROR: "NETWORK_ERROR",
|
|
41
|
+
CONVERSATION_NOT_FOUND: "CONVERSATION_NOT_FOUND",
|
|
42
|
+
/**
|
|
43
|
+
* The backend run FAILED (e.g. the model provider returned an error). The raw provider error is admin-only (never
|
|
44
|
+
* shown here); the owner gets a generic "something went wrong" card.
|
|
45
|
+
*/
|
|
46
|
+
AGENT_ERROR: "AGENT_ERROR",
|
|
47
|
+
/**
|
|
48
|
+
* The conversation is COMPLETED/CANCELLED and refuses further owner input. Set from the server's stable error code
|
|
49
|
+
* `CONVERSATION_CLOSED` or by the chat's own pre-send guard; the error card owns the copy.
|
|
50
|
+
*/
|
|
51
|
+
CONVERSATION_CLOSED: "CONVERSATION_CLOSED"
|
|
52
|
+
};
|
|
53
|
+
const readConversationErrorTypeOfRefusedSend = (error) => {
|
|
54
|
+
if (error.kind === "budget") return ConversationErrorType.AI_BUDGET;
|
|
55
|
+
if (error.kind === "rateLimit") return ConversationErrorType.RATE_LIMIT;
|
|
56
|
+
if (error.kind === "closed") return ConversationErrorType.CONVERSATION_CLOSED;
|
|
57
|
+
return ConversationErrorType.NETWORK_ERROR;
|
|
58
|
+
};
|
|
59
|
+
const mergeChatMessagesByIndex = (existing, incoming) => {
|
|
60
|
+
const messagesByIndex = /* @__PURE__ */ new Map();
|
|
61
|
+
const messagesWithoutIndex = [];
|
|
62
|
+
const collectMessage = (message) => {
|
|
63
|
+
if (message.indexInConversation != null) {
|
|
64
|
+
messagesByIndex.set(message.indexInConversation, message);
|
|
65
|
+
} else {
|
|
66
|
+
messagesWithoutIndex.push(message);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
existing.forEach(collectMessage);
|
|
70
|
+
incoming.forEach(collectMessage);
|
|
71
|
+
const indexedMessages = Array.from(messagesByIndex.values()).sort(
|
|
72
|
+
(first, second) => (first.indexInConversation ?? 0) - (second.indexInConversation ?? 0)
|
|
73
|
+
);
|
|
74
|
+
return [...indexedMessages, ...messagesWithoutIndex];
|
|
75
|
+
};
|
|
76
|
+
const tagFreshChatMessages = (incoming, previousMessages) => {
|
|
77
|
+
const previousIds = new Set(previousMessages.map((message) => message.id).filter((id) => id != null));
|
|
78
|
+
return incoming.map((message) => ({ ...message, fresh: message.id != null && !previousIds.has(message.id) }));
|
|
79
|
+
};
|
|
80
|
+
const mergeMessagesPage = (loadedMessages, page, requestedConversationId) => {
|
|
81
|
+
const shownConversationId = loadedMessages?.find((message) => message.conversationId != null)?.conversationId;
|
|
82
|
+
const replacesShownConversation = shownConversationId != null && shownConversationId !== requestedConversationId;
|
|
83
|
+
const existingMessages = replacesShownConversation ? [] : loadedMessages ?? [];
|
|
84
|
+
const messagesByIndex = /* @__PURE__ */ new Map();
|
|
85
|
+
for (const existingMessage of existingMessages) {
|
|
86
|
+
if (existingMessage.indexInConversation != null) {
|
|
87
|
+
messagesByIndex.set(existingMessage.indexInConversation, existingMessage);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const hadMessagesBeforeMerge = existingMessages.length > 0;
|
|
91
|
+
const highestShownIndex = Math.max(-1, ...existingMessages.map((message) => message.indexInConversation ?? -1));
|
|
92
|
+
for (const incomingMessage of page) {
|
|
93
|
+
if (incomingMessage.indexInConversation == null) continue;
|
|
94
|
+
const previousMessage = messagesByIndex.get(incomingMessage.indexInConversation);
|
|
95
|
+
const isLiveArrival = hadMessagesBeforeMerge && previousMessage == null && incomingMessage.indexInConversation > highestShownIndex;
|
|
96
|
+
messagesByIndex.set(incomingMessage.indexInConversation, {
|
|
97
|
+
...incomingMessage,
|
|
98
|
+
fresh: previousMessage?.fresh ?? isLiveArrival
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
return Array.from(messagesByIndex.values()).sort(
|
|
102
|
+
(first, second) => (first.indexInConversation ?? 0) - (second.indexInConversation ?? 0)
|
|
103
|
+
);
|
|
104
|
+
};
|
|
105
|
+
const withRefusedSendError = (state, error) => {
|
|
106
|
+
const conversationErrorType = readConversationErrorTypeOfRefusedSend(error);
|
|
107
|
+
return {
|
|
108
|
+
...state,
|
|
109
|
+
error: conversationErrorType,
|
|
110
|
+
rateLimitRetryAfterSeconds: conversationErrorType === ConversationErrorType.RATE_LIMIT ? error.retryAfterSeconds ?? null : null
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
const mergeSendAnswer = (loadedMessages, answerMessages) => {
|
|
114
|
+
const messagesWithoutOptimisticMessage = loadedMessages ? loadedMessages.slice(0, loadedMessages.length - 1) : [];
|
|
115
|
+
return mergeChatMessagesByIndex(
|
|
116
|
+
messagesWithoutOptimisticMessage,
|
|
117
|
+
tagFreshChatMessages(answerMessages, messagesWithoutOptimisticMessage)
|
|
118
|
+
);
|
|
119
|
+
};
|
|
120
|
+
const withCanvasTransition = (state, applyCanvasTransition) => {
|
|
121
|
+
const nextState = { ...state };
|
|
122
|
+
applyCanvasTransition(nextState);
|
|
123
|
+
const changed = nextState.canvas !== state.canvas || nextState.lastClosedCanvas !== state.lastClosedCanvas || nextState.canvasMountCount !== state.canvasMountCount;
|
|
124
|
+
return changed ? nextState : state;
|
|
125
|
+
};
|
|
126
|
+
const reduceAgentsChatState = (state, event) => {
|
|
127
|
+
switch (event.type) {
|
|
128
|
+
case "reset":
|
|
129
|
+
return {
|
|
130
|
+
...INITIAL_AGENTS_CHAT_STATE,
|
|
131
|
+
openingRequest: state.openingRequest,
|
|
132
|
+
canvasMountCount: state.canvasMountCount,
|
|
133
|
+
startTokenCount: state.startTokenCount
|
|
134
|
+
};
|
|
135
|
+
case "conversationMetadataRequested":
|
|
136
|
+
case "messagesPageRequested":
|
|
137
|
+
return state.requestedConversationId === event.conversationId ? state : { ...state, requestedConversationId: event.conversationId };
|
|
138
|
+
case "conversationMetadataReceived":
|
|
139
|
+
if (state.requestedConversationId === null || state.requestedConversationId !== event.conversationId) {
|
|
140
|
+
return state;
|
|
141
|
+
}
|
|
142
|
+
return { ...state, conversation: event.conversation, conversationLoaded: true };
|
|
143
|
+
case "conversationMetadataFailed":
|
|
144
|
+
return { ...state, conversationLoaded: true };
|
|
145
|
+
case "messagesPageReceived": {
|
|
146
|
+
if (state.requestedConversationId === null || state.requestedConversationId !== event.conversationId) {
|
|
147
|
+
return state;
|
|
148
|
+
}
|
|
149
|
+
if (state.conversation !== null && state.conversation.id !== event.conversationId) {
|
|
150
|
+
return state;
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
...state,
|
|
154
|
+
messages: mergeMessagesPage(state.messages, event.messages, event.conversationId),
|
|
155
|
+
hasMoreOlder: event.hasMoreOlder ?? state.hasMoreOlder,
|
|
156
|
+
conversationLoaded: true
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
case "messagePostRequested":
|
|
160
|
+
return {
|
|
161
|
+
...state,
|
|
162
|
+
conversationLoading: true,
|
|
163
|
+
conversationLoaded: false,
|
|
164
|
+
aiThinking: true,
|
|
165
|
+
error: null,
|
|
166
|
+
rateLimitRetryAfterSeconds: null,
|
|
167
|
+
messages: [...state.messages ?? [], event.message]
|
|
168
|
+
};
|
|
169
|
+
case "messagePostReceived":
|
|
170
|
+
if (event.conversationId !== state.conversation?.id) {
|
|
171
|
+
return state;
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
...state,
|
|
175
|
+
messages: mergeSendAnswer(state.messages, event.posted.messages),
|
|
176
|
+
conversationLoading: false,
|
|
177
|
+
conversationLoaded: true,
|
|
178
|
+
error: null
|
|
179
|
+
};
|
|
180
|
+
case "messagePostFailed":
|
|
181
|
+
return withRefusedSendError(
|
|
182
|
+
{ ...state, conversationLoading: false, conversationLoaded: true, aiThinking: false },
|
|
183
|
+
event.error
|
|
184
|
+
);
|
|
185
|
+
case "startRequested":
|
|
186
|
+
return {
|
|
187
|
+
...state,
|
|
188
|
+
conversation: null,
|
|
189
|
+
conversationLoading: true,
|
|
190
|
+
conversationLoaded: false,
|
|
191
|
+
aiThinking: true,
|
|
192
|
+
error: null,
|
|
193
|
+
rateLimitRetryAfterSeconds: null,
|
|
194
|
+
startingNewConversation: true,
|
|
195
|
+
startTokenCount: state.startTokenCount + 1,
|
|
196
|
+
pendingStartToken: state.startTokenCount + 1,
|
|
197
|
+
// A signal-only start (an empty visible message carries the start signal) seeds no empty bubble.
|
|
198
|
+
messages: event.message.message ? [event.message] : []
|
|
199
|
+
};
|
|
200
|
+
case "startReceived": {
|
|
201
|
+
if (event.startToken !== state.pendingStartToken) {
|
|
202
|
+
return state;
|
|
203
|
+
}
|
|
204
|
+
const { started } = event;
|
|
205
|
+
if (started.reopenedExisting) {
|
|
206
|
+
return {
|
|
207
|
+
...state,
|
|
208
|
+
conversation: started.conversation,
|
|
209
|
+
messages: [],
|
|
210
|
+
conversationLoading: false,
|
|
211
|
+
conversationLoaded: true,
|
|
212
|
+
aiThinking: false,
|
|
213
|
+
startingNewConversation: false,
|
|
214
|
+
pendingStartToken: null
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
...state,
|
|
219
|
+
conversation: started.conversation,
|
|
220
|
+
messages: mergeSendAnswer(state.messages, started.messages),
|
|
221
|
+
conversationLoading: false,
|
|
222
|
+
conversationLoaded: true,
|
|
223
|
+
startingNewConversation: false,
|
|
224
|
+
pendingStartToken: null
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
case "startFailed":
|
|
228
|
+
return withRefusedSendError(
|
|
229
|
+
{
|
|
230
|
+
...state,
|
|
231
|
+
conversation: null,
|
|
232
|
+
conversationLoading: false,
|
|
233
|
+
conversationLoaded: true,
|
|
234
|
+
aiThinking: false,
|
|
235
|
+
startingNewConversation: false,
|
|
236
|
+
pendingStartToken: null
|
|
237
|
+
},
|
|
238
|
+
event.error
|
|
239
|
+
);
|
|
240
|
+
case "errorSet":
|
|
241
|
+
return state.error === event.error ? state : { ...state, error: event.error };
|
|
242
|
+
case "aiThinkingSet":
|
|
243
|
+
return state.aiThinking === event.aiThinking ? state : { ...state, aiThinking: event.aiThinking };
|
|
244
|
+
case "openingRequestSet":
|
|
245
|
+
return { ...state, openingRequest: { ...state.openingRequest, ...event.openingRequest } };
|
|
246
|
+
case "canvasOpened":
|
|
247
|
+
return withCanvasTransition(state, (nextState) => {
|
|
248
|
+
applyOpenCanvas(nextState, event.request);
|
|
249
|
+
});
|
|
250
|
+
case "canvasClosed":
|
|
251
|
+
return withCanvasTransition(state, (nextState) => applyCloseCanvas(nextState, event.byCustomer));
|
|
252
|
+
case "canvasResetForNewTurn":
|
|
253
|
+
return withCanvasTransition(state, applyResetCanvasForNewTurn);
|
|
254
|
+
case "canvasCleared":
|
|
255
|
+
return withCanvasTransition(state, applyClearCanvas);
|
|
256
|
+
case "canvasCreatedEntityIdSet":
|
|
257
|
+
return withCanvasTransition(state, (nextState) => {
|
|
258
|
+
applySetCanvasCreatedEntityId(nextState, event.created);
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
class AgentsChatStateContainer {
|
|
263
|
+
constructor(initialState = INITIAL_AGENTS_CHAT_STATE) {
|
|
264
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
265
|
+
this.getState = () => this.state;
|
|
266
|
+
this.subscribe = (listener) => {
|
|
267
|
+
this.listeners.add(listener);
|
|
268
|
+
return () => {
|
|
269
|
+
this.listeners.delete(listener);
|
|
270
|
+
};
|
|
271
|
+
};
|
|
272
|
+
this.dispatch = (event) => {
|
|
273
|
+
const nextState = reduceAgentsChatState(this.state, event);
|
|
274
|
+
if (nextState === this.state) return;
|
|
275
|
+
this.state = nextState;
|
|
276
|
+
for (const notifyListener of [...this.listeners]) notifyListener();
|
|
277
|
+
};
|
|
278
|
+
this.state = initialState;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
const createAgentsChatStore = (initialState) => new AgentsChatStateContainer(initialState);
|
|
282
|
+
const AgentsChatStoreContext = createContext(null);
|
|
283
|
+
const AgentsChatStoreProvider = (props) => {
|
|
284
|
+
const { chatStore, children } = props;
|
|
285
|
+
return /* @__PURE__ */ jsx(AgentsChatStoreContext.Provider, { value: chatStore, children });
|
|
286
|
+
};
|
|
287
|
+
const useAgentsChatStore = () => {
|
|
288
|
+
const chatStore = useContext(AgentsChatStoreContext);
|
|
289
|
+
if (chatStore === null) {
|
|
290
|
+
throw new Error("A chat component rendered outside AgentsChatStoreProvider: the app has to mount its chat store.");
|
|
291
|
+
}
|
|
292
|
+
return chatStore;
|
|
293
|
+
};
|
|
294
|
+
const useOptionalAgentsChatStore = () => useContext(AgentsChatStoreContext);
|
|
295
|
+
const subscribeToNothing = () => () => void 0;
|
|
296
|
+
const useAgentsChatSelector = (chatStore, selector, valueWithoutStore) => {
|
|
297
|
+
const subscribe = chatStore ? chatStore.subscribe : subscribeToNothing;
|
|
298
|
+
const readSelectedValue = useCallback(
|
|
299
|
+
() => chatStore ? selector(chatStore.getState()) : valueWithoutStore,
|
|
300
|
+
[chatStore, selector, valueWithoutStore]
|
|
301
|
+
);
|
|
302
|
+
return useSyncExternalStore(subscribe, readSelectedValue, readSelectedValue);
|
|
303
|
+
};
|
|
304
|
+
const useAgentsChatState = (selector) => useAgentsChatSelector(useAgentsChatStore(), selector);
|
|
305
|
+
let agenticChatMountCount = 0;
|
|
306
|
+
const selectCanvas = (state) => state.canvas;
|
|
307
|
+
const selectLastClosedCanvas = (state) => state.lastClosedCanvas;
|
|
308
|
+
const selectAiThinking = (state) => state.aiThinking;
|
|
309
|
+
const selectRunState = (state) => state.conversation?.runState;
|
|
310
|
+
const selectMessages = (state) => state.messages;
|
|
311
|
+
const ChatStoreConversationWidgetProvider = (props) => {
|
|
312
|
+
const { chatStore, ...bodyProps } = props;
|
|
313
|
+
const canvas = useAgentsChatSelector(chatStore, selectCanvas);
|
|
314
|
+
const lastClosedCanvas = useAgentsChatSelector(chatStore, selectLastClosedCanvas);
|
|
315
|
+
const isConversationRunning = useAgentsChatSelector(chatStore, selectAiThinking);
|
|
316
|
+
const runState = useAgentsChatSelector(chatStore, selectRunState);
|
|
317
|
+
const messages = useAgentsChatSelector(chatStore, selectMessages);
|
|
318
|
+
const chatState = useMemo(
|
|
319
|
+
() => ({
|
|
320
|
+
canvas,
|
|
321
|
+
lastClosedCanvas,
|
|
322
|
+
isConversationRunning,
|
|
323
|
+
runState,
|
|
324
|
+
messages,
|
|
325
|
+
dispatchCanvasEvent: chatStore.dispatch
|
|
326
|
+
}),
|
|
327
|
+
[canvas, lastClosedCanvas, isConversationRunning, runState, messages, chatStore]
|
|
328
|
+
);
|
|
329
|
+
return /* @__PURE__ */ jsx(ConversationWidgetProviderBody, { ...bodyProps, chatState });
|
|
330
|
+
};
|
|
331
|
+
const SliceConversationWidgetProvider = (props) => {
|
|
332
|
+
const { sliceInstance, ...bodyProps } = props;
|
|
333
|
+
const dispatch = useAgentsStateDispatch();
|
|
334
|
+
const canvas = useAgentsStateSelector((state) => sliceInstance.selectState(state).canvas);
|
|
335
|
+
const lastClosedCanvas = useAgentsStateSelector((state) => sliceInstance.selectState(state).lastClosedCanvas);
|
|
336
|
+
const isConversationRunning = useAgentsStateSelector((state) => sliceInstance.selectState(state).aiThinking);
|
|
337
|
+
const runState = useAgentsStateSelector((state) => sliceInstance.selectState(state).conversation?.runState);
|
|
338
|
+
const messages = useAgentsStateSelector((state) => sliceInstance.selectState(state).messages);
|
|
339
|
+
const dispatchCanvasEvent = useCallback(
|
|
340
|
+
(event) => {
|
|
341
|
+
const { actions } = sliceInstance;
|
|
342
|
+
if (event.type === "canvasOpened") dispatch(actions.openCanvas(event.request));
|
|
343
|
+
else if (event.type === "canvasClosed") dispatch(actions.closeCanvas({ byCustomer: event.byCustomer }));
|
|
344
|
+
else if (event.type === "canvasResetForNewTurn") dispatch(actions.resetCanvasForNewTurn());
|
|
345
|
+
else if (event.type === "canvasCleared") dispatch(actions.clearCanvas());
|
|
346
|
+
else dispatch(actions.setCanvasCreatedEntityId(event.created));
|
|
347
|
+
},
|
|
348
|
+
[dispatch, sliceInstance]
|
|
349
|
+
);
|
|
350
|
+
const chatState = useMemo(
|
|
351
|
+
() => ({ canvas, lastClosedCanvas, isConversationRunning, runState, messages, dispatchCanvasEvent }),
|
|
352
|
+
[canvas, lastClosedCanvas, isConversationRunning, runState, messages, dispatchCanvasEvent]
|
|
353
|
+
);
|
|
354
|
+
return /* @__PURE__ */ jsx(ConversationWidgetProviderBody, { ...bodyProps, chatState });
|
|
355
|
+
};
|
|
356
|
+
const OwnChatStoreConversationWidgetProvider = (props) => {
|
|
357
|
+
const [ownChatStore] = useState(createAgentsChatStore);
|
|
358
|
+
return /* @__PURE__ */ jsx(ChatStoreConversationWidgetProvider, { ...props, chatStore: ownChatStore });
|
|
359
|
+
};
|
|
360
|
+
const ConversationWidgetProvider = (props) => {
|
|
361
|
+
const { sliceInstance, chatStore, ...bodyProps } = props;
|
|
362
|
+
const { defaultChatStatePartition } = useAgentsEnvironment();
|
|
363
|
+
const statePartition = sliceInstance ?? defaultChatStatePartition;
|
|
364
|
+
if (chatStore) return /* @__PURE__ */ jsx(ChatStoreConversationWidgetProvider, { ...bodyProps, chatStore });
|
|
365
|
+
if (statePartition) return /* @__PURE__ */ jsx(SliceConversationWidgetProvider, { ...bodyProps, sliceInstance: statePartition });
|
|
366
|
+
return /* @__PURE__ */ jsx(OwnChatStoreConversationWidgetProvider, { ...bodyProps });
|
|
367
|
+
};
|
|
368
|
+
const ConversationWidgetProviderBody = ({
|
|
369
|
+
children,
|
|
370
|
+
callbacks,
|
|
371
|
+
hostHasCanvasSurface = true,
|
|
372
|
+
chatState
|
|
373
|
+
}) => {
|
|
374
|
+
const dispatch = useAgentsStateDispatch();
|
|
375
|
+
const { buildChatSurfaceOpenChangedAction } = useAgentsEnvironment();
|
|
376
|
+
const { canvas, lastClosedCanvas, isConversationRunning, runState, messages } = chatState;
|
|
377
|
+
const isConversationClosed = runState === "COMPLETED" || runState === "CANCELLED";
|
|
378
|
+
const dispatchCanvasEventRef = useRef(chatState.dispatchCanvasEvent);
|
|
379
|
+
dispatchCanvasEventRef.current = chatState.dispatchCanvasEvent;
|
|
380
|
+
const hostHasCanvasSurfaceRef = useRef(hostHasCanvasSurface);
|
|
381
|
+
hostHasCanvasSurfaceRef.current = hostHasCanvasSurface;
|
|
382
|
+
const buildChatSurfaceOpenChangedActionRef = useRef(buildChatSurfaceOpenChangedAction);
|
|
383
|
+
buildChatSurfaceOpenChangedActionRef.current = buildChatSurfaceOpenChangedAction;
|
|
384
|
+
useEffect(() => {
|
|
385
|
+
agenticChatMountCount += 1;
|
|
386
|
+
if (agenticChatMountCount === 1 && buildChatSurfaceOpenChangedActionRef.current) {
|
|
387
|
+
dispatch(buildChatSurfaceOpenChangedActionRef.current(true));
|
|
388
|
+
}
|
|
389
|
+
return () => {
|
|
390
|
+
agenticChatMountCount -= 1;
|
|
391
|
+
if (agenticChatMountCount === 0 && buildChatSurfaceOpenChangedActionRef.current) {
|
|
392
|
+
dispatch(buildChatSurfaceOpenChangedActionRef.current(false));
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
}, [dispatch]);
|
|
396
|
+
const callbacksRef = useRef(callbacks);
|
|
397
|
+
callbacksRef.current = callbacks;
|
|
398
|
+
const isComposerWidgetsControlled = callbacks.composerWidgets !== void 0;
|
|
399
|
+
const [internalComposerWidgets, setInternalComposerWidgets] = useState([]);
|
|
400
|
+
const composerWidgets = isComposerWidgetsControlled ? callbacks.composerWidgets : internalComposerWidgets;
|
|
401
|
+
const composerWidgetsStateRef = useRef({ composerWidgets, isComposerWidgetsControlled });
|
|
402
|
+
composerWidgetsStateRef.current = { composerWidgets, isComposerWidgetsControlled };
|
|
403
|
+
const publishComposerWidgets = useCallback((next) => {
|
|
404
|
+
if (composerWidgetsStateRef.current.isComposerWidgetsControlled) {
|
|
405
|
+
callbacksRef.current.onComposerWidgetsChange?.(next);
|
|
406
|
+
} else {
|
|
407
|
+
setInternalComposerWidgets(next);
|
|
408
|
+
}
|
|
409
|
+
}, []);
|
|
410
|
+
const addComposerWidget = useCallback(
|
|
411
|
+
(widgetName, fields) => {
|
|
412
|
+
const composerWidgetId = crypto.randomUUID();
|
|
413
|
+
publishComposerWidgets([
|
|
414
|
+
...composerWidgetsStateRef.current.composerWidgets,
|
|
415
|
+
{ composerWidgetId, widgetName, fields }
|
|
416
|
+
]);
|
|
417
|
+
return composerWidgetId;
|
|
418
|
+
},
|
|
419
|
+
[publishComposerWidgets]
|
|
420
|
+
);
|
|
421
|
+
const replaceComposerWidgetFields = useCallback(
|
|
422
|
+
(composerWidgetId, fields) => {
|
|
423
|
+
publishComposerWidgets(
|
|
424
|
+
composerWidgetsStateRef.current.composerWidgets.map(
|
|
425
|
+
(widget) => widget.composerWidgetId === composerWidgetId ? { ...widget, fields } : widget
|
|
426
|
+
)
|
|
427
|
+
);
|
|
428
|
+
},
|
|
429
|
+
[publishComposerWidgets]
|
|
430
|
+
);
|
|
431
|
+
const removeComposerWidget = useCallback(
|
|
432
|
+
(composerWidgetId) => {
|
|
433
|
+
publishComposerWidgets(
|
|
434
|
+
composerWidgetsStateRef.current.composerWidgets.filter(
|
|
435
|
+
(widget) => widget.composerWidgetId !== composerWidgetId
|
|
436
|
+
)
|
|
437
|
+
);
|
|
438
|
+
},
|
|
439
|
+
[publishComposerWidgets]
|
|
440
|
+
);
|
|
441
|
+
const clearComposerWidgets = useCallback(() => {
|
|
442
|
+
publishComposerWidgets([]);
|
|
443
|
+
}, [publishComposerWidgets]);
|
|
444
|
+
const openCanvas = useCallback(
|
|
445
|
+
(request) => {
|
|
446
|
+
dispatchCanvasEventRef.current({
|
|
447
|
+
type: "canvasOpened",
|
|
448
|
+
request: {
|
|
449
|
+
...request,
|
|
450
|
+
viewportViable: window.innerWidth >= CANVAS_VIABLE_MIN_WIDTH,
|
|
451
|
+
hostHasCanvasSurface: hostHasCanvasSurfaceRef.current
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
},
|
|
455
|
+
[]
|
|
456
|
+
);
|
|
457
|
+
const closeCanvas = useCallback(
|
|
458
|
+
(byCustomer) => {
|
|
459
|
+
dispatchCanvasEventRef.current({ type: "canvasClosed", byCustomer });
|
|
460
|
+
},
|
|
461
|
+
[]
|
|
462
|
+
);
|
|
463
|
+
const lastClosedCanvasRef = useRef(lastClosedCanvas);
|
|
464
|
+
lastClosedCanvasRef.current = lastClosedCanvas;
|
|
465
|
+
const reopenLastClosedCanvas = useCallback(() => {
|
|
466
|
+
const last = lastClosedCanvasRef.current;
|
|
467
|
+
if (last === null) return;
|
|
468
|
+
dispatchCanvasEventRef.current({
|
|
469
|
+
type: "canvasOpened",
|
|
470
|
+
request: {
|
|
471
|
+
canvasId: last.canvasId,
|
|
472
|
+
instanceId: last.instanceId,
|
|
473
|
+
anchor: last.anchor,
|
|
474
|
+
origin: "cardClick",
|
|
475
|
+
justDelivered: false,
|
|
476
|
+
viewportViable: window.innerWidth >= CANVAS_VIABLE_MIN_WIDTH,
|
|
477
|
+
hostHasCanvasSurface: hostHasCanvasSurfaceRef.current,
|
|
478
|
+
...last.createdEntityId !== void 0 ? { createdEntityId: last.createdEntityId } : {}
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
}, []);
|
|
482
|
+
const setCanvasCreatedEntityId = useCallback(
|
|
483
|
+
(created) => {
|
|
484
|
+
dispatchCanvasEventRef.current({ type: "canvasCreatedEntityIdSet", created });
|
|
485
|
+
},
|
|
486
|
+
[]
|
|
487
|
+
);
|
|
488
|
+
const storedCanvasConversationIdRef = useRef(void 0);
|
|
489
|
+
const conversationIdForStorage = callbacks.conversationId;
|
|
490
|
+
useEffect(() => {
|
|
491
|
+
if (canvas !== null) {
|
|
492
|
+
storeOpenCanvas(conversationIdForStorage, canvas);
|
|
493
|
+
storedCanvasConversationIdRef.current = conversationIdForStorage;
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
if (storedCanvasConversationIdRef.current !== void 0 && storedCanvasConversationIdRef.current === conversationIdForStorage) {
|
|
497
|
+
clearStoredCanvas(conversationIdForStorage);
|
|
498
|
+
}
|
|
499
|
+
storedCanvasConversationIdRef.current = void 0;
|
|
500
|
+
}, [canvas, conversationIdForStorage]);
|
|
501
|
+
const resetCanvas = useCallback(() => {
|
|
502
|
+
dispatchCanvasEventRef.current({ type: "canvasCleared" });
|
|
503
|
+
}, []);
|
|
504
|
+
const resetCanvasForNewTurn = useCallback(() => {
|
|
505
|
+
dispatchCanvasEventRef.current({ type: "canvasResetForNewTurn" });
|
|
506
|
+
}, []);
|
|
507
|
+
const sendMessageToChat = useCallback((message) => {
|
|
508
|
+
return callbacksRef.current.sendMessageToChat?.(message);
|
|
509
|
+
}, []);
|
|
510
|
+
const prefillComposer = useCallback((text) => {
|
|
511
|
+
callbacksRef.current.prefillComposer?.(text);
|
|
512
|
+
}, []);
|
|
513
|
+
const injectSignal = useCallback((signalText, options) => {
|
|
514
|
+
return callbacksRef.current.injectSignal?.(signalText, options);
|
|
515
|
+
}, []);
|
|
516
|
+
const minimizeChatHost = useCallback(() => {
|
|
517
|
+
callbacksRef.current.minimizeChatHost?.();
|
|
518
|
+
}, []);
|
|
519
|
+
const contextValue = useMemo(
|
|
520
|
+
() => ({
|
|
521
|
+
canvas,
|
|
522
|
+
hostHasCanvasSurface,
|
|
523
|
+
lastClosedCanvas,
|
|
524
|
+
openCanvas,
|
|
525
|
+
closeCanvas,
|
|
526
|
+
reopenLastClosedCanvas,
|
|
527
|
+
setCanvasCreatedEntityId,
|
|
528
|
+
resetCanvas,
|
|
529
|
+
resetCanvasForNewTurn,
|
|
530
|
+
sendMessageToChat,
|
|
531
|
+
prefillComposer,
|
|
532
|
+
injectSignal,
|
|
533
|
+
minimizeChatHost,
|
|
534
|
+
chatAgentSpaceKey: callbacks.chatAgentSpaceKey,
|
|
535
|
+
isConversationRunning,
|
|
536
|
+
isConversationClosed,
|
|
537
|
+
conversationId: callbacks.conversationId,
|
|
538
|
+
composerWidgets,
|
|
539
|
+
addComposerWidget,
|
|
540
|
+
replaceComposerWidgetFields,
|
|
541
|
+
removeComposerWidget,
|
|
542
|
+
clearComposerWidgets,
|
|
543
|
+
onOpenConversation: callbacks.onOpenConversation,
|
|
544
|
+
onSwitchConversation: callbacks.onSwitchConversation,
|
|
545
|
+
isOnboardingSetupConversation: callbacks.isOnboardingSetupConversation ?? false,
|
|
546
|
+
messages
|
|
547
|
+
}),
|
|
548
|
+
[
|
|
549
|
+
canvas,
|
|
550
|
+
hostHasCanvasSurface,
|
|
551
|
+
lastClosedCanvas,
|
|
552
|
+
openCanvas,
|
|
553
|
+
closeCanvas,
|
|
554
|
+
reopenLastClosedCanvas,
|
|
555
|
+
setCanvasCreatedEntityId,
|
|
556
|
+
resetCanvas,
|
|
557
|
+
resetCanvasForNewTurn,
|
|
558
|
+
sendMessageToChat,
|
|
559
|
+
prefillComposer,
|
|
560
|
+
injectSignal,
|
|
561
|
+
minimizeChatHost,
|
|
562
|
+
callbacks.chatAgentSpaceKey,
|
|
563
|
+
isConversationRunning,
|
|
564
|
+
isConversationClosed,
|
|
565
|
+
callbacks.conversationId,
|
|
566
|
+
composerWidgets,
|
|
567
|
+
addComposerWidget,
|
|
568
|
+
replaceComposerWidgetFields,
|
|
569
|
+
removeComposerWidget,
|
|
570
|
+
clearComposerWidgets,
|
|
571
|
+
callbacks.onOpenConversation,
|
|
572
|
+
callbacks.onSwitchConversation,
|
|
573
|
+
callbacks.isOnboardingSetupConversation,
|
|
574
|
+
messages
|
|
575
|
+
]
|
|
576
|
+
);
|
|
577
|
+
return /* @__PURE__ */ jsx(ConversationWidgetContext.Provider, { value: contextValue, children });
|
|
578
|
+
};
|
|
579
|
+
const stripReveal = "agents_stripReveal_6XAjCM";
|
|
580
|
+
const stripRevealOpen = "agents_stripRevealOpen_sWkJwh";
|
|
581
|
+
const stripRevealInner = "agents_stripRevealInner_C2VlV7";
|
|
582
|
+
const strip = "agents_strip_rKQFvx";
|
|
583
|
+
const styles = {
|
|
584
|
+
stripReveal,
|
|
585
|
+
stripRevealOpen,
|
|
586
|
+
stripRevealInner,
|
|
587
|
+
strip
|
|
588
|
+
};
|
|
589
|
+
const ConversationMessageInputComposerWidgets = (props) => {
|
|
590
|
+
const { testId = "chat-input" } = props;
|
|
591
|
+
const { composerWidgets, replaceComposerWidgetFields, removeComposerWidget } = useConversationWidgetContext();
|
|
592
|
+
const renderableWidgets = composerWidgets.flatMap((widget) => {
|
|
593
|
+
const entry = conversationWidgetRegistry.widgets.find((candidate) => candidate.name === widget.widgetName);
|
|
594
|
+
return entry?.composerComponent ? [{ widget, Component: entry.composerComponent }] : [];
|
|
595
|
+
});
|
|
596
|
+
return /* @__PURE__ */ jsx(
|
|
597
|
+
"div",
|
|
598
|
+
{
|
|
599
|
+
className: classNames(styles.stripReveal, { [styles.stripRevealOpen]: renderableWidgets.length > 0 }),
|
|
600
|
+
"data-testid": `${testId}-composer-widgets-strip`,
|
|
601
|
+
children: /* @__PURE__ */ jsx("div", { className: styles.stripRevealInner, children: /* @__PURE__ */ jsx("div", { className: styles.strip, children: renderableWidgets.map(({ widget, Component }) => /* @__PURE__ */ jsx(
|
|
602
|
+
Component,
|
|
603
|
+
{
|
|
604
|
+
composerWidgetId: widget.composerWidgetId,
|
|
605
|
+
fields: widget.fields,
|
|
606
|
+
replaceFields: (nextFields) => replaceComposerWidgetFields(widget.composerWidgetId, nextFields),
|
|
607
|
+
remove: () => removeComposerWidget(widget.composerWidgetId),
|
|
608
|
+
testId: `${testId}-composer-widget-${widget.composerWidgetId}`
|
|
609
|
+
},
|
|
610
|
+
widget.composerWidgetId
|
|
611
|
+
)) }) })
|
|
612
|
+
}
|
|
613
|
+
);
|
|
614
|
+
};
|
|
615
|
+
export {
|
|
616
|
+
AgentsChatStateContainer as A,
|
|
617
|
+
ConversationWidgetProvider as C,
|
|
618
|
+
EMPTY_AGENTS_CHAT_OPENING_REQUEST as E,
|
|
619
|
+
INITIAL_AGENTS_CHAT_STATE as I,
|
|
620
|
+
ConversationMessageInputComposerWidgets as a,
|
|
621
|
+
ConversationErrorType as b,
|
|
622
|
+
createAgentsChatStore as c,
|
|
623
|
+
AgentsChatStoreProvider as d,
|
|
624
|
+
reduceAgentsChatState as e,
|
|
625
|
+
useAgentsChatState as f,
|
|
626
|
+
useAgentsChatStore as g,
|
|
627
|
+
useOptionalAgentsChatStore as h,
|
|
628
|
+
readConversationErrorTypeOfRefusedSend as r,
|
|
629
|
+
useAgentsChatSelector as u
|
|
630
|
+
};
|
|
631
|
+
//# sourceMappingURL=ConversationMessageInputComposerWidgets-BxyaFBA6.js.map
|