@nifrajs/ag-ui 3.2.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.
- package/README.md +135 -0
- package/dist/index.d.ts +125 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +637 -0
- package/dist/index.js.map +1 -0
- package/package.json +62 -0
- package/src/index.ts +817 -0
package/README.md
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# @nifrajs/ag-ui
|
|
2
|
+
|
|
3
|
+
Mount a nifra agent as an [AG-UI](https://docs.ag-ui.com) (Agent-User Interaction protocol) endpoint: one POST accepting `RunAgentInput`, a stream of AG-UI events out over SSE - run lifecycle, step and tool-call events projected from the runner's step evidence, text message events for the output, and a typed continuation for human-in-the-loop resume.
|
|
4
|
+
|
|
5
|
+
A protocol bridge over [`@nifrajs/agent`](../agent) - the request body reuses core's single bounded, prototype-guarded trust boundary, and the model, durable state store, and approval transport are injected per request through the same `ports` factory `mountAgent` uses. Dependency-free beyond the two nifra peers.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bun add @nifrajs/ag-ui @nifrajs/agent
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Mount
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { server } from "@nifrajs/core"
|
|
17
|
+
import { mountAgUI } from "@nifrajs/ag-ui"
|
|
18
|
+
import { agent } from "./agent" // an AgentDefinition
|
|
19
|
+
|
|
20
|
+
const app = server()
|
|
21
|
+
mountAgUI(app, {
|
|
22
|
+
agent,
|
|
23
|
+
ports: (c) => ({
|
|
24
|
+
model: myModelPort, // scope to the request subject
|
|
25
|
+
capabilities: ["search.read"],
|
|
26
|
+
state: myStateStore, // required for resume
|
|
27
|
+
}),
|
|
28
|
+
})
|
|
29
|
+
// POST /agui - RunAgentInput in, AG-UI events out (SSE)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Event mapping
|
|
33
|
+
|
|
34
|
+
| Runner | AG-UI events |
|
|
35
|
+
| --- | --- |
|
|
36
|
+
| run starts | `RUN_STARTED`, then `CUSTOM { name: "nifra.turn" }` announcing the turn id |
|
|
37
|
+
| tool evidence | `TOOL_CALL_START` / `TOOL_CALL_END`, then `TOOL_CALL_RESULT` whose `content` is the token-only outcome `{ "outcome": "committed" \| "failed" \| "denied", "code"? }` |
|
|
38
|
+
| model, approval, budget, state evidence | `STEP_STARTED` / `STEP_FINISHED` |
|
|
39
|
+
| model text deltas | live `TEXT_MESSAGE_START` / `_CONTENT` (see streaming below) |
|
|
40
|
+
| model reasoning deltas | `REASONING_START` / `REASONING_MESSAGE_START` / `_CONTENT` / `_END` / `REASONING_END` |
|
|
41
|
+
| model tool-args deltas | provisional `TOOL_CALL_START` + `TOOL_CALL_ARGS`, closed by the call's tool evidence |
|
|
42
|
+
| shared state | `STATE_SNAPSHOT` on the seed and `STATE_DELTA` (RFC 6902 ops) per patch (see below) |
|
|
43
|
+
| model usage deltas | summed per `(provider, model)` into the `usage: TokenUsage[]` array on `RUN_FINISHED` |
|
|
44
|
+
| completed output | `TEXT_MESSAGE_START` / `_CONTENT` / `_END` (unless text was streamed), an optional `MESSAGES_SNAPSHOT` (see below), then `RUN_FINISHED` with `result` and `outcome: { "type": "success" }` |
|
|
45
|
+
| completed with a typed error | `RUN_ERROR` |
|
|
46
|
+
| suspended | `CUSTOM { name: "nifra.pending" }` with the continuation, then `RUN_FINISHED` with `outcome: { "type": "interrupt", "interrupts": [...] }` |
|
|
47
|
+
|
|
48
|
+
Evidence-derived events carry the evidence `timestamp`. The runtime is token-only by design - `TOOL_CALL_RESULT` reports the outcome and error code, never the tool's payload.
|
|
49
|
+
|
|
50
|
+
Agent input is `forwardedProps.input` when present, otherwise the content of the last `role: "user"` message.
|
|
51
|
+
|
|
52
|
+
## Token streaming
|
|
53
|
+
|
|
54
|
+
A model port that calls the request's optional `onDelta` callback (see `@nifrajs/agent`'s `AgentModelDelta`) streams live:
|
|
55
|
+
|
|
56
|
+
- `{ kind: "text", text }` opens a `TEXT_MESSAGE` and streams each chunk as `TEXT_MESSAGE_CONTENT`. When any text was streamed, the terminal text block is suppressed - the streamed text IS the assistant message, so a streaming port must stream all user-visible text. A non-streaming port keeps the single terminal block; nothing changes for it.
|
|
57
|
+
- `{ kind: "reasoning", text }` streams a `REASONING_*` message.
|
|
58
|
+
- `{ kind: "tool-args", name?, argsText }` opens a provisional `TOOL_CALL_START` (id `<turnId>:call:<n>`) and streams `TOOL_CALL_ARGS`. The tool evidence that follows closes the same call - `TOOL_CALL_END` plus the token-only `TOOL_CALL_RESULT` - instead of opening a second one.
|
|
59
|
+
- `{ kind: "usage", provider?, model?, inputTokens?, ... }` never becomes a frame. The counts are summed per `(provider, model)` across the run's model decisions and stamped as the spec `usage: TokenUsage[]` array on the terminal `RUN_FINISHED` (success and interrupt alike); non-finite figures are ignored.
|
|
60
|
+
|
|
61
|
+
Each stream closes when a different delta kind starts, when tool evidence lands, or at the end of the run. Deltas are transient observer data: a `Last-Event-ID` replay carries evidence frames and the stored, unsuppressed terminal events only - the stored `RUN_FINISHED` keeps its `usage`.
|
|
62
|
+
|
|
63
|
+
## Shared state
|
|
64
|
+
|
|
65
|
+
The `ports` factory receives `(c, run)`; `run.sharedState` is the run's `AgentSharedState` channel and `run.turnId` the resolved turn id. `body.state` seeds the document and is announced with an upfront `STATE_SNAPSHOT`; every `patch` from a port or tool executor streams as `STATE_DELTA` carrying the RFC 6902 ops. A first patch on an unseeded document announces itself as a `STATE_SNAPSHOT` instead of a delta against a base the client never saw. The channel is per-run and transient - nothing in it is persisted.
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
mountAgUI(app, {
|
|
69
|
+
agent,
|
|
70
|
+
ports: (c, run) => ({
|
|
71
|
+
model: myStreamingModelPort(run.sharedState), // patch progress as the run advances
|
|
72
|
+
capabilities: ["search.read"],
|
|
73
|
+
}),
|
|
74
|
+
})
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
With `emitMessagesSnapshot: true`, a successful run also emits `MESSAGES_SNAPSHOT` - the request's `messages` echoed back with the assistant output message appended - before `RUN_FINISHED`. It is off by default: the snapshot echoes client message payloads, and terminal events persist to the evidence log when one is configured.
|
|
78
|
+
|
|
79
|
+
## Human-in-the-loop resume
|
|
80
|
+
|
|
81
|
+
A suspended run finishes with `outcome: { "type": "interrupt", "interrupts": [interrupt] }` where the interrupt is:
|
|
82
|
+
|
|
83
|
+
```jsonc
|
|
84
|
+
{
|
|
85
|
+
"id": "<turnId>",
|
|
86
|
+
"reason": "approval", // approval | budget | model | cancelled | max_turns
|
|
87
|
+
"toolCallId": "<effectId>", // present for tool suspensions
|
|
88
|
+
"responseSchema": { /* JSON Schema for the resume payload */ },
|
|
89
|
+
"metadata": { "turnId": "…", "continuation": { "kind": "approval", "tool": "…", "effectId": "…" } }
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Resume with the AG-UI `resume` array. The runtime keeps state token-only - it holds no interrupt registry - so the payload must echo `metadata.continuation`, with the suspended tool's input replayed in `continuation.input`:
|
|
94
|
+
|
|
95
|
+
```jsonc
|
|
96
|
+
{
|
|
97
|
+
"threadId": "thread-1", "runId": "run-2", "messages": [],
|
|
98
|
+
"forwardedProps": { "input": { "prompt": "go" } },
|
|
99
|
+
"resume": [{
|
|
100
|
+
"interruptId": "<interrupt id>",
|
|
101
|
+
"status": "resolved", // "cancelled" without an approval resumes as a denial
|
|
102
|
+
"payload": {
|
|
103
|
+
"continuation": { "kind": "approval", "tool": "search.read", "effectId": "…", "input": { "q": "…" } },
|
|
104
|
+
"approval": { "granted": true }
|
|
105
|
+
}
|
|
106
|
+
}]
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The pre-interrupt form - the same `{ continuation, approval? }` object in `forwardedProps.resume` plus `forwardedProps.turnId` - keeps working. A resume that fails validation is ignored and the POST starts a fresh run.
|
|
111
|
+
|
|
112
|
+
## Resumable streams
|
|
113
|
+
|
|
114
|
+
Pass an `evidenceLog` to make a dropped SSE connection resumable. Evidence-derived frames then
|
|
115
|
+
carry SSE `id: <seq>`; a client reconnects by re-POSTing the same body with a `Last-Event-ID`
|
|
116
|
+
header and receives the missed events, rejoining a still-running turn live or replaying the stored
|
|
117
|
+
terminal events - the run is never re-executed.
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
import { createMemoryAgentEvidenceLog } from "@nifrajs/agent/events"
|
|
121
|
+
|
|
122
|
+
mountAgUI(app, { agent, ports, evidenceLog: createMemoryAgentEvidenceLog() })
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
The in-memory log is the single-process dev/test reference; a durable, multi-process log is an
|
|
126
|
+
adapter implementing the same `AgentEvidenceLog` interface.
|
|
127
|
+
|
|
128
|
+
The seam performs no authentication or authorization - wrap it with your app's route guards and scope every port in `ports(c)` to the caller.
|
|
129
|
+
|
|
130
|
+
## Docs
|
|
131
|
+
|
|
132
|
+
Part of the **[nifra](https://nifra.dev)** full-stack TypeScript framework - one core, five UI libraries, every runtime. Scaffold a new app with `bun create nifra`.
|
|
133
|
+
|
|
134
|
+
For AI agents, see [`LLM.md`](./LLM.md) and the full corpus
|
|
135
|
+
[`../../llms-full.txt`](../../llms-full.txt).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@nifrajs/ag-ui` - mount a nifra agent as an AG-UI (Agent-User Interaction protocol) endpoint.
|
|
3
|
+
*
|
|
4
|
+
* The package is a protocol bridge over the `@nifrajs/agent` runner, mirroring the `mountAgent`
|
|
5
|
+
* seam: one HTTP POST accepting the AG-UI `RunAgentInput` body, the bounded runner in the middle,
|
|
6
|
+
* a stream of AG-UI events out. The request body is read through core's single bounded,
|
|
7
|
+
* proto-guarded framing lane (`@nifrajs/core/edge-kit`); the model, durable state store, and
|
|
8
|
+
* approval transport arrive through a per-request `ports` factory and never live in this package.
|
|
9
|
+
*
|
|
10
|
+
* Wire contract (default path `/agui`):
|
|
11
|
+
* - `POST {path}` body `RunAgentInput` (`threadId` and `runId` required) -> SSE where each `data:`
|
|
12
|
+
* field is one AG-UI event:
|
|
13
|
+
* - `RUN_STARTED`, then `CUSTOM { name: "nifra.turn", value: { turnId } }` announcing the
|
|
14
|
+
* runner's turn id.
|
|
15
|
+
* - Step evidence maps to `TOOL_CALL_START`/`TOOL_CALL_END` for tool effects, followed by a
|
|
16
|
+
* `TOOL_CALL_RESULT` whose `content` is the token-only outcome (`{ outcome, code? }` - the
|
|
17
|
+
* runtime never carries tool payloads), and `STEP_STARTED`/`STEP_FINISHED` for everything
|
|
18
|
+
* else. Evidence-derived events carry the evidence `timestamp`.
|
|
19
|
+
* - A model port that streams (`request.onDelta`) turns into live token frames:
|
|
20
|
+
* `TEXT_MESSAGE_START`/`_CONTENT` for text deltas, `REASONING_*` for reasoning deltas, and
|
|
21
|
+
* `TOOL_CALL_START` + `TOOL_CALL_ARGS` for the tool call being formed - the following tool
|
|
22
|
+
* evidence closes that same call (`TOOL_CALL_END` + `TOOL_CALL_RESULT`) instead of opening a
|
|
23
|
+
* second one. When any text was streamed, the terminal `TEXT_MESSAGE_*` block is suppressed -
|
|
24
|
+
* the streamed text IS the assistant message, so a streaming port must stream all
|
|
25
|
+
* user-visible text. A non-streaming port keeps the single terminal
|
|
26
|
+
* `TEXT_MESSAGE_START`/`_CONTENT`/`_END` block. `usage` deltas are summed per
|
|
27
|
+
* `(provider, model)` across the run's model decisions and stamped as the spec's
|
|
28
|
+
* `usage: TokenUsage[]` array on the terminal `RUN_FINISHED` event (success and interrupt
|
|
29
|
+
* alike) - they never produce a frame of their own. Deltas are transient: a `Last-Event-ID`
|
|
30
|
+
* replay carries evidence frames and the stored (unsuppressed) terminal events only - the
|
|
31
|
+
* stored `RUN_FINISHED` keeps its `usage`.
|
|
32
|
+
* - The `ports` factory receives `(c, run)` where `run.sharedState` is the run's
|
|
33
|
+
* `AgentSharedState` channel: `body.state` seeds the document (announced as an upfront
|
|
34
|
+
* `STATE_SNAPSHOT` when present), every `patch` streams as `STATE_DELTA` (RFC 6902 ops), and
|
|
35
|
+
* a first patch without a seeded document announces itself as a `STATE_SNAPSHOT`.
|
|
36
|
+
* - A completed run ends `RUN_FINISHED` with `result` and `outcome: { type: "success" }`, after
|
|
37
|
+
* an optional `MESSAGES_SNAPSHOT` (see `emitMessagesSnapshot`); a failed one ends `RUN_ERROR`.
|
|
38
|
+
* - A suspended run (approval, budget, model retry, max turns) emits
|
|
39
|
+
* `CUSTOM { name: "nifra.pending", value: { turnId, reason, continuation } }` and then
|
|
40
|
+
* `RUN_FINISHED` with `outcome: { type: "interrupt", interrupts: [{ id: turnId, reason,
|
|
41
|
+
* toolCallId?, responseSchema, metadata: { turnId, continuation } }] }`. Resume with the
|
|
42
|
+
* spec `resume` array - `[{ interruptId: turnId, status, payload: { continuation,
|
|
43
|
+
* approval? } }]` where `payload.continuation` echoes `metadata.continuation` (the runtime is
|
|
44
|
+
* stateless, so the client must send it back) - or with the legacy
|
|
45
|
+
* `forwardedProps.resume` (`{ continuation, approval? }`) plus `forwardedProps.turnId`. A
|
|
46
|
+
* `status: "cancelled"` entry without an explicit approval resumes as a denial. The runtime
|
|
47
|
+
* keeps state token-only, so a suspended tool's input must be replayed in
|
|
48
|
+
* `continuation.input`. A resume that fails validation is ignored and the POST starts a
|
|
49
|
+
* fresh run.
|
|
50
|
+
* - Agent input is `forwardedProps.input` when present, otherwise the content of the last
|
|
51
|
+
* `role: "user"` message.
|
|
52
|
+
* - With an `evidenceLog` configured, evidence-derived frames carry SSE `id: <seq>` and a dropped
|
|
53
|
+
* connection is resumable: re-POST the same body with a `Last-Event-ID` header to replay the
|
|
54
|
+
* missed events and rejoin the still-running turn - the run is never re-executed. Without the
|
|
55
|
+
* log the header is ignored and every POST starts a run.
|
|
56
|
+
* - The seam performs no authentication or authorization. Wrap it with the app's own route guards,
|
|
57
|
+
* and scope the store/model returned by `ports` to the caller.
|
|
58
|
+
*/
|
|
59
|
+
import { type AgentDefinition, type AgentPorts, type AgentSharedState } from "@nifrajs/agent";
|
|
60
|
+
import { type AgentEvidenceLog } from "@nifrajs/agent/events";
|
|
61
|
+
import { type ProtoPoisoning } from "@nifrajs/core/edge-kit";
|
|
62
|
+
import type { StandardSchemaV1 } from "@nifrajs/core/schema";
|
|
63
|
+
/** The structural slice of a route context the seam needs. */
|
|
64
|
+
export interface AgUIRouteContext {
|
|
65
|
+
readonly req: Request;
|
|
66
|
+
}
|
|
67
|
+
/** The structural slice of a nifra server `mountAgUI` needs. */
|
|
68
|
+
export interface AgUIMountableApp {
|
|
69
|
+
post(path: string, handler: (c: AgUIRouteContext) => Response | Promise<Response>): unknown;
|
|
70
|
+
}
|
|
71
|
+
/** Per-run context handed to the `ports` factory alongside the route context. */
|
|
72
|
+
export interface AgUIRunContext {
|
|
73
|
+
/** The runner turn id this request resolves to (fresh run or resume target). */
|
|
74
|
+
readonly turnId: string;
|
|
75
|
+
/**
|
|
76
|
+
* The run's shared UI state channel. `body.state` seeds the document; patches applied by any
|
|
77
|
+
* port stream to the client as `STATE_SNAPSHOT`/`STATE_DELTA`. Transient - never persisted.
|
|
78
|
+
*/
|
|
79
|
+
readonly sharedState: AgentSharedState;
|
|
80
|
+
}
|
|
81
|
+
export interface MountAgUIOptions<InputSchema extends StandardSchemaV1, OutputSchema extends StandardSchemaV1> {
|
|
82
|
+
readonly agent: AgentDefinition<InputSchema, OutputSchema>;
|
|
83
|
+
/** Endpoint path. Default `/agui`. */
|
|
84
|
+
readonly path?: string;
|
|
85
|
+
/** Bounded run length passed to the runner. */
|
|
86
|
+
readonly maxTurns?: number;
|
|
87
|
+
/** Maximum request body size in bytes. Default 1_000_000. */
|
|
88
|
+
readonly maxBodyBytes?: number;
|
|
89
|
+
/** Prototype-poisoning policy for the framing lane. Default `"reject"`. */
|
|
90
|
+
readonly protoPoisoning?: ProtoPoisoning;
|
|
91
|
+
/**
|
|
92
|
+
* Build the ports for one request - the model, durable state store, approval transport,
|
|
93
|
+
* capabilities, and budgets. Receives the route context so the caller can scope every port to
|
|
94
|
+
* the request subject, and the run context carrying the turn id and the shared UI state channel.
|
|
95
|
+
*/
|
|
96
|
+
readonly ports: (c: AgUIRouteContext, run: AgUIRunContext) => AgentPorts | Promise<AgentPorts>;
|
|
97
|
+
/**
|
|
98
|
+
* Evidence log making the SSE stream resumable via `Last-Event-ID`. The in-memory reference
|
|
99
|
+
* (`createMemoryAgentEvidenceLog`) is single-process; a durable log is an adapter concern.
|
|
100
|
+
*/
|
|
101
|
+
readonly evidenceLog?: AgentEvidenceLog;
|
|
102
|
+
/**
|
|
103
|
+
* Emit a `MESSAGES_SNAPSHOT` (the request's `messages` plus the assistant output message)
|
|
104
|
+
* before `RUN_FINISHED` on a successful completion. Default `false`: the snapshot echoes
|
|
105
|
+
* client-sent message payloads, and terminal events are persisted to the evidence log when one
|
|
106
|
+
* is configured - leave it off unless the client relies on an authoritative snapshot.
|
|
107
|
+
*/
|
|
108
|
+
readonly emitMessagesSnapshot?: boolean;
|
|
109
|
+
}
|
|
110
|
+
/** Mount a single agent as an AG-UI `POST {path}` SSE endpoint. */
|
|
111
|
+
export declare function mountAgUI<InputSchema extends StandardSchemaV1, OutputSchema extends StandardSchemaV1>(app: AgUIMountableApp, options: MountAgUIOptions<InputSchema, OutputSchema>): void;
|
|
112
|
+
/**
|
|
113
|
+
* One aggregated token-usage entry in the spec's `RUN_FINISHED.usage` array: the model port's
|
|
114
|
+
* `usage` deltas summed per `(provider, model)` pair, matching AG-UI's `TokenUsage` shape.
|
|
115
|
+
*/
|
|
116
|
+
export interface AgUIRunUsage {
|
|
117
|
+
readonly provider?: string;
|
|
118
|
+
readonly model?: string;
|
|
119
|
+
readonly inputTokens?: number;
|
|
120
|
+
readonly outputTokens?: number;
|
|
121
|
+
readonly totalTokens?: number;
|
|
122
|
+
readonly reasoningTokens?: number;
|
|
123
|
+
readonly cachedInputTokens?: number;
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AAEH,OAAO,EACL,KAAK,eAAe,EAIpB,KAAK,UAAU,EAEf,KAAK,gBAAgB,EAStB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAEL,KAAK,cAAc,EAKpB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAQ5D,8DAA8D;AAC9D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;CACtB;AAED,gEAAgE;AAChE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,gBAAgB,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAA;CAC5F;AAED,iFAAiF;AACjF,MAAM,WAAW,cAAc;IAC7B,gFAAgF;IAChF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB;;;OAGG;IACH,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAA;CACvC;AAED,MAAM,WAAW,gBAAgB,CAC/B,WAAW,SAAS,gBAAgB,EACpC,YAAY,SAAS,gBAAgB;IAErC,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC,WAAW,EAAE,YAAY,CAAC,CAAA;IAC1D,sCAAsC;IACtC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,+CAA+C;IAC/C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,6DAA6D;IAC7D,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,2EAA2E;IAC3E,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAA;IACxC;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,gBAAgB,EAAE,GAAG,EAAE,cAAc,KAAK,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;IAC9F;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAA;IACvC;;;;;OAKG;IACH,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAA;CACxC;AAED,mEAAmE;AACnE,wBAAgB,SAAS,CACvB,WAAW,SAAS,gBAAgB,EACpC,YAAY,SAAS,gBAAgB,EACrC,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,gBAAgB,CAAC,WAAW,EAAE,YAAY,CAAC,GAAG,IAAI,CAgBnF;AAyND;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CACpC"}
|