@copilotkit/channels-teams 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 (84) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +141 -0
  3. package/dist/adapter.d.ts +133 -0
  4. package/dist/adapter.d.ts.map +1 -0
  5. package/dist/adapter.js +539 -0
  6. package/dist/adapter.test.d.ts +2 -0
  7. package/dist/adapter.test.d.ts.map +1 -0
  8. package/dist/adapter.test.js +202 -0
  9. package/dist/conversation-store.d.ts +36 -0
  10. package/dist/conversation-store.d.ts.map +1 -0
  11. package/dist/conversation-store.js +78 -0
  12. package/dist/conversation-store.test.d.ts +2 -0
  13. package/dist/conversation-store.test.d.ts.map +1 -0
  14. package/dist/conversation-store.test.js +72 -0
  15. package/dist/download-files.d.ts +62 -0
  16. package/dist/download-files.d.ts.map +1 -0
  17. package/dist/download-files.js +190 -0
  18. package/dist/download-files.test.d.ts +2 -0
  19. package/dist/download-files.test.d.ts.map +1 -0
  20. package/dist/download-files.test.js +96 -0
  21. package/dist/event-renderer.d.ts +23 -0
  22. package/dist/event-renderer.d.ts.map +1 -0
  23. package/dist/event-renderer.js +135 -0
  24. package/dist/event-renderer.test.d.ts +2 -0
  25. package/dist/event-renderer.test.d.ts.map +1 -0
  26. package/dist/event-renderer.test.js +95 -0
  27. package/dist/graph-files.d.ts +50 -0
  28. package/dist/graph-files.d.ts.map +1 -0
  29. package/dist/graph-files.js +126 -0
  30. package/dist/graph-files.test.d.ts +2 -0
  31. package/dist/graph-files.test.d.ts.map +1 -0
  32. package/dist/graph-files.test.js +114 -0
  33. package/dist/index.d.ts +20 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +14 -0
  36. package/dist/interaction.d.ts +36 -0
  37. package/dist/interaction.d.ts.map +1 -0
  38. package/dist/interaction.js +35 -0
  39. package/dist/interaction.test.d.ts +2 -0
  40. package/dist/interaction.test.d.ts.map +1 -0
  41. package/dist/interaction.test.js +43 -0
  42. package/dist/listener.d.ts +26 -0
  43. package/dist/listener.d.ts.map +1 -0
  44. package/dist/listener.js +55 -0
  45. package/dist/listener.test.d.ts +2 -0
  46. package/dist/listener.test.d.ts.map +1 -0
  47. package/dist/listener.test.js +43 -0
  48. package/dist/message-stream.d.ts +52 -0
  49. package/dist/message-stream.d.ts.map +1 -0
  50. package/dist/message-stream.js +78 -0
  51. package/dist/message-stream.test.d.ts +2 -0
  52. package/dist/message-stream.test.d.ts.map +1 -0
  53. package/dist/message-stream.test.js +44 -0
  54. package/dist/render/adaptive-card.d.ts +43 -0
  55. package/dist/render/adaptive-card.d.ts.map +1 -0
  56. package/dist/render/adaptive-card.js +401 -0
  57. package/dist/render/adaptive-card.test.d.ts +2 -0
  58. package/dist/render/adaptive-card.test.d.ts.map +1 -0
  59. package/dist/render/adaptive-card.test.js +240 -0
  60. package/dist/render/auto-close.d.ts +27 -0
  61. package/dist/render/auto-close.d.ts.map +1 -0
  62. package/dist/render/auto-close.js +153 -0
  63. package/dist/render/auto-close.test.d.ts +2 -0
  64. package/dist/render/auto-close.test.d.ts.map +1 -0
  65. package/dist/render/auto-close.test.js +46 -0
  66. package/dist/render/budget.d.ts +38 -0
  67. package/dist/render/budget.d.ts.map +1 -0
  68. package/dist/render/budget.js +44 -0
  69. package/dist/render/budget.test.d.ts +2 -0
  70. package/dist/render/budget.test.d.ts.map +1 -0
  71. package/dist/render/budget.test.js +25 -0
  72. package/dist/render/markdown.d.ts +13 -0
  73. package/dist/render/markdown.d.ts.map +1 -0
  74. package/dist/render/markdown.js +121 -0
  75. package/dist/render/markdown.test.d.ts +2 -0
  76. package/dist/render/markdown.test.d.ts.map +1 -0
  77. package/dist/render/markdown.test.js +58 -0
  78. package/dist/sanitizing-http-agent.d.ts +35 -0
  79. package/dist/sanitizing-http-agent.d.ts.map +1 -0
  80. package/dist/sanitizing-http-agent.js +58 -0
  81. package/dist/types.d.ts +53 -0
  82. package/dist/types.d.ts.map +1 -0
  83. package/dist/types.js +1 -0
  84. package/package.json +67 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) Atai Barkai
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,141 @@
1
+ # @copilotkit/channels-teams
2
+
3
+ The **Microsoft Teams platform adapter** for [`@copilotkit/channels`](../channels). It's a
4
+ concrete `PlatformAdapter` that plugs Teams into the platform-agnostic bot
5
+ engine, exactly like [`@copilotkit/channels-slack`](../channels-slack) does for Slack. You
6
+ write your bot once with `createBot` (handlers, JSX, tools, context) and run it
7
+ on Teams by adding this adapter.
8
+
9
+ It is built on the **Microsoft 365 Agents SDK** (`@microsoft/agents-hosting`),
10
+ the successor to the Bot Framework SDK.
11
+
12
+ ## Install
13
+
14
+ ```sh
15
+ pnpm add @copilotkit/channels @copilotkit/channels-ui @copilotkit/channels-teams
16
+ ```
17
+
18
+ ## Quickstart
19
+
20
+ ```ts
21
+ import { createBot } from "@copilotkit/channels";
22
+ import { teams } from "@copilotkit/channels-teams";
23
+
24
+ const bot = createBot({
25
+ adapters: [teams({ port: 3978 })],
26
+ });
27
+
28
+ bot.onMessage(({ thread, message }) => thread.post(`Echo: ${message.text}`));
29
+
30
+ await bot.start(); // POST /api/messages now listening on :3978
31
+ ```
32
+
33
+ Then point the **Microsoft 365 Agents Playground** at it. No Microsoft
34
+ credentials are required for local development:
35
+
36
+ ```sh
37
+ npx @microsoft/m365agentsplayground # opens http://localhost:56150
38
+ ```
39
+
40
+ The Playground connects to `http://127.0.0.1:3978/api/messages` and gives you a
41
+ Teams-like chat UI to test against. See [`examples/teams`](../../examples/teams)
42
+ for a complete, runnable echo bot, and the
43
+ [Microsoft Teams guide](../../showcase/shell-docs/src/content/docs/frontends/teams.mdx)
44
+ for sideloading into real Teams via Azure Bot Service.
45
+
46
+ ## How it maps onto the `PlatformAdapter` contract
47
+
48
+ - **Ingress:** a `CloudAdapter` receives Teams activities at
49
+ `POST /api/messages` (stood up by an Express server). Each `message` activity
50
+ is normalized into `sink.onTurn(...)`. Uploaded files ride along as
51
+ attachments: `buildFileContentParts` downloads them (a `file.download.info`
52
+ URL, or a `data:`/https media URL) and hands the agent multimodal content
53
+ parts — CSV/JSON/text as decoded text, images and PDFs as binary. That's what
54
+ makes "upload a CSV → get a chart" work. Note Teams only delivers uploaded
55
+ files to a bot in **1:1 (personal) chat** (requires `supportsFiles: true` in
56
+ the app manifest); in a channel or group chat Teams does NOT send the file to
57
+ the bot at all, so chart-from-data there means pasting the data inline.
58
+ - **Egress:** structured/interactive UI is rendered to an **Adaptive Card**
59
+ (1.5) and sent as an attachment; a reply that collapses to plain text is sent
60
+ as a normal text activity (a bare `Echo: hi` shouldn't be a card). Both go out
61
+ on the live `TurnContext` _within the originating turn_. The engine awaits the
62
+ whole turn handler, so a reply (or a full `runAgent()` loop) completes before
63
+ the HTTP response closes. (Out-of-turn / proactive sends fall back to
64
+ `CloudAdapter.continueConversation` via the captured conversation reference.)
65
+ - **Files out:** `postFile` posts a file to the conversation. An image (e.g. a
66
+ rendered chart PNG) is sent as an inline attachment via a `data:` URI, so it
67
+ renders directly in the thread — the bot-slack `postFile` parallel.
68
+ - **Streaming:** text replies stream **by message edit** (Teams' baseline
69
+ model). It posts the first content, then `updateActivity` edits the same
70
+ message as the buffer grows (throttled and serialised; see
71
+ `TeamsMessageStream`), after a typing indicator. Native token streaming is a
72
+ later enhancement.
73
+ - **Agent runs:** `createRunRenderer` bridges AG-UI events to Teams. Each text
74
+ message is streamed by edit, and tool calls plus interrupts are captured for
75
+ the run loop.
76
+ - **History:** Teams does not hand the bot a queryable transcript, so an
77
+ in-memory `TeamsConversationStore` keeps one per conversation and seeds each
78
+ agent run with it. Swap in a durable `ConversationStore` for production.
79
+
80
+ ## Options
81
+
82
+ ```ts
83
+ teams({
84
+ port: 3978, // POST /api/messages port (Playground default)
85
+ clientId, // Microsoft app id; omit for anonymous local dev
86
+ clientSecret, // omit for anonymous local dev
87
+ tenantId, // omit for multi-tenant / anonymous
88
+ interruptEventNames, // custom-event names treated as agent interrupts
89
+ });
90
+ ```
91
+
92
+ Credentials also resolve from the `clientId` / `clientSecret` / `tenantId`
93
+ environment variables (the names the M365 Agents SDK reads).
94
+
95
+ ## Status & roadmap
96
+
97
+ Implemented: message ingress; **Adaptive Card rendering** of the bot-ui
98
+ vocabulary (`<Header>`, `<Section>`/`<Markdown>`, `<Fields>`, `<Table>`,
99
+ `<Image>`, `<Actions>`/`<Button>`, `<Select>`, `<Input>`, `<Context>`) with a
100
+ plain-text path for bare replies and a Markdown table fallback; **streamed-by-
101
+ edit** text replies with a typing indicator; `runAgent` tool-call / interrupt
102
+ capture; **card-action round-trip + HITL** (below); conversation history;
103
+ `update` / `delete`. Verified in the M365 Agents Playground.
104
+
105
+ **Card-action round-trip + HITL.** Adaptive Card `Action.Submit` clicks arrive
106
+ as Message activities carrying the action `data` in `activity.value`;
107
+ `decodeInteraction` parses our opaque `ckActionId` + button value and routes them
108
+ to `sink.onInteraction`, which resolves the engine's `awaitChoice` waiter and
109
+ runs the button's `onClick` (e.g. to edit the picker in place). A tool handler
110
+ that calls `await thread.awaitChoice(<Card/>)` therefore gates the agent on a
111
+ human decision; see `examples/teams` for an approve/reject demo. Ingress and
112
+ interaction decoding derive the conversation key from one shared helper
113
+ (`conversationKeyOf`) so the waiter always resolves.
114
+
115
+ **Async turn handoff.** When credentialed, ingress acks the inbound turn
116
+ immediately and runs the agent on a detached `continueConversation` context, so
117
+ an `awaitChoice` suspend can outlive the Teams turn window (approval minutes
118
+ later). In the anonymous local Playground (where `continueConversation` has no
119
+ app id) the run uses the inbound turn context, which localhost holds open across
120
+ the suspend. Waiters are in-memory (v1), so they don't survive a process restart.
121
+
122
+ Planned follow-ups (the architecture leaves room for each):
123
+
124
+ - **Native token streaming:** token-by-token replies via the SDK's
125
+ `StreamingResponse` (`queueInformativeUpdate` / `queueTextChunk` / `endStream`),
126
+ vs. the current post-then-edit model.
127
+ - **Durable HITL waiters:** persist pending `awaitChoice` state so approvals
128
+ survive a restart (today they're in-memory).
129
+ - **User lookup** (Microsoft Graph) and **arbitrary non-image file upload** via
130
+ the Teams/Graph file-consent flow (today `postFile` handles inline images).
131
+
132
+ ## Exports
133
+
134
+ `teams`, `TeamsAdapter`, `TeamsAdapterOptions`, `TeamsReplyTarget`,
135
+ `ConversationKey`; `TeamsConversationStore`; `createRunRenderer`;
136
+ `conversationKeyOf` / `parseCardAction`; `renderTeamsMarkdown`;
137
+ `renderAdaptiveCard` / `AdaptiveCard` / `isPlainText` /
138
+ `ADAPTIVE_CARD_CONTENT_TYPE`; `TEAMS_LIMITS`; `TeamsMessageStream`;
139
+ `createTeamsServer` / `TeamsServer` / `TeamsServerConfig`;
140
+ `SanitizingHttpAgent`; `buildFileContentParts` / `TeamsAttachmentRef` /
141
+ `FileDeliveryConfig`.
@@ -0,0 +1,133 @@
1
+ import type { PlatformAdapter, SurfaceCapabilities, IngressSink, InteractionEvent, RunRenderer, ReplyTarget, ConversationStore, MessageRef, PlatformUser, UserQuery } from "@copilotkit/channels";
2
+ import type { BotNode, ThreadMessage } from "@copilotkit/channels-ui";
3
+ import type { AdaptiveCard } from "./render/adaptive-card.js";
4
+ import type { TeamsAdapterOptions } from "./types.js";
5
+ /** Native render output: a plain text activity or an Adaptive Card attachment. */
6
+ type TeamsActivityPayload = {
7
+ text: string;
8
+ } | {
9
+ card: AdaptiveCard;
10
+ };
11
+ /**
12
+ * Microsoft Teams `PlatformAdapter`.
13
+ *
14
+ * Ingress: a `CloudAdapter` receives Teams activities at `POST /api/messages`
15
+ * (M365 Agents SDK). The inbound HTTP turn is **acked immediately**; the agent
16
+ * run is handed off to a detached `continueConversation` so it can outlive the
17
+ * turn. This is required for HITL, where `awaitChoice` suspends the run until a user
18
+ * clicks an Adaptive Card button (possibly minutes later). That detached
19
+ * `continueConversation` provides a stable `TurnContext` the whole run streams
20
+ * on, exactly as the Slack adapter runs in the background off a web client.
21
+ *
22
+ * Adaptive Card `Action.Submit` clicks arrive as Message activities carrying
23
+ * the action `data` in `activity.value`; those are decoded and routed to
24
+ * `sink.onInteraction` to resolve the waiter. This path needs no Microsoft
25
+ * credentials in the local M365 Agents Playground.
26
+ */
27
+ export declare class TeamsAdapter implements PlatformAdapter {
28
+ private readonly opts;
29
+ readonly platform = "teams";
30
+ readonly capabilities: SurfaceCapabilities;
31
+ readonly ackDeadlineMs = 15000;
32
+ private readonly store;
33
+ private cloud;
34
+ private server;
35
+ private sink;
36
+ constructor(opts?: TeamsAdapterOptions);
37
+ start(sink: IngressSink): Promise<void>;
38
+ stop(): Promise<void>;
39
+ /**
40
+ * Normalize an inbound activity, ack the HTTP turn immediately, and drive the
41
+ * work into the engine on a **detached** `continueConversation` so it can
42
+ * outlive this turn (HITL suspends the run until a later click).
43
+ */
44
+ private handleActivity;
45
+ /**
46
+ * Resolve a message's uploaded files into AG-UI content parts. Personal chats
47
+ * deliver the file inline (the Teams bot file API), which `buildFileContentParts`
48
+ * handles; a channel doesn't include the file at all, so we fetch it through
49
+ * Microsoft Graph when credentials are configured (group chats aren't wired
50
+ * up yet). Failures are logged, never thrown.
51
+ */
52
+ private collectInboundFileParts;
53
+ /** App-only Graph credentials, when all three are configured. */
54
+ private graphCredentials;
55
+ /** Pull the team/channel/message ids Graph needs out of a channel activity. */
56
+ private channelMessageRef;
57
+ /**
58
+ * Concise operational log for the inbound-file pipeline: how many parts we
59
+ * built and any skip reasons. Deliberately content-free — it never logs file
60
+ * bytes, decoded text, or SharePoint URLs.
61
+ */
62
+ private logFileParts;
63
+ /** Whether we can send proactively (out-of-turn). Requires a Microsoft app id. */
64
+ private canGoProactive;
65
+ /**
66
+ * Run `fn` against a proactive `TurnContext` opened by `continueConversation`,
67
+ * detached from any inbound HTTP turn. Fire-and-forget: the caller acks the
68
+ * inbound turn immediately and this runs (and may suspend at `awaitChoice`)
69
+ * in the background. Errors are logged, never surfaced to the inbound turn.
70
+ */
71
+ private runDetached;
72
+ /** Open a proactive `TurnContext` for the conversation and await `fn`. */
73
+ private withProactive;
74
+ /**
75
+ * Render IR to a native payload: plain text when it collapses to text,
76
+ * otherwise an Adaptive Card. (A bare `Echo: hi` is a text bubble; structured
77
+ * or interactive UI becomes a card.)
78
+ */
79
+ render(ir: BotNode[]): TeamsActivityPayload;
80
+ post(target: ReplyTarget, ir: BotNode[]): Promise<MessageRef>;
81
+ update(ref: MessageRef, ir: BotNode[]): Promise<void>;
82
+ /**
83
+ * Stream a text reply by message edit: post the first content, then
84
+ * `updateActivity` the same message as the buffer grows (throttled). This is
85
+ * Teams' baseline streaming model: no native token streaming.
86
+ */
87
+ stream(target: ReplyTarget, chunks: AsyncIterable<string>): Promise<MessageRef>;
88
+ delete(ref: MessageRef): Promise<void>;
89
+ /**
90
+ * Post a file to the conversation. Teams renders an image inline when it's
91
+ * sent as an attachment whose `contentUrl` is a `data:` URI, so we base64 the
92
+ * bytes into one — exactly what `render_chart`/`render_diagram` need to drop a
93
+ * PNG into the thread (the bot-slack `postFile` parallel). Non-image bytes are
94
+ * still attached with their inferred MIME; whether Teams previews them is up
95
+ * to the client. Sends on the live turn context, or proactively by reference.
96
+ */
97
+ postFile(target: ReplyTarget, { bytes, filename, altText, }: {
98
+ bytes: Uint8Array;
99
+ filename: string;
100
+ title?: string;
101
+ altText?: string;
102
+ }): Promise<{
103
+ ok: boolean;
104
+ fileId?: string;
105
+ error?: string;
106
+ }>;
107
+ createRunRenderer(target: ReplyTarget): RunRenderer;
108
+ decodeInteraction(raw: unknown): InteractionEvent | undefined;
109
+ lookupUser(_q: UserQuery): Promise<PlatformUser | undefined>;
110
+ get conversationStore(): ConversationStore;
111
+ /** Return the conversation transcript the adapter has accumulated. */
112
+ getMessages(target: ReplyTarget): Promise<ThreadMessage[]>;
113
+ /** Send plain Markdown text, preferring the live turn context. */
114
+ private sendText;
115
+ /** Send an Adaptive Card as a message attachment on the live turn. */
116
+ private sendCard;
117
+ /** Edit a previously-posted text activity in place (streamed-by-edit). */
118
+ private updateText;
119
+ /** Fire a typing indicator (shown while the agent works). */
120
+ private sendTyping;
121
+ /**
122
+ * Send a typing indicator now and keep re-sending it every few seconds until
123
+ * the returned stop fn is called. Teams' typing indicator lapses after a few
124
+ * seconds, so a single ping can't cover slow work (a Graph download, a chart
125
+ * render) where nothing posts in between. Returns a stop fn; call it in a
126
+ * `finally` so the timer is always cleared.
127
+ */
128
+ private startTypingHeartbeat;
129
+ }
130
+ /** Construct a Microsoft Teams `PlatformAdapter`. */
131
+ export declare function teams(opts?: TeamsAdapterOptions): TeamsAdapter;
132
+ export {};
133
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,SAAS,EACV,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EACV,OAAO,EACP,aAAa,EAEd,MAAM,yBAAyB,CAAC;AAajC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAE9D,OAAO,KAAK,EAAE,mBAAmB,EAAoB,MAAM,YAAY,CAAC;AAExE,kFAAkF;AAClF,KAAK,oBAAoB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC;AActE;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,YAAa,YAAW,eAAe;IAYtC,OAAO,CAAC,QAAQ,CAAC,IAAI;IAXjC,QAAQ,CAAC,QAAQ,WAAW;IAC5B,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAG3C,QAAQ,CAAC,aAAa,SAAS;IAE/B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;IACtD,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,IAAI,CAA0B;gBAET,IAAI,GAAE,mBAAwB;IAWrD,KAAK,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAyBvC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B;;;;OAIG;YACW,cAAc;IA0I5B;;;;;;OAMG;YACW,uBAAuB;IAgCrC,iEAAiE;IACjE,OAAO,CAAC,gBAAgB;IAUxB,+EAA+E;IAC/E,OAAO,CAAC,iBAAiB;IAgBzB;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAWpB,kFAAkF;IAClF,OAAO,CAAC,cAAc;IAItB;;;;;OAKG;IACH,OAAO,CAAC,WAAW;IASnB,0EAA0E;YAC5D,aAAa;IAa3B;;;;OAIG;IACH,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,oBAAoB;IAMrC,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAU7D,MAAM,CAAC,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAwB3D;;;;OAIG;IACG,MAAM,CACV,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,GAC5B,OAAO,CAAC,UAAU,CAAC;IAgBhB,MAAM,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAM5C;;;;;;;OAOG;IACG,QAAQ,CACZ,MAAM,EAAE,WAAW,EACnB,EACE,KAAK,EACL,QAAQ,EACR,OAAO,GACR,EAAE;QACD,KAAK,EAAE,UAAU,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,GACA,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAiC5D,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW;IAYnD,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,GAAG,SAAS;IAqBvD,UAAU,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC;IAKlE,IAAI,iBAAiB,IAAI,iBAAiB,CAEzC;IAED,sEAAsE;IAChE,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAKhE,kEAAkE;YACpD,QAAQ;IAwBtB,sEAAsE;YACxD,QAAQ;IAyBtB,0EAA0E;YAC5D,UAAU;IAWxB,6DAA6D;YAC/C,UAAU;IASxB;;;;;;OAMG;IACH,OAAO,CAAC,oBAAoB;CAK7B;AAED,qDAAqD;AACrD,wBAAgB,KAAK,CAAC,IAAI,GAAE,mBAAwB,GAAG,YAAY,CAElE"}