@flowget/ai-chat 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.
- package/CHANGELOG.md +52 -0
- package/LICENSE +105 -0
- package/README.md +228 -0
- package/dist/react.cjs +567 -0
- package/dist/react.d.cts +250 -0
- package/dist/react.d.ts +250 -0
- package/dist/react.js +561 -0
- package/dist/server.cjs +118 -0
- package/dist/server.d.cts +91 -0
- package/dist/server.d.ts +91 -0
- package/dist/server.js +114 -0
- package/dist/styles.css +473 -0
- package/package.json +91 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@flowget/ai-chat` are documented here. This
|
|
4
|
+
project adheres to [Semantic Versioning](https://semver.org/) (pre-1.0:
|
|
5
|
+
minor = breaking).
|
|
6
|
+
|
|
7
|
+
## [0.1.0]
|
|
8
|
+
|
|
9
|
+
Initial release — a builder-agnostic AI workflow-authoring chat.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **`@flowget/ai-chat/react`** — the client.
|
|
14
|
+
- `<WorkflowChat currentGraph={…} applyGraph={…} />`: a turnkey floating
|
|
15
|
+
chat panel (assistant-ui `AssistantModalPrimitive`) with a streaming
|
|
16
|
+
runtime, a thread, and a proposal → **approval** → apply flow. The
|
|
17
|
+
approval gate pauses the run; the proposal card renders Apply / Dismiss
|
|
18
|
+
inline; applying lays the graph out (preserving surviving-node positions)
|
|
19
|
+
and commits it through the host's `applyGraph`. Builder-agnostic: the host
|
|
20
|
+
owns the canvas via the `currentGraph` / `applyGraph` seam.
|
|
21
|
+
- Props for light theming and continuity: `heading`, `subtitle`, `examples`,
|
|
22
|
+
`endpoint`, a fully custom `transport`, and `actor` / `context` request
|
|
23
|
+
metadata.
|
|
24
|
+
- A host-pluggable `layout` prop: delegate proposal layout to your builder
|
|
25
|
+
(e.g. a dagre merge) instead of the built-in `layoutProposal`, keeping
|
|
26
|
+
ai-chat builder-agnostic (the host supplies the function).
|
|
27
|
+
- **Headless tier** for hosts that bring their own shell / transport:
|
|
28
|
+
`ChatRuntimeProvider`, `createWorkflowChatAdapter`,
|
|
29
|
+
`httpChatStreamTransport`, and the pure `layoutProposal` layout helper.
|
|
30
|
+
- **`@flowget/ai-chat/server`** — the BFF helper (React-free).
|
|
31
|
+
- `createChatStreamResponse(req, config, options?)`: parses + validates the
|
|
32
|
+
request, then streams `@flowget/ai`'s `authorStream()` to the browser as
|
|
33
|
+
SSE. `options.buildRequest` is the seam for injecting a **server-derived**
|
|
34
|
+
actor (from the host's session/JWT) over the untrusted client value;
|
|
35
|
+
`options.onError` maps errors to client-safe messages.
|
|
36
|
+
- `streamAuthorSSE(request, config, options?)`: the lower-level primitive for
|
|
37
|
+
hosts that build/validate the `AuthorRequest` themselves.
|
|
38
|
+
- `parseChatRequest(req, limits?)`: body/command size bounds and shape
|
|
39
|
+
validation (rejects a non-object or array `currentGraph`).
|
|
40
|
+
- **`@flowget/ai-chat/styles.css`** — a self-contained stylesheet. Every value
|
|
41
|
+
reads a `--flowget-*` design token with a sensible built-in fallback, so the
|
|
42
|
+
chat renders standalone and inherits a host's theme where those tokens are
|
|
43
|
+
defined. Placement is tunable via `--fg-aichat-z` and
|
|
44
|
+
`--fg-aichat-launcher-offset`; class names use the `fg-aichat-` namespace.
|
|
45
|
+
|
|
46
|
+
### Security
|
|
47
|
+
|
|
48
|
+
- The `/server` helper is **unauthenticated by design**. The host must place
|
|
49
|
+
its own authentication, authorization, and rate-limiting in front of the
|
|
50
|
+
route, and inject a server-derived `actor` via `buildRequest` for any
|
|
51
|
+
actor-scoped data access. Server errors are logged server-side and never
|
|
52
|
+
forwarded verbatim to the browser. See the README "Security" section.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Functional Source License, Version 1.1, ALv2 Future License
|
|
2
|
+
|
|
3
|
+
## Abbreviation
|
|
4
|
+
|
|
5
|
+
FSL-1.1-ALv2
|
|
6
|
+
|
|
7
|
+
## Notice
|
|
8
|
+
|
|
9
|
+
Copyright 2026 Flowget
|
|
10
|
+
|
|
11
|
+
## Terms and Conditions
|
|
12
|
+
|
|
13
|
+
### Licensor ("We")
|
|
14
|
+
|
|
15
|
+
The party offering the Software under these Terms and Conditions.
|
|
16
|
+
|
|
17
|
+
### The Software
|
|
18
|
+
|
|
19
|
+
The "Software" is each version of the software that we make available under
|
|
20
|
+
these Terms and Conditions, as indicated by our inclusion of these Terms and
|
|
21
|
+
Conditions with the Software.
|
|
22
|
+
|
|
23
|
+
### License Grant
|
|
24
|
+
|
|
25
|
+
Subject to your compliance with this License Grant and the Patents,
|
|
26
|
+
Redistribution and Trademark clauses below, we hereby grant you the right to
|
|
27
|
+
use, copy, modify, create derivative works, publicly perform, publicly display
|
|
28
|
+
and redistribute the Software for any Permitted Purpose identified below.
|
|
29
|
+
|
|
30
|
+
### Permitted Purpose
|
|
31
|
+
|
|
32
|
+
A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
|
|
33
|
+
means making the Software available to others in a commercial product or
|
|
34
|
+
service that:
|
|
35
|
+
|
|
36
|
+
1. substitutes for the Software;
|
|
37
|
+
|
|
38
|
+
2. substitutes for any other product or service we offer using the Software
|
|
39
|
+
that exists as of the date we make the Software available; or
|
|
40
|
+
|
|
41
|
+
3. offers the same or substantially similar functionality as the Software.
|
|
42
|
+
|
|
43
|
+
Permitted Purposes specifically include using the Software:
|
|
44
|
+
|
|
45
|
+
1. for your internal use and access;
|
|
46
|
+
|
|
47
|
+
2. for non-commercial education;
|
|
48
|
+
|
|
49
|
+
3. for non-commercial research; and
|
|
50
|
+
|
|
51
|
+
4. in connection with professional services that you provide to a licensee
|
|
52
|
+
using the Software in accordance with these Terms and Conditions.
|
|
53
|
+
|
|
54
|
+
### Patents
|
|
55
|
+
|
|
56
|
+
To the extent your use for a Permitted Purpose would necessarily infringe our
|
|
57
|
+
patents, the license grant above includes a license under our patents. If you
|
|
58
|
+
make a claim against any party that the Software infringes or contributes to
|
|
59
|
+
the infringement of any patent, then your patent license to the Software ends
|
|
60
|
+
immediately.
|
|
61
|
+
|
|
62
|
+
### Redistribution
|
|
63
|
+
|
|
64
|
+
The Terms and Conditions apply to all copies, modifications and derivatives of
|
|
65
|
+
the Software.
|
|
66
|
+
|
|
67
|
+
If you redistribute any copies, modifications or derivatives of the Software,
|
|
68
|
+
you must include a copy of or a link to these Terms and Conditions and not
|
|
69
|
+
remove any copyright notices provided in or with the Software.
|
|
70
|
+
|
|
71
|
+
### Disclaimer
|
|
72
|
+
|
|
73
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
|
|
74
|
+
IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
|
|
75
|
+
PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
|
|
76
|
+
|
|
77
|
+
IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
|
|
78
|
+
SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
|
|
79
|
+
EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
|
|
80
|
+
|
|
81
|
+
### Trademarks
|
|
82
|
+
|
|
83
|
+
Except for displaying the License Details and identifying us as the origin of
|
|
84
|
+
the Software, you have no right under these Terms and Conditions to use our
|
|
85
|
+
trademarks, trade names, service marks or product names.
|
|
86
|
+
|
|
87
|
+
## Grant of Future License
|
|
88
|
+
|
|
89
|
+
We hereby irrevocably grant you an additional license to use the Software under
|
|
90
|
+
the Apache License, Version 2.0 that is effective on the second anniversary of
|
|
91
|
+
the date we make the Software available. On or after that date, you may use the
|
|
92
|
+
Software under the Apache License, Version 2.0, in which case the following
|
|
93
|
+
will apply:
|
|
94
|
+
|
|
95
|
+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
|
96
|
+
this file except in compliance with the License.
|
|
97
|
+
|
|
98
|
+
You may obtain a copy of the License at
|
|
99
|
+
|
|
100
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
101
|
+
|
|
102
|
+
Unless required by applicable law or agreed to in writing, software distributed
|
|
103
|
+
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
104
|
+
CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
105
|
+
specific language governing permissions and limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# @flowget/ai-chat
|
|
2
|
+
|
|
3
|
+
Builder-agnostic **AI workflow-authoring chat** for [Flowget](https://flowget.io).
|
|
4
|
+
|
|
5
|
+
A user describes a workflow in natural language; the chat streams a proposal,
|
|
6
|
+
shows an **approval card**, and — once approved — applies the laid-out graph to
|
|
7
|
+
your canvas. Editing works the same way (the current graph is the context).
|
|
8
|
+
|
|
9
|
+
Built on assistant-ui primitives (streaming, approval gate, thread) and
|
|
10
|
+
[`@flowget/ai`](https://github.com/flowgethq/ai)'s streaming `author()` — with
|
|
11
|
+
**no lock-in**: the LLM stays behind `@flowget/ai`'s BYO adapter, and the chat
|
|
12
|
+
never imports your builder.
|
|
13
|
+
|
|
14
|
+
## Two entry points
|
|
15
|
+
|
|
16
|
+
| Import | Runs | What |
|
|
17
|
+
| --- | --- | --- |
|
|
18
|
+
| `@flowget/ai-chat/react` | browser | `<WorkflowChat>` — the chat panel + streaming runtime + proposal card |
|
|
19
|
+
| `@flowget/ai-chat/server` | your BFF | `createChatStreamResponse()` — SSE over `@flowget/ai`'s `authorStream()` |
|
|
20
|
+
| `@flowget/ai-chat/styles.css` | — | the stylesheet (import once) |
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install @flowget/ai-chat @flowget/ai @assistant-ui/react
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`react`, `react-dom`, `@assistant-ui/react` are peer deps (you provide them).
|
|
29
|
+
`@flowget/ai` is an **optional** peer — install it only if you use the
|
|
30
|
+
`/server` helper (the authoring engine runs there). A react-only consumer with
|
|
31
|
+
its own backend transport can skip it.
|
|
32
|
+
|
|
33
|
+
## Client — mount the chat
|
|
34
|
+
|
|
35
|
+
Drop `<WorkflowChat>` inside your builder. It's builder-agnostic: pass the live
|
|
36
|
+
`currentGraph` and an `applyGraph` callback (e.g. your store's `setGraph`). The
|
|
37
|
+
chat proposes; you apply.
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import "@flowget/ai-chat/styles.css";
|
|
41
|
+
import { WorkflowChat } from "@flowget/ai-chat/react";
|
|
42
|
+
import { useFlowgetWorkflow } from "@flowget/builder"; // your builder
|
|
43
|
+
|
|
44
|
+
function BuilderChat() {
|
|
45
|
+
const { graph, setGraph } = useFlowgetWorkflow();
|
|
46
|
+
return <WorkflowChat currentGraph={graph} applyGraph={setGraph} />;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// inside your builder's children slot:
|
|
50
|
+
// <FlowgetBuilder ...><BuilderChat /></FlowgetBuilder>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`WorkflowChat` props:
|
|
54
|
+
|
|
55
|
+
| Prop | Type | |
|
|
56
|
+
| --- | --- | --- |
|
|
57
|
+
| `currentGraph` | `WorkflowGraph` | live canvas graph (edit context + layout baseline) |
|
|
58
|
+
| `applyGraph` | `(g: WorkflowGraph) => void` | commit a laid-out graph to the canvas |
|
|
59
|
+
| `transport?` | `ChatStreamTransport` | fully custom backend transport (overrides `endpoint`) |
|
|
60
|
+
| `endpoint?` | `string` | endpoint for the default SSE transport (`/api/chat`) |
|
|
61
|
+
| `heading?` | `string` | panel heading (default `"Workflow AI"`) |
|
|
62
|
+
| `subtitle?` | `string` | panel subtitle (default `"Draft & edit with a prompt"`) |
|
|
63
|
+
| `examples?` | `readonly string[]` | empty-state suggestion chips; `[]` hides them |
|
|
64
|
+
| `layout?` | `WorkflowLayout` | lay a proposal out before apply (default `layoutProposal`) — see below |
|
|
65
|
+
| `actor?` | `ChatActor` | caller-identity hint — **untrusted on the wire** (see [Security](#security)) |
|
|
66
|
+
| `context?` | `unknown` | opaque continuity payload forwarded to the model |
|
|
67
|
+
|
|
68
|
+
### Layout — delegate to your builder
|
|
69
|
+
|
|
70
|
+
By default the chat lays each proposal out with the built-in `layoutProposal`
|
|
71
|
+
(a zero-dependency BFS layered layout that preserves the positions of nodes
|
|
72
|
+
already on the canvas). A builder-host with a better layout — e.g. a dagre
|
|
73
|
+
`autoLayout` / merge — injects it via the `layout` prop, keeping ai-chat
|
|
74
|
+
builder-agnostic (the host supplies the function; the chat never imports your
|
|
75
|
+
builder):
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
import { WorkflowChat, type WorkflowLayout } from "@flowget/ai-chat/react";
|
|
79
|
+
|
|
80
|
+
const layout: WorkflowLayout = (proposed, current) => mergeGraph(current, proposed);
|
|
81
|
+
|
|
82
|
+
<WorkflowChat currentGraph={graph} applyGraph={setGraph} layout={layout} />;
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`layout: (proposed: ProposedGraph, current: WorkflowGraph) => WorkflowGraph`.
|
|
86
|
+
`layoutProposal` stays exported as the default / fallback.
|
|
87
|
+
|
|
88
|
+
### Headless mode
|
|
89
|
+
|
|
90
|
+
`<WorkflowChat>` is a turnkey shell built from smaller pieces. To bring your own
|
|
91
|
+
shell — or render assistant-ui primitives yourself — compose them directly:
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
import {
|
|
95
|
+
ChatRuntimeProvider,
|
|
96
|
+
httpChatStreamTransport,
|
|
97
|
+
layoutProposal,
|
|
98
|
+
} from "@flowget/ai-chat/react";
|
|
99
|
+
|
|
100
|
+
// getCurrentGraph must be referentially stable (a ref getter, not an inline fn)
|
|
101
|
+
<ChatRuntimeProvider getCurrentGraph={getCurrentGraph} transport={httpChatStreamTransport("/api/chat")}>
|
|
102
|
+
{/* your own assistant-ui <Thread>, composer, and proposal rendering */}
|
|
103
|
+
</ChatRuntimeProvider>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
- `ChatRuntimeProvider` — wires assistant-ui's `LocalRuntime` to the authoring
|
|
107
|
+
adapter and provides it to your subtree.
|
|
108
|
+
- `createWorkflowChatAdapter(...)` — the raw `ChatModelAdapter`, if you drive
|
|
109
|
+
the runtime yourself.
|
|
110
|
+
- `httpChatStreamTransport(endpoint?)` — the default SSE transport; swap it for
|
|
111
|
+
any `ChatStreamTransport` (an async generator of `ChatStreamEvent`s) to reach
|
|
112
|
+
a custom backend.
|
|
113
|
+
- `layoutProposal(proposed, current?)` — the pure layout helper (BFS layered
|
|
114
|
+
layout; preserves the positions of nodes that already exist on the canvas).
|
|
115
|
+
|
|
116
|
+
## Server — the BFF route
|
|
117
|
+
|
|
118
|
+
Wire your `@flowget/ai` config (your node catalog + LLM adapter) into the SSE
|
|
119
|
+
helper. The engine runs entirely server-side.
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
import { createChatStreamResponse } from "@flowget/ai-chat/server";
|
|
123
|
+
import { finalizeConfig, resolveCatalog, openaiAdapter } from "@flowget/ai";
|
|
124
|
+
|
|
125
|
+
const catalog = await resolveCatalog({ registryDir: process.env.REGISTRY_DIR! });
|
|
126
|
+
const config = finalizeConfig(
|
|
127
|
+
{ adapter: openaiAdapter({ apiKey: process.env.OPENROUTER_API_KEY! }), catalog },
|
|
128
|
+
catalog,
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
// e.g. a Bun / Node / edge handler for POST /api/chat
|
|
132
|
+
export async function POST(req: Request): Promise<Response> {
|
|
133
|
+
// ⚠️ Your auth + rate-limiting run FIRST — see Security below.
|
|
134
|
+
const session = await getSession(req);
|
|
135
|
+
if (!session) return new Response("Unauthorized", { status: 401 });
|
|
136
|
+
|
|
137
|
+
return createChatStreamResponse(req, config, {
|
|
138
|
+
// Inject a SERVER-DERIVED actor over the untrusted client value:
|
|
139
|
+
buildRequest: (parsed) => ({ ...parsed, actor: session.actor }),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
`createChatStreamResponse(req, config, options?)` — parses + validates the
|
|
145
|
+
request, then streams the authoring result as SSE. Options:
|
|
146
|
+
|
|
147
|
+
| Option | | |
|
|
148
|
+
| --- | --- | --- |
|
|
149
|
+
| `buildRequest?` | `(parsed, req) => AuthorRequest` | rebuild the request — inject a server-derived `actor` / `context` |
|
|
150
|
+
| `onError?` | `(err) => string` | map an error to a client-safe message (default `"Authoring failed"`) |
|
|
151
|
+
| `maxBodyBytes?` | `number` | request-body cap (default 1 MiB) |
|
|
152
|
+
| `maxCommandLength?` | `number` | `command` length cap (default 8000) |
|
|
153
|
+
|
|
154
|
+
Need to build the `AuthorRequest` yourself? Use the lower-level
|
|
155
|
+
`streamAuthorSSE(request, config, { signal?, onError? })`.
|
|
156
|
+
|
|
157
|
+
The wire format between `/server` and `/react` is SSE: one `data:`-framed event
|
|
158
|
+
per line — `text-delta`\* then a terminal `proposal | message`, or `error`.
|
|
159
|
+
|
|
160
|
+
## Security
|
|
161
|
+
|
|
162
|
+
The `/server` helper is **unauthenticated by design** and does **no**
|
|
163
|
+
rate-limiting. It is streaming plumbing, not a security boundary.
|
|
164
|
+
|
|
165
|
+
**You MUST:**
|
|
166
|
+
|
|
167
|
+
- Put your own **authentication and authorization** in front of the route
|
|
168
|
+
(reject unauthenticated requests before calling the helper).
|
|
169
|
+
- Add **rate-limiting** / abuse protection — each request drives an LLM call.
|
|
170
|
+
- Treat the client-supplied `actor` as **untrusted**. It is plain JSON on the
|
|
171
|
+
request body; a browser can send anything. If any `@flowget/ai` toolset or
|
|
172
|
+
authorizer gates data access on the actor (e.g. by `tenantId`), derive the
|
|
173
|
+
actor **server-side** (from your session/JWT) and inject it with
|
|
174
|
+
`buildRequest` — and/or verify it with a `@flowget/ai` authorizer. Otherwise
|
|
175
|
+
a client can spoof it.
|
|
176
|
+
|
|
177
|
+
Server-side errors are logged on the server and never forwarded verbatim to the
|
|
178
|
+
browser (the client only sees a generic message, or your `onError` mapping).
|
|
179
|
+
|
|
180
|
+
## Theming
|
|
181
|
+
|
|
182
|
+
Import the stylesheet once — it is **self-contained** and renders correctly with
|
|
183
|
+
no host theme. Every value reads a `--flowget-*` design token with a built-in
|
|
184
|
+
fallback, so where your app defines those tokens (light/dark), the chat inherits
|
|
185
|
+
them automatically; where it doesn't, the fallback applies.
|
|
186
|
+
|
|
187
|
+
Overridable design tokens (set them on `:root` or any ancestor):
|
|
188
|
+
|
|
189
|
+
| Token | Fallback | Used for |
|
|
190
|
+
| --- | --- | --- |
|
|
191
|
+
| `--flowget-color-accent` | `#6366f1` | primary / brand accent |
|
|
192
|
+
| `--flowget-color-text` | `#0f172a` | body text |
|
|
193
|
+
| `--flowget-color-text-subtle` | `#64748b` | secondary text |
|
|
194
|
+
| `--flowget-color-text-inverse` | `#ffffff` | text on the accent |
|
|
195
|
+
| `--flowget-color-bg` | `#ffffff` | input / chip background |
|
|
196
|
+
| `--flowget-color-bg-elevated` | `#ffffff` | panel background |
|
|
197
|
+
| `--flowget-color-surface-strong` | `#f8fafc` | proposal-card surface |
|
|
198
|
+
| `--flowget-color-border` | `#e2e8f0` | borders |
|
|
199
|
+
| `--flowget-color-border-strong` | `#cbd5e1` | hover borders |
|
|
200
|
+
| `--flowget-color-danger` | `#dc2626` | error state |
|
|
201
|
+
| `--flowget-color-success` | `#16a34a` | applied confirmation |
|
|
202
|
+
| `--flowget-radius-lg` / `-md` | `14px` / `9px` | corner radii |
|
|
203
|
+
| `--flowget-shadow-lg` | `0 12px 32px -8px rgba(15,23,42,.28)` | panel / launcher shadow |
|
|
204
|
+
| `--flowget-font-sans` / `-mono` | system stacks | typography |
|
|
205
|
+
| `--flowget-font-size-sm` / `-xs` / `-md` | `13px` / `11px` / `15px` | type scale |
|
|
206
|
+
| `--flowget-motion-fast` | `140ms` | transition duration |
|
|
207
|
+
|
|
208
|
+
Two package-owned knobs control placement (class prefix: `fg-aichat-`):
|
|
209
|
+
|
|
210
|
+
| Token | Fallback | |
|
|
211
|
+
| --- | --- | --- |
|
|
212
|
+
| `--fg-aichat-z` | `200` | stacking order of the launcher + panel |
|
|
213
|
+
| `--fg-aichat-launcher-offset` | `24px` | gap from the bottom-right corner |
|
|
214
|
+
|
|
215
|
+
## How it fits together
|
|
216
|
+
|
|
217
|
+
```
|
|
218
|
+
browser your BFF @flowget/ai
|
|
219
|
+
──────── ──────── ───────────
|
|
220
|
+
<WorkflowChat> createChatStreamResponse(req,cfg)
|
|
221
|
+
LocalRuntime ── POST /api/chat ──► authorStream(cfg, request) ──► BYO adapter (LLM)
|
|
222
|
+
(streams text) ◄──── SSE ──────── (text-delta* → proposal|message)
|
|
223
|
+
proposal card → Apply → applyGraph(graph) (your canvas)
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## License
|
|
227
|
+
|
|
228
|
+
FSL-1.1-ALv2
|