@chai-ui/core 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/LICENSE +21 -0
- package/README.md +84 -0
- package/dist/engine.d.ts +84 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +173 -0
- package/dist/engine.js.map +1 -0
- package/dist/engines/fal.d.ts +95 -0
- package/dist/engines/fal.d.ts.map +1 -0
- package/dist/engines/fal.js +209 -0
- package/dist/engines/fal.js.map +1 -0
- package/dist/engines/openrouter.d.ts +141 -0
- package/dist/engines/openrouter.d.ts.map +1 -0
- package/dist/engines/openrouter.js +220 -0
- package/dist/engines/openrouter.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/media-analysis-prompts.d.ts +18 -0
- package/dist/media-analysis-prompts.d.ts.map +1 -0
- package/dist/media-analysis-prompts.js +35 -0
- package/dist/media-analysis-prompts.js.map +1 -0
- package/dist/model-routing.d.ts +49 -0
- package/dist/model-routing.d.ts.map +1 -0
- package/dist/model-routing.js +72 -0
- package/dist/model-routing.js.map +1 -0
- package/dist/run.d.ts +75 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +90 -0
- package/dist/run.js.map +1 -0
- package/dist/server/chai-handler.d.ts +43 -0
- package/dist/server/chai-handler.d.ts.map +1 -0
- package/dist/server/chai-handler.js +106 -0
- package/dist/server/chai-handler.js.map +1 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +4 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/node.d.ts +24 -0
- package/dist/server/node.d.ts.map +1 -0
- package/dist/server/node.js +60 -0
- package/dist/server/node.js.map +1 -0
- package/dist/types.d.ts +85 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +63 -0
- package/src/engine.ts +237 -0
- package/src/engines/fal.ts +271 -0
- package/src/engines/openrouter.ts +301 -0
- package/src/index.ts +7 -0
- package/src/media-analysis-prompts.ts +45 -0
- package/src/model-routing.ts +104 -0
- package/src/run.ts +145 -0
- package/src/server/chai-handler.ts +146 -0
- package/src/server/index.ts +3 -0
- package/src/server/node.ts +75 -0
- package/src/types.ts +96 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 kazarazat
|
|
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 all
|
|
13
|
+
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 THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# @chai-ui/core
|
|
2
|
+
|
|
3
|
+
The headless core behind CHAI's components: the data types, the
|
|
4
|
+
Request → Run → Result model a submitted prompt flows through, and the
|
|
5
|
+
pluggable generation engines that actually call models. No framework, no
|
|
6
|
+
rendering — `@chai-ui/react` is one binding of this; a future non-React
|
|
7
|
+
binding would depend on this package the same way.
|
|
8
|
+
|
|
9
|
+
## Layout
|
|
10
|
+
|
|
11
|
+
- `types.ts` — shared types: `MediaKind`, `DroppedMedia`, `ModelOption`, `Usage`, `GenerationUseCase`.
|
|
12
|
+
- `run.ts` — `Request`/`Run`/`Result` plus pure transitions over them (`createRun`, `startResult`, `resolveResult`, `failResult`, `deriveGenerationUseCase`).
|
|
13
|
+
- `engine.ts` — the `GenerationEngine` interface every provider implements, `GenerationError`, and `mockEngine`/`createMockEngine` (placeholder output, no network call, no API key).
|
|
14
|
+
- `engines/fal.ts` — `createFalEngine`, media generation through Fal.ai (the default).
|
|
15
|
+
- `engines/openrouter.ts` — `createOpenRouterEngine`, text/reasoning through OpenRouter (prompt enhancement, media analysis).
|
|
16
|
+
- `media-analysis-prompts.ts` — the instruction text `MediaAnalyzer` sends, per media kind × prompt length.
|
|
17
|
+
- `model-routing.ts` — auto-select: `buildModelRoutingPrompt`, `parseModelRoutingReply`, and `routeModel`, which falls back to the first listed model instead of throwing.
|
|
18
|
+
- `server/` — `createChaiHandler` and `toNodeHandler`, exported from `@chai-ui/core/server` (server-only).
|
|
19
|
+
|
|
20
|
+
## The server route: `@chai-ui/core/server`
|
|
21
|
+
|
|
22
|
+
The built-in engines never hold an API key. They call one route on your
|
|
23
|
+
server, `/api/chai/*`, and `createChaiHandler` serves it: it adds the key
|
|
24
|
+
and forwards the request to Fal.ai or OpenRouter, streaming replies
|
|
25
|
+
through.
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
// Next.js: app/api/chai/[...path]/route.ts
|
|
29
|
+
import { createChaiHandler } from "@chai-ui/core/server";
|
|
30
|
+
|
|
31
|
+
export const { GET, POST, PUT } = createChaiHandler();
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Set `FAL_KEY` and `OPENROUTER_API_KEY` in the server's environment (never
|
|
35
|
+
with a `VITE_` or `NEXT_PUBLIC_` prefix). A missing key comes back as a
|
|
36
|
+
clear error, e.g. "FAL_KEY isn't set on the server."
|
|
37
|
+
|
|
38
|
+
**Where it runs.** Chai's components are React-only, so the route lives in
|
|
39
|
+
your React app's framework or on the API server behind it. Mount it at
|
|
40
|
+
`/api/chai`, where the components send their requests. `handle(request)`
|
|
41
|
+
takes a standard web `Request` and returns a `Response`; `GET`, `POST` and
|
|
42
|
+
`PUT` (Fal's cancel call) are the same function. When the browser
|
|
43
|
+
disconnects, the provider call is aborted too.
|
|
44
|
+
|
|
45
|
+
| Your setup | Add this |
|
|
46
|
+
|---|---|
|
|
47
|
+
| Next.js (App Router) | `export const { GET, POST, PUT } = createChaiHandler();` in `app/api/chai/[...path]/route.ts` |
|
|
48
|
+
| Remix / React Router | `export const loader = ({ request }) => chai.handle(request); export const action = loader;` in `app/routes/api.chai.$.ts` |
|
|
49
|
+
| Hono | `app.all("/api/chai/*", (c) => chai.handle(c.req.raw))` |
|
|
50
|
+
| Bun, Deno | route `/api/chai/*` to `chai.handle` in `Bun.serve` / `Deno.serve` |
|
|
51
|
+
| Cloudflare Workers | `createChaiHandler({ falKey: env.FAL_KEY, openRouterKey: env.OPENROUTER_API_KEY }).handle(request)` |
|
|
52
|
+
| Express, plain Node | `app.use("/api/chai", toNodeHandler(createChaiHandler()))` |
|
|
53
|
+
|
|
54
|
+
**Before going live**, limit who can use the route and what it runs.
|
|
55
|
+
Without these, anyone who reaches your site can spend your API credit:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
createChaiHandler({
|
|
59
|
+
authorize: async (request) => Boolean(await getSession(request)), // false → 403
|
|
60
|
+
allowedModels: ["fal-ai/flux/schnell", "anthropic/claude-opus-5"], // anything else → 403
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Never import `@chai-ui/core/server` from browser code.
|
|
65
|
+
|
|
66
|
+
## Writing an engine
|
|
67
|
+
|
|
68
|
+
One method: a prompt plus any attached media in, one piece of output back.
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import type { GenerationEngine } from "@chai-ui/core";
|
|
72
|
+
|
|
73
|
+
const myEngine: GenerationEngine = {
|
|
74
|
+
async generate({ modelId, prompt, attachments }) {
|
|
75
|
+
// call your provider…
|
|
76
|
+
return { src: "https://…/output.png", kind: "image" };
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Throw a `GenerationError(message, reasons?)` to fail a call with
|
|
82
|
+
user-facing content rather than a bare network error. API keys never
|
|
83
|
+
belong in an engine: call a server route that adds the key, like
|
|
84
|
+
`createChaiHandler` above.
|
package/dist/engine.d.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A pluggable generation engine — the one interface every model provider
|
|
3
|
+
* (`createFalEngine`, `createOpenRouterEngine`, `mockEngine`, or your own)
|
|
4
|
+
* implements, and the one `useComposer` calls. One call = one model run:
|
|
5
|
+
* a prompt plus any attached media in, one piece of output back.
|
|
6
|
+
*
|
|
7
|
+
* `mockEngine` stands in for a real model API during prototyping: it
|
|
8
|
+
* "generates" a small deterministic placeholder image without any network
|
|
9
|
+
* call or API key. Swap in a real engine without touching any component —
|
|
10
|
+
* that's the whole point of keeping this behind an interface.
|
|
11
|
+
*/
|
|
12
|
+
import type { DroppedMedia, Evaluation, MediaKind, Usage } from "./types.js";
|
|
13
|
+
export interface GenerationEngine {
|
|
14
|
+
generate(args: {
|
|
15
|
+
/**
|
|
16
|
+
* The model the person picked. An engine uses it when set and falls
|
|
17
|
+
* back to its own configured default when it isn't.
|
|
18
|
+
*/
|
|
19
|
+
modelId?: string;
|
|
20
|
+
prompt: string;
|
|
21
|
+
attachments: DroppedMedia[];
|
|
22
|
+
/**
|
|
23
|
+
* Optional streaming hook for text output. An engine that can stream
|
|
24
|
+
* calls this with the full text received so far (not a delta) each time
|
|
25
|
+
* more arrives; one that can't simply never calls it. The returned
|
|
26
|
+
* promise's value is still the authoritative final output.
|
|
27
|
+
*/
|
|
28
|
+
onText?: (textSoFar: string) => void;
|
|
29
|
+
/**
|
|
30
|
+
* Aborted when the person stops the request. An engine that can cancel
|
|
31
|
+
* at the provider does so, then rejects with an `AbortError` (see
|
|
32
|
+
* `abortError`). Cancellation is best effort: some providers keep
|
|
33
|
+
* running, and billing, once a request has started.
|
|
34
|
+
*/
|
|
35
|
+
signal?: AbortSignal;
|
|
36
|
+
}): Promise<{
|
|
37
|
+
src: string;
|
|
38
|
+
kind: MediaKind;
|
|
39
|
+
usage?: Usage;
|
|
40
|
+
evaluations?: Evaluation[];
|
|
41
|
+
}>;
|
|
42
|
+
}
|
|
43
|
+
/** The error an engine rejects with when its `signal` was aborted. */
|
|
44
|
+
export declare function abortError(): Error;
|
|
45
|
+
/** True for an `AbortError`, the way an engine reports a cancelled call. */
|
|
46
|
+
export declare function isAbortError(err: unknown): boolean;
|
|
47
|
+
/** Resolves after `ms`, or rejects with an `AbortError` as soon as `signal` aborts. */
|
|
48
|
+
export declare function abortableSleep(ms: number, signal?: AbortSignal): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Thrown by a `GenerationEngine` to fail a call with structured,
|
|
51
|
+
* user-facing content — `reasons` can render as a bullet list, `message`
|
|
52
|
+
* alone as a single sentence. A real engine should unwrap its provider's
|
|
53
|
+
* specific error into this shape rather than let a bare network/HTTP error
|
|
54
|
+
* reach the UI.
|
|
55
|
+
*/
|
|
56
|
+
export declare class GenerationError extends Error {
|
|
57
|
+
reasons?: string[];
|
|
58
|
+
constructor(message: string, reasons?: string[]);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Reads the top-level `evaluations` field a builder's backend proxy
|
|
62
|
+
* appended to a provider response, the convention both built-in engines
|
|
63
|
+
* follow. Malformed entries are dropped rather than rendered as verdicts
|
|
64
|
+
* nobody actually returned.
|
|
65
|
+
*/
|
|
66
|
+
export declare function readEvaluations(json: unknown): Evaluation[] | undefined;
|
|
67
|
+
/** Turns anything an engine threw into the `{ message, reasons }` shape a `Result`'s `error` holds. */
|
|
68
|
+
export declare function normalizeGenerationError(err: unknown): {
|
|
69
|
+
message: string;
|
|
70
|
+
reasons?: string[];
|
|
71
|
+
};
|
|
72
|
+
export interface MockEngineOptions {
|
|
73
|
+
/** What the mock "generates". Defaults to "image" (a placeholder gradient); "text" returns a plausible text reply instead. */
|
|
74
|
+
outputKind?: "image" | "text";
|
|
75
|
+
/**
|
|
76
|
+
* Fraction of calls that fail with `GenerationError`, 0-1. Default 0 —
|
|
77
|
+
* pass 1 to force every call to fail (a UI-testing convenience for
|
|
78
|
+
* previewing error states on demand).
|
|
79
|
+
*/
|
|
80
|
+
failureRate?: number;
|
|
81
|
+
}
|
|
82
|
+
export declare function createMockEngine(options?: MockEngineOptions): GenerationEngine;
|
|
83
|
+
export declare const mockEngine: GenerationEngine;
|
|
84
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAE7E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE;QACb;;;WAGG;QACH,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,YAAY,EAAE,CAAC;QAC5B;;;;;WAKG;QACH,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;QACrC;;;;;WAKG;QACH,MAAM,CAAC,EAAE,WAAW,CAAC;KACtB,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,SAAS,CAAC;QAAC,KAAK,CAAC,EAAE,KAAK,CAAC;QAAC,WAAW,CAAC,EAAE,UAAU,EAAE,CAAA;KAAE,CAAC,CAAC;CAC1F;AAED,sEAAsE;AACtE,wBAAgB,UAAU,IAAI,KAAK,CAElC;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAElD;AAED,uFAAuF;AACvF,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAa9E;AAED;;;;;;GAMG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACxC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;gBACP,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE;CAKhD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,EAAE,GAAG,SAAS,CAQvE;AAED,uGAAuG;AACvG,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,OAAO,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAM9F;AAoFD,MAAM,WAAW,iBAAiB;IAChC,8HAA8H;IAC9H,UAAU,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC9B;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CAgClF;AAED,eAAO,MAAM,UAAU,EAAE,gBAAqC,CAAC"}
|
package/dist/engine.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A pluggable generation engine — the one interface every model provider
|
|
3
|
+
* (`createFalEngine`, `createOpenRouterEngine`, `mockEngine`, or your own)
|
|
4
|
+
* implements, and the one `useComposer` calls. One call = one model run:
|
|
5
|
+
* a prompt plus any attached media in, one piece of output back.
|
|
6
|
+
*
|
|
7
|
+
* `mockEngine` stands in for a real model API during prototyping: it
|
|
8
|
+
* "generates" a small deterministic placeholder image without any network
|
|
9
|
+
* call or API key. Swap in a real engine without touching any component —
|
|
10
|
+
* that's the whole point of keeping this behind an interface.
|
|
11
|
+
*/
|
|
12
|
+
/** The error an engine rejects with when its `signal` was aborted. */
|
|
13
|
+
export function abortError() {
|
|
14
|
+
return new DOMException("The request was cancelled.", "AbortError");
|
|
15
|
+
}
|
|
16
|
+
/** True for an `AbortError`, the way an engine reports a cancelled call. */
|
|
17
|
+
export function isAbortError(err) {
|
|
18
|
+
return typeof err === "object" && err !== null && err.name === "AbortError";
|
|
19
|
+
}
|
|
20
|
+
/** Resolves after `ms`, or rejects with an `AbortError` as soon as `signal` aborts. */
|
|
21
|
+
export function abortableSleep(ms, signal) {
|
|
22
|
+
return new Promise((resolve, reject) => {
|
|
23
|
+
if (signal?.aborted)
|
|
24
|
+
return reject(abortError());
|
|
25
|
+
const timer = setTimeout(() => {
|
|
26
|
+
signal?.removeEventListener("abort", onAbort);
|
|
27
|
+
resolve();
|
|
28
|
+
}, ms);
|
|
29
|
+
const onAbort = () => {
|
|
30
|
+
clearTimeout(timer);
|
|
31
|
+
reject(abortError());
|
|
32
|
+
};
|
|
33
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Thrown by a `GenerationEngine` to fail a call with structured,
|
|
38
|
+
* user-facing content — `reasons` can render as a bullet list, `message`
|
|
39
|
+
* alone as a single sentence. A real engine should unwrap its provider's
|
|
40
|
+
* specific error into this shape rather than let a bare network/HTTP error
|
|
41
|
+
* reach the UI.
|
|
42
|
+
*/
|
|
43
|
+
export class GenerationError extends Error {
|
|
44
|
+
constructor(message, reasons) {
|
|
45
|
+
super(message);
|
|
46
|
+
this.name = "GenerationError";
|
|
47
|
+
this.reasons = reasons;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Reads the top-level `evaluations` field a builder's backend proxy
|
|
52
|
+
* appended to a provider response, the convention both built-in engines
|
|
53
|
+
* follow. Malformed entries are dropped rather than rendered as verdicts
|
|
54
|
+
* nobody actually returned.
|
|
55
|
+
*/
|
|
56
|
+
export function readEvaluations(json) {
|
|
57
|
+
const raw = json?.evaluations;
|
|
58
|
+
if (!Array.isArray(raw))
|
|
59
|
+
return undefined;
|
|
60
|
+
const valid = raw.filter((e) => !!e && typeof e.id === "string" && typeof e.label === "string" && typeof e.passed === "boolean");
|
|
61
|
+
return valid.length ? valid.map(({ id, label, passed }) => ({ id, label, passed })) : undefined;
|
|
62
|
+
}
|
|
63
|
+
/** Turns anything an engine threw into the `{ message, reasons }` shape a `Result`'s `error` holds. */
|
|
64
|
+
export function normalizeGenerationError(err) {
|
|
65
|
+
if (err instanceof GenerationError) {
|
|
66
|
+
return { message: err.message, reasons: err.reasons };
|
|
67
|
+
}
|
|
68
|
+
if (err instanceof Error)
|
|
69
|
+
return { message: err.message };
|
|
70
|
+
return { message: "Something went wrong. Please try again." };
|
|
71
|
+
}
|
|
72
|
+
function hash(input) {
|
|
73
|
+
let h = 0;
|
|
74
|
+
for (let i = 0; i < input.length; i++) {
|
|
75
|
+
h = (h << 5) - h + input.charCodeAt(i);
|
|
76
|
+
h |= 0;
|
|
77
|
+
}
|
|
78
|
+
return Math.abs(h);
|
|
79
|
+
}
|
|
80
|
+
function placeholderSvg(seed, caption) {
|
|
81
|
+
const h = hash(seed);
|
|
82
|
+
const hue = h % 360;
|
|
83
|
+
const hue2 = (hue + 40 + (h % 60)) % 360;
|
|
84
|
+
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="480" height="360">
|
|
85
|
+
<defs>
|
|
86
|
+
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
|
|
87
|
+
<stop offset="0%" stop-color="hsl(${hue} 55% 38%)" />
|
|
88
|
+
<stop offset="100%" stop-color="hsl(${hue2} 60% 24%)" />
|
|
89
|
+
</linearGradient>
|
|
90
|
+
</defs>
|
|
91
|
+
<rect width="480" height="360" fill="url(#g)" />
|
|
92
|
+
<text x="24" y="332" font-family="ui-monospace, monospace" font-size="13" fill="rgba(255,255,255,0.85)">${escapeXml(caption)}</text>
|
|
93
|
+
</svg>`;
|
|
94
|
+
return `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`;
|
|
95
|
+
}
|
|
96
|
+
function escapeXml(s) {
|
|
97
|
+
return s.replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c] ?? c);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* A plausible text reply for a text-output mock (e.g. standing in for a
|
|
101
|
+
* reasoning/vision model) — still not a real model call, just a more
|
|
102
|
+
* honest stand-in than a gradient image would be.
|
|
103
|
+
*/
|
|
104
|
+
function mockText(prompt, modelId) {
|
|
105
|
+
const stylePhrases = [
|
|
106
|
+
"warm, diffused daylight",
|
|
107
|
+
"a shallow depth of field",
|
|
108
|
+
"muted, desaturated tones",
|
|
109
|
+
"a centered, symmetrical composition",
|
|
110
|
+
"soft shadows and high contrast",
|
|
111
|
+
];
|
|
112
|
+
const subjectPhrases = [
|
|
113
|
+
"a single object resting on a plain surface",
|
|
114
|
+
"a figure positioned slightly off-center",
|
|
115
|
+
"an outdoor scene with layered depth",
|
|
116
|
+
"a close-up study of texture and material",
|
|
117
|
+
];
|
|
118
|
+
const style = stylePhrases[hash(modelId + "style") % stylePhrases.length];
|
|
119
|
+
const subject = subjectPhrases[hash(modelId + "subject") % subjectPhrases.length];
|
|
120
|
+
const detail = prompt.includes("detailed")
|
|
121
|
+
? " Rendered here with extra material and lighting detail, per the requested length."
|
|
122
|
+
: "";
|
|
123
|
+
return `${subject}, shot with ${style}.${detail} (mock — ${modelId})`;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* A plausible, deterministic-per-call token/cost fabrication, so a demo can
|
|
127
|
+
* show usage without a real tokenizer or pricing API. `costUsd` uses an
|
|
128
|
+
* illustrative, not verified, rate — a real engine should only ever report
|
|
129
|
+
* a cost it actually derived from real pricing.
|
|
130
|
+
*/
|
|
131
|
+
function mockUsage(seed) {
|
|
132
|
+
const promptTokens = 180 + (hash(seed + "prompt") % 420);
|
|
133
|
+
const completionTokens = 40 + (hash(seed + "completion") % 260);
|
|
134
|
+
const illustrativeRatePerMillion = { input: 0.15, output: 0.6 };
|
|
135
|
+
const costUsd = (promptTokens * illustrativeRatePerMillion.input +
|
|
136
|
+
completionTokens * illustrativeRatePerMillion.output) /
|
|
137
|
+
1_000_000;
|
|
138
|
+
return { promptTokens, completionTokens, totalTokens: promptTokens + completionTokens, costUsd };
|
|
139
|
+
}
|
|
140
|
+
let mockCallCount = 0;
|
|
141
|
+
export function createMockEngine(options = {}) {
|
|
142
|
+
const outputKind = options.outputKind ?? "image";
|
|
143
|
+
const failureRate = options.failureRate ?? 0;
|
|
144
|
+
return {
|
|
145
|
+
async generate({ modelId = "mock-model", prompt, onText, signal }) {
|
|
146
|
+
mockCallCount += 1;
|
|
147
|
+
const seed = `${modelId}:${prompt}:${mockCallCount}`;
|
|
148
|
+
await abortableSleep(500 + (hash(seed) % 1200), signal);
|
|
149
|
+
if (failureRate > 0 && (hash(seed) % 100) / 100 < failureRate) {
|
|
150
|
+
throw new GenerationError("Generation failed", [
|
|
151
|
+
"The model could not complete this request.",
|
|
152
|
+
"Try again, or select a different model.",
|
|
153
|
+
]);
|
|
154
|
+
}
|
|
155
|
+
if (outputKind === "text") {
|
|
156
|
+
const text = mockText(prompt, modelId);
|
|
157
|
+
if (onText) {
|
|
158
|
+
// Word by word, so a streaming UI has something real to render.
|
|
159
|
+
const words = text.split(" ");
|
|
160
|
+
for (let i = 1; i <= words.length; i++) {
|
|
161
|
+
onText(words.slice(0, i).join(" "));
|
|
162
|
+
await abortableSleep(60, signal);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return { src: text, kind: "text", usage: mockUsage(seed) };
|
|
166
|
+
}
|
|
167
|
+
const caption = `${modelId} · ${prompt.slice(0, 48)}${prompt.length > 48 ? "…" : ""}`;
|
|
168
|
+
return { src: placeholderSvg(`${modelId}:${prompt}`, caption), kind: "image", usage: mockUsage(seed) };
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
export const mockEngine = createMockEngine();
|
|
173
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A real `GenerationEngine` backed by Fal.ai (fal.ai) — CHAI's default
|
|
3
|
+
* model marketplace as of 2026-09-24, chosen for the
|
|
4
|
+
* text/image-to-video and audio-generation coverage OpenRouter lacks.
|
|
5
|
+
* OpenRouter remains a fully-supported alternative, not deprecated by
|
|
6
|
+
* this — see the Develop page's "Model providers" section.
|
|
7
|
+
*
|
|
8
|
+
* Handles media generation only: produces real image/video media via Fal's
|
|
9
|
+
* queue API (submit → poll → fetch result). Fal's own vision/LLM access
|
|
10
|
+
* (`any-llm`, `any-llm/vision`) is itself a proxy in front of OpenRouter,
|
|
11
|
+
* not an independent catalog — for text/reasoning calls
|
|
12
|
+
* (e.g. prompt enhancement, media analysis) use `createOpenRouterEngine`
|
|
13
|
+
* instead of routing through Fal to OpenRouter.
|
|
14
|
+
*
|
|
15
|
+
* Security: this engine never sees an API key and never calls
|
|
16
|
+
* `queue.fal.run` directly. It calls a same-origin `endpoint` (default
|
|
17
|
+
* `/api/chai/fal`, served by `createChaiHandler`) that a server-side proxy owns and mirrors Fal's own queue
|
|
18
|
+
* URL shape (`/{model}`, `/{model}/requests/{id}/status`,
|
|
19
|
+
* `/{model}/requests/{id}`) — the proxy is the only thing that reads
|
|
20
|
+
* `FAL_KEY` and attaches the `Authorization: Key ...` header. Passing a
|
|
21
|
+
* key into this file would put it in the browser bundle; don't add one.
|
|
22
|
+
*/
|
|
23
|
+
import { type GenerationEngine } from "../engine.js";
|
|
24
|
+
import type { DroppedMedia, MediaKind } from "../types.js";
|
|
25
|
+
/** Output kinds this engine can produce — text goes through a reasoning engine instead (see file doc comment). */
|
|
26
|
+
type FalOutputKind = Exclude<MediaKind, "text">;
|
|
27
|
+
export interface FalEngineOptions {
|
|
28
|
+
/** Same-origin proxy path that attaches the real key server-side and mirrors Fal's queue URL shape. */
|
|
29
|
+
endpoint?: string;
|
|
30
|
+
/** Fal model id to call when the caller passes no `modelId` and no `modelByKind` entry matches `outputKind`. */
|
|
31
|
+
model?: string;
|
|
32
|
+
/** Per-output-kind Fal model id override — e.g. `{ image: "fal-ai/flux/schnell", video: "minimax/h3-max/text-to-video" }`. */
|
|
33
|
+
modelByKind?: Partial<Record<FalOutputKind, string>>;
|
|
34
|
+
/** Which kind of media this engine instance produces. Defaults to "image". */
|
|
35
|
+
outputKind?: FalOutputKind;
|
|
36
|
+
/** Poll interval while a queued job is in progress. Defaults to 1500ms. */
|
|
37
|
+
pollIntervalMs?: number;
|
|
38
|
+
/** Give up waiting after this long. Defaults to 120000ms (2 min) — video/audio jobs run longer than image ones. */
|
|
39
|
+
timeoutMs?: number;
|
|
40
|
+
/** Injectable for tests; defaults to the global `fetch`. */
|
|
41
|
+
fetchImpl?: typeof fetch;
|
|
42
|
+
}
|
|
43
|
+
interface FalResultResponse {
|
|
44
|
+
images?: {
|
|
45
|
+
url: string;
|
|
46
|
+
}[];
|
|
47
|
+
video?: {
|
|
48
|
+
url: string;
|
|
49
|
+
};
|
|
50
|
+
audio?: {
|
|
51
|
+
url: string;
|
|
52
|
+
};
|
|
53
|
+
audio_url?: string;
|
|
54
|
+
error?: unknown;
|
|
55
|
+
detail?: unknown;
|
|
56
|
+
}
|
|
57
|
+
/** Fal's error shape varies by failure type — validation errors carry `detail`, job failures carry `error`. Prefer whichever is present and stringify a non-string one. */
|
|
58
|
+
export declare function describeFalError(json: {
|
|
59
|
+
error?: unknown;
|
|
60
|
+
detail?: unknown;
|
|
61
|
+
}, fallback: string): string;
|
|
62
|
+
/** Builds the one Fal request body CHAI sends — a prompt, plus an `image_url` when an attached image is available (for image-to-video / edit-shaped models). */
|
|
63
|
+
export declare function buildFalRequestBody(args: {
|
|
64
|
+
prompt: string;
|
|
65
|
+
media?: DroppedMedia;
|
|
66
|
+
}): Record<string, unknown>;
|
|
67
|
+
/** Pulls the generated media URL out of Fal's result JSON for the given output kind — the response shape differs by modality. */
|
|
68
|
+
export declare function extractFalResultSrc(json: FalResultResponse, kind: FalOutputKind): string | undefined;
|
|
69
|
+
/**
|
|
70
|
+
* A media-generation `GenerationEngine` — submits the prompt (plus the
|
|
71
|
+
* first attached image, if any) to Fal's queue API and polls until the job
|
|
72
|
+
* completes, returning the real generated `src` URL. Calls the caller's
|
|
73
|
+
* `modelId` when given, otherwise `modelByKind`/`model`/the built-in default.
|
|
74
|
+
*/
|
|
75
|
+
export declare function createFalEngine(options?: FalEngineOptions): GenerationEngine;
|
|
76
|
+
/**
|
|
77
|
+
* A minimal, cheap connectivity check against Fal's fastest image model —
|
|
78
|
+
* the "use real inference sparingly" path, same role as `pingOpenRouter`.
|
|
79
|
+
* Deliberately not a `GenerationEngine` and not exercised by any automated
|
|
80
|
+
* test: meant to be triggered once, by a person, from the Develop page's
|
|
81
|
+
* "Test connection" button.
|
|
82
|
+
*/
|
|
83
|
+
export declare function pingFal(options?: {
|
|
84
|
+
endpoint?: string;
|
|
85
|
+
model?: string;
|
|
86
|
+
fetchImpl?: typeof fetch;
|
|
87
|
+
}): Promise<{
|
|
88
|
+
ok: true;
|
|
89
|
+
src: string;
|
|
90
|
+
} | {
|
|
91
|
+
ok: false;
|
|
92
|
+
error: string;
|
|
93
|
+
}>;
|
|
94
|
+
export {};
|
|
95
|
+
//# sourceMappingURL=fal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fal.d.ts","sourceRoot":"","sources":["../../src/engines/fal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAA6D,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChH,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE3D,kHAAkH;AAClH,KAAK,aAAa,GAAG,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;AAEhD,MAAM,WAAW,gBAAgB;IAC/B,uGAAuG;IACvG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gHAAgH;IAChH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8HAA8H;IAC9H,WAAW,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC;IACrD,8EAA8E;IAC9E,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,2EAA2E;IAC3E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mHAAmH;IACnH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AA6BD,UAAU,iBAAiB;IACzB,MAAM,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACxB,KAAK,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAGD,2KAA2K;AAC3K,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAStG;AAED,gKAAgK;AAChK,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAI1B;AAED,iIAAiI;AACjI,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,aAAa,GAAG,MAAM,GAAG,SAAS,CAIpG;AA0DD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,GAAE,gBAAqB,GAAG,gBAAgB,CAyDhF;AAED;;;;;;GAMG;AACH,wBAAsB,OAAO,CAC3B,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CAAO,GAC5E,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CA4BnE"}
|