@darqlabs/curator-sdk-react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +205 -0
  3. package/dist/cjs/CuratorAdapter.d.ts +28 -0
  4. package/dist/cjs/CuratorAdapter.d.ts.map +1 -0
  5. package/dist/cjs/CuratorAdapter.js +100 -0
  6. package/dist/cjs/CuratorAdapter.js.map +1 -0
  7. package/dist/cjs/CuratorChat.d.ts +70 -0
  8. package/dist/cjs/CuratorChat.d.ts.map +1 -0
  9. package/dist/cjs/CuratorChat.js +454 -0
  10. package/dist/cjs/CuratorChat.js.map +1 -0
  11. package/dist/cjs/CuratorChatLauncher.d.ts +57 -0
  12. package/dist/cjs/CuratorChatLauncher.d.ts.map +1 -0
  13. package/dist/cjs/CuratorChatLauncher.js +134 -0
  14. package/dist/cjs/CuratorChatLauncher.js.map +1 -0
  15. package/dist/cjs/CuratorProvider.d.ts +37 -0
  16. package/dist/cjs/CuratorProvider.d.ts.map +1 -0
  17. package/dist/cjs/CuratorProvider.js +49 -0
  18. package/dist/cjs/CuratorProvider.js.map +1 -0
  19. package/dist/cjs/Markdown.d.ts +16 -0
  20. package/dist/cjs/Markdown.d.ts.map +1 -0
  21. package/dist/cjs/Markdown.js +18 -0
  22. package/dist/cjs/Markdown.js.map +1 -0
  23. package/dist/cjs/brand.d.ts +26 -0
  24. package/dist/cjs/brand.d.ts.map +1 -0
  25. package/dist/cjs/brand.js +47 -0
  26. package/dist/cjs/brand.js.map +1 -0
  27. package/dist/cjs/index.d.ts +10 -0
  28. package/dist/cjs/index.d.ts.map +1 -0
  29. package/dist/cjs/index.js +17 -0
  30. package/dist/cjs/index.js.map +1 -0
  31. package/dist/cjs/normalizeMarkdown.d.ts +24 -0
  32. package/dist/cjs/normalizeMarkdown.d.ts.map +1 -0
  33. package/dist/cjs/normalizeMarkdown.js +111 -0
  34. package/dist/cjs/normalizeMarkdown.js.map +1 -0
  35. package/dist/cjs/useCuratorChat.d.ts +79 -0
  36. package/dist/cjs/useCuratorChat.d.ts.map +1 -0
  37. package/dist/cjs/useCuratorChat.js +135 -0
  38. package/dist/cjs/useCuratorChat.js.map +1 -0
  39. package/dist/esm/CuratorAdapter.d.ts +28 -0
  40. package/dist/esm/CuratorAdapter.d.ts.map +1 -0
  41. package/dist/esm/CuratorAdapter.js +97 -0
  42. package/dist/esm/CuratorAdapter.js.map +1 -0
  43. package/dist/esm/CuratorChat.d.ts +70 -0
  44. package/dist/esm/CuratorChat.d.ts.map +1 -0
  45. package/dist/esm/CuratorChat.js +451 -0
  46. package/dist/esm/CuratorChat.js.map +1 -0
  47. package/dist/esm/CuratorChatLauncher.d.ts +57 -0
  48. package/dist/esm/CuratorChatLauncher.d.ts.map +1 -0
  49. package/dist/esm/CuratorChatLauncher.js +131 -0
  50. package/dist/esm/CuratorChatLauncher.js.map +1 -0
  51. package/dist/esm/CuratorProvider.d.ts +37 -0
  52. package/dist/esm/CuratorProvider.d.ts.map +1 -0
  53. package/dist/esm/CuratorProvider.js +44 -0
  54. package/dist/esm/CuratorProvider.js.map +1 -0
  55. package/dist/esm/Markdown.d.ts +16 -0
  56. package/dist/esm/Markdown.d.ts.map +1 -0
  57. package/dist/esm/Markdown.js +12 -0
  58. package/dist/esm/Markdown.js.map +1 -0
  59. package/dist/esm/brand.d.ts +26 -0
  60. package/dist/esm/brand.d.ts.map +1 -0
  61. package/dist/esm/brand.js +43 -0
  62. package/dist/esm/brand.js.map +1 -0
  63. package/dist/esm/index.d.ts +10 -0
  64. package/dist/esm/index.d.ts.map +1 -0
  65. package/dist/esm/index.js +6 -0
  66. package/dist/esm/index.js.map +1 -0
  67. package/dist/esm/normalizeMarkdown.d.ts +24 -0
  68. package/dist/esm/normalizeMarkdown.d.ts.map +1 -0
  69. package/dist/esm/normalizeMarkdown.js +108 -0
  70. package/dist/esm/normalizeMarkdown.js.map +1 -0
  71. package/dist/esm/package.json +3 -0
  72. package/dist/esm/useCuratorChat.d.ts +79 -0
  73. package/dist/esm/useCuratorChat.d.ts.map +1 -0
  74. package/dist/esm/useCuratorChat.js +132 -0
  75. package/dist/esm/useCuratorChat.js.map +1 -0
  76. package/package.json +66 -0
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ /**
3
+ * Headless chat hook for the Curator SDK.
4
+ *
5
+ * Manages a single conversation against a deployed agent. Owns the
6
+ * `Chat` instance from the SDK, exposes the rolling message list, a
7
+ * `send()` action, and the various pending/error states the UI needs.
8
+ *
9
+ * Bring your own UI on top of this hook, or use `<CuratorChat />` for
10
+ * the drop-in styled widget that consumes this hook internally.
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.useCuratorChat = useCuratorChat;
14
+ const react_1 = require("react");
15
+ const curator_sdk_1 = require("@darqlabs/curator-sdk");
16
+ const CuratorProvider_js_1 = require("./CuratorProvider.js");
17
+ let counter = 0;
18
+ function localId() {
19
+ counter += 1;
20
+ return `local_${Date.now().toString(36)}_${counter}`;
21
+ }
22
+ function useCuratorChat(opts) {
23
+ const { agent, project, environment, system, conversationId, onMessage, onError } = opts;
24
+ // Resolve the client: explicit prop wins, then context, then fail loud.
25
+ const contextClient = (0, CuratorProvider_js_1.useCuratorOrNull)();
26
+ const curator = opts.curator ?? contextClient;
27
+ if (!curator) {
28
+ throw new Error("useCuratorChat() requires a Curator client. Either pass `curator` explicitly " +
29
+ "or wrap your app in <CuratorProvider client={curator}>.");
30
+ }
31
+ // Construct the Chat on first render and whenever any addressing input
32
+ // changes. Re-creating on slug/project/env changes prevents accidentally
33
+ // sending to a stale agent if the consumer swaps props.
34
+ const chat = (0, react_1.useMemo)(() => {
35
+ const agentHandle = curator.agent(agent, { project, environment, system });
36
+ return conversationId ? agentHandle.conversation(conversationId) : agentHandle.chat();
37
+ // eslint-disable-next-line react-hooks/exhaustive-deps
38
+ }, [curator, agent, project, environment, system, conversationId]);
39
+ const [messages, setMessages] = (0, react_1.useState)([]);
40
+ const [sending, setSending] = (0, react_1.useState)(false);
41
+ const [error, setError] = (0, react_1.useState)(null);
42
+ const [conversationIdState, setConversationIdState] = (0, react_1.useState)(conversationId ?? null);
43
+ // Whenever the chat handle changes (consumer swapped props or called
44
+ // reset), wipe local message state to avoid mixing transcripts.
45
+ const lastChatRef = (0, react_1.useRef)(null);
46
+ (0, react_1.useEffect)(() => {
47
+ if (lastChatRef.current !== chat) {
48
+ lastChatRef.current = chat;
49
+ setMessages([]);
50
+ setError(null);
51
+ setConversationIdState(chat.id);
52
+ }
53
+ }, [chat]);
54
+ const send = (0, react_1.useCallback)(async (content, args = {}) => {
55
+ const trimmed = content.trim();
56
+ if (!trimmed && !args.files?.length)
57
+ return;
58
+ const userBubble = { kind: "user", content: trimmed, localId: localId() };
59
+ setMessages((prev) => [...prev, userBubble]);
60
+ setSending(true);
61
+ setError(null);
62
+ try {
63
+ const reply = await chat.send(trimmed, args);
64
+ setConversationIdState(reply.conversationId);
65
+ setMessages((prev) => [
66
+ ...prev,
67
+ {
68
+ kind: "assistant",
69
+ content: reply.content,
70
+ sequence: reply.sequence,
71
+ stepId: reply.stepId,
72
+ createdAt: reply.createdAt,
73
+ runId: reply.runId,
74
+ },
75
+ ]);
76
+ onMessage?.(reply);
77
+ }
78
+ catch (err) {
79
+ const message = renderError(err);
80
+ setError(err);
81
+ setMessages((prev) => [...prev, { kind: "error", message, localId: localId() }]);
82
+ onError?.(err);
83
+ }
84
+ finally {
85
+ setSending(false);
86
+ }
87
+ }, [chat, onMessage, onError]);
88
+ const reset = (0, react_1.useCallback)(() => {
89
+ // Force the memo to refresh by zeroing the ref; the consumer-controlled
90
+ // inputs determine the next Chat. For the no-prop-change case, we
91
+ // instead just clear local state — the existing Chat is still valid.
92
+ setMessages([]);
93
+ setError(null);
94
+ setConversationIdState(chat.id);
95
+ }, [chat]);
96
+ return {
97
+ messages,
98
+ send,
99
+ sending,
100
+ error,
101
+ chat,
102
+ conversationId: conversationIdState,
103
+ reset,
104
+ };
105
+ }
106
+ function renderError(err) {
107
+ if (err instanceof curator_sdk_1.CuratorApprovalRequiredError) {
108
+ return `That action needs administrator approval. Please contact your administrator to review the request for "${err.approval.tool_name}".`;
109
+ }
110
+ if (err instanceof curator_sdk_1.CuratorAgentError) {
111
+ return err.message || `Agent error (${err.failureClass}).`;
112
+ }
113
+ if (err instanceof curator_sdk_1.CuratorTimeoutError) {
114
+ return "The agent is taking longer than expected. It may still complete in the background.";
115
+ }
116
+ if (err instanceof curator_sdk_1.CuratorAuthError) {
117
+ return "Authentication failed. Check your API key.";
118
+ }
119
+ if (err instanceof curator_sdk_1.CuratorForbiddenError) {
120
+ return err.message || "Permission denied.";
121
+ }
122
+ if (err instanceof curator_sdk_1.CuratorNotFoundError) {
123
+ return err.message || "Deployment or conversation not found.";
124
+ }
125
+ if (err instanceof curator_sdk_1.CuratorDeploymentRetiredError) {
126
+ return "This deployment has been retired by the operator.";
127
+ }
128
+ if (err instanceof curator_sdk_1.CuratorRateLimitError) {
129
+ return "Rate limit reached. Please wait a moment and try again.";
130
+ }
131
+ if (err instanceof Error)
132
+ return err.message;
133
+ return "Something went wrong.";
134
+ }
135
+ //# sourceMappingURL=useCuratorChat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCuratorChat.js","sourceRoot":"","sources":["../../src/useCuratorChat.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Adapter that plugs the Curator SDK into assistant-ui's `useLocalRuntime`.
3
+ *
4
+ * Each invocation of `run()` is one user-turn. We pull the latest user
5
+ * message text out of assistant-ui's structured `messages[]`, hand it to
6
+ * `chat.stream(...)`, and yield assistant-ui-shaped updates back as the
7
+ * SDK's stream events flow in.
8
+ *
9
+ * stream.delta → accumulate text, yield partial assistant content
10
+ * stream.done → yield final content + status: complete
11
+ * stream.error → yield friendly text + status: incomplete
12
+ * stream.paused_for_ → yield "contact your administrator" text +
13
+ * approval status: incomplete
14
+ *
15
+ * The Chat handle is constructed once per chat session (one per
16
+ * mounted CuratorChat / launcher panel) so multi-turn context stays
17
+ * intact across runs.
18
+ */
19
+ import type { ChatModelAdapter } from "@assistant-ui/react";
20
+ import type { AssistantMessage, Chat, CuratorError } from "@darqlabs/curator-sdk";
21
+ export interface CuratorAdapterCallbacks {
22
+ /** Fired once per successfully-returned assistant message. */
23
+ onMessage?: (message: AssistantMessage) => void;
24
+ /** Fired on any send-time error surfaced through the stream. */
25
+ onError?: (error: CuratorError | Error) => void;
26
+ }
27
+ export declare function createCuratorAdapter(chat: Chat, callbacks?: CuratorAdapterCallbacks): ChatModelAdapter;
28
+ //# sourceMappingURL=CuratorAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CuratorAdapter.d.ts","sourceRoot":"","sources":["../../src/CuratorAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAsB,MAAM,qBAAqB,CAAA;AAC/E,OAAO,KAAK,EACV,gBAAgB,EAChB,IAAI,EACJ,YAAY,EACb,MAAM,uBAAuB,CAAA;AAE9B,MAAM,WAAW,uBAAuB;IACtC,8DAA8D;IAC9D,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,CAAA;IAC/C,gEAAgE;IAChE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,GAAG,KAAK,KAAK,IAAI,CAAA;CAChD;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,IAAI,EACV,SAAS,GAAE,uBAA4B,GACtC,gBAAgB,CA6DlB"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Adapter that plugs the Curator SDK into assistant-ui's `useLocalRuntime`.
3
+ *
4
+ * Each invocation of `run()` is one user-turn. We pull the latest user
5
+ * message text out of assistant-ui's structured `messages[]`, hand it to
6
+ * `chat.stream(...)`, and yield assistant-ui-shaped updates back as the
7
+ * SDK's stream events flow in.
8
+ *
9
+ * stream.delta → accumulate text, yield partial assistant content
10
+ * stream.done → yield final content + status: complete
11
+ * stream.error → yield friendly text + status: incomplete
12
+ * stream.paused_for_ → yield "contact your administrator" text +
13
+ * approval status: incomplete
14
+ *
15
+ * The Chat handle is constructed once per chat session (one per
16
+ * mounted CuratorChat / launcher panel) so multi-turn context stays
17
+ * intact across runs.
18
+ */
19
+ export function createCuratorAdapter(chat, callbacks = {}) {
20
+ return {
21
+ async *run({ messages, abortSignal }) {
22
+ const userText = extractLatestUserText(messages);
23
+ if (!userText)
24
+ return;
25
+ let acc = "";
26
+ try {
27
+ for await (const event of chat.stream(userText)) {
28
+ if (abortSignal.aborted)
29
+ return;
30
+ if (event.type === "delta") {
31
+ acc += event.text;
32
+ yield { content: [{ type: "text", text: acc }] };
33
+ continue;
34
+ }
35
+ if (event.type === "done") {
36
+ const finalText = event.message?.content ?? acc;
37
+ yield {
38
+ content: [{ type: "text", text: finalText }],
39
+ status: { type: "complete", reason: "stop" },
40
+ };
41
+ if (event.message)
42
+ callbacks.onMessage?.(event.message);
43
+ return;
44
+ }
45
+ if (event.type === "error") {
46
+ yield {
47
+ content: [{ type: "text", text: event.message }],
48
+ status: { type: "incomplete", reason: "error" },
49
+ };
50
+ callbacks.onError?.(new Error(event.message));
51
+ return;
52
+ }
53
+ if (event.type === "paused_for_approval") {
54
+ const pausedMessage = `This action needs administrator approval. ` +
55
+ `Contact your administrator to review the request for "${event.approval.tool_name}".`;
56
+ yield {
57
+ content: [{ type: "text", text: pausedMessage }],
58
+ status: { type: "incomplete", reason: "error" },
59
+ };
60
+ callbacks.onError?.(new Error(pausedMessage));
61
+ return;
62
+ }
63
+ // tool_call.* and any future event types are silently dropped
64
+ // until a richer UI surface ships for them.
65
+ }
66
+ }
67
+ catch (err) {
68
+ const message = err?.message || "Something went wrong sending your message.";
69
+ yield {
70
+ content: [{ type: "text", text: message }],
71
+ status: { type: "incomplete", reason: "error" },
72
+ };
73
+ callbacks.onError?.(err);
74
+ }
75
+ },
76
+ };
77
+ }
78
+ /**
79
+ * Pull the latest user-turn text out of assistant-ui's structured
80
+ * message array. Text parts are concatenated with newlines; other
81
+ * part types (image, file, etc.) are ignored for now — the SDK's
82
+ * `chat.stream` accepts plain text content only.
83
+ */
84
+ function extractLatestUserText(messages) {
85
+ for (let i = messages.length - 1; i >= 0; i--) {
86
+ const m = messages[i];
87
+ if (m.role !== "user")
88
+ continue;
89
+ const text = m.content
90
+ .filter((p) => typeof p === "object" && p !== null && p.type === "text")
91
+ .map((p) => p.text)
92
+ .join("\n");
93
+ return text.trim();
94
+ }
95
+ return "";
96
+ }
97
+ //# sourceMappingURL=CuratorAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CuratorAdapter.js","sourceRoot":"","sources":["../../src/CuratorAdapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * <CuratorChat /> — drop-in chat widget backed by a Curator SDK client.
3
+ *
4
+ * <CuratorChat curator={curator} agent="support-bot" />
5
+ *
6
+ * Internals are powered by `@assistant-ui/react` — `useLocalRuntime`
7
+ * wraps our `CuratorAdapter`, which delegates each user turn to
8
+ * `chat.stream(...)` for token-by-token rendering. The outer chrome
9
+ * (header, brand footer, theme tokens, close button) and the bubble
10
+ * layout stay ours so the widget keeps its identity across themes.
11
+ */
12
+ import { type CSSProperties, type ReactNode } from "react";
13
+ import type { AssistantMessage, Curator, CuratorError, Environment } from "@darqlabs/curator-sdk";
14
+ export interface CuratorChatProps {
15
+ /** SDK instance. Optional when a `<CuratorProvider>` is mounted. */
16
+ curator?: Curator;
17
+ /** Deployment slug to chat with. */
18
+ agent: string;
19
+ /** Override the SDK's default project for this widget. */
20
+ project?: string;
21
+ /** Override the SDK's default environment for this widget. */
22
+ environment?: Environment;
23
+ /** Address a system-scoped deployment. */
24
+ system?: boolean;
25
+ /** Reattach to an existing conversation id instead of starting fresh. */
26
+ conversationId?: string;
27
+ /** Header title. Default: "Chat". */
28
+ title?: string;
29
+ /** Input placeholder. Default: "Type a message…". */
30
+ placeholder?: string;
31
+ /** Shown above the empty message list as a system prompt. */
32
+ welcomeMessage?: string;
33
+ /** Built-in palette. Default: "light". */
34
+ theme?: "light" | "dark";
35
+ /** Class applied to the outer wrapper. */
36
+ className?: string;
37
+ /** Inline styles merged onto the outer wrapper. */
38
+ style?: CSSProperties;
39
+ /** If set, the header shows an X button that calls this. */
40
+ onClose?: () => void;
41
+ /**
42
+ * Indicator rendered inside the assistant bubble while it's waiting
43
+ * for the first token (the gap between Send and the first delta).
44
+ * Default: animated three-dot pulse. Pass any node to swap it out.
45
+ */
46
+ loadingIndicator?: ReactNode;
47
+ /** Fired once per assistant message that completes successfully. */
48
+ onMessage?: (message: AssistantMessage) => void;
49
+ /** Fired on any terminal stream error or thrown exception. */
50
+ onError?: (error: CuratorError | Error) => void;
51
+ /**
52
+ * Show a retry (↻) button under the latest assistant message. Default:
53
+ * off. Retry re-sends the preceding user message through the SDK — note
54
+ * that this appends a fresh turn to the server-side conversation rather
55
+ * than regenerating the last reply in place, so persisted history will
56
+ * contain the duplicated user message. Fine for casual / demo widgets;
57
+ * enable only if that history shape is acceptable for your deployment.
58
+ */
59
+ enableRetry?: boolean;
60
+ /**
61
+ * Show a copy button on assistant messages that copies the message text
62
+ * to the clipboard. Default: off. Appears alongside retry (when enabled)
63
+ * in the per-message action bar; a check glyph confirms the copy briefly.
64
+ */
65
+ enableCopy?: boolean;
66
+ }
67
+ export declare function CuratorChat(props: CuratorChatProps): import("react").JSX.Element;
68
+ declare function AssistantMessage(): import("react").JSX.Element;
69
+ export {};
70
+ //# sourceMappingURL=CuratorChat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CuratorChat.d.ts","sourceRoot":"","sources":["../../src/CuratorChat.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAML,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AAUd,OAAO,KAAK,EACV,gBAAgB,EAEhB,OAAO,EACP,YAAY,EACZ,WAAW,EACZ,MAAM,uBAAuB,CAAA;AAM9B,MAAM,WAAW,gBAAgB;IAC/B,oEAAoE;IACpE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAA;IACb,0DAA0D;IAC1D,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAA;IAEvB,qCAAqC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,6DAA6D;IAC7D,cAAc,CAAC,EAAE,MAAM,CAAA;IAEvB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IACxB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mDAAmD;IACnD,KAAK,CAAC,EAAE,aAAa,CAAA;IAErB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IAEpB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,SAAS,CAAA;IAC5B,oEAAoE;IACpE,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,CAAA;IAC/C,8DAA8D;IAC9D,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,GAAG,KAAK,KAAK,IAAI,CAAA;IAE/C;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,+BAqGlD;AAoDD,iBAAS,gBAAgB,gCAqCxB"}