@chai-ui/core 0.6.0 → 0.7.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 +10 -5
- package/dist/composer-view.d.ts +93 -0
- package/dist/composer-view.d.ts.map +1 -0
- package/dist/composer-view.js +142 -0
- package/dist/composer-view.js.map +1 -0
- package/dist/composer.d.ts +188 -0
- package/dist/composer.d.ts.map +1 -0
- package/dist/composer.js +326 -0
- package/dist/composer.js.map +1 -0
- package/dist/edit-card.d.ts +53 -0
- package/dist/edit-card.d.ts.map +1 -0
- package/dist/edit-card.js +119 -0
- package/dist/edit-card.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/media-actions.d.ts +19 -0
- package/dist/media-actions.d.ts.map +1 -0
- package/dist/media-actions.js +57 -0
- package/dist/media-actions.js.map +1 -0
- package/dist/media-analyzer.d.ts +101 -0
- package/dist/media-analyzer.d.ts.map +1 -0
- package/dist/media-analyzer.js +215 -0
- package/dist/media-analyzer.js.map +1 -0
- package/dist/reasoning.d.ts +59 -0
- package/dist/reasoning.d.ts.map +1 -0
- package/dist/reasoning.js +55 -0
- package/dist/reasoning.js.map +1 -0
- package/dist/region-edit.d.ts +2 -0
- package/dist/region-edit.d.ts.map +1 -1
- package/dist/region-edit.js +6 -0
- package/dist/region-edit.js.map +1 -1
- package/dist/result-format.d.ts +11 -0
- package/dist/result-format.d.ts.map +1 -0
- package/dist/result-format.js +30 -0
- package/dist/result-format.js.map +1 -0
- package/dist/unique-id.d.ts +3 -0
- package/dist/unique-id.d.ts.map +1 -0
- package/dist/unique-id.js +7 -0
- package/dist/unique-id.js.map +1 -0
- package/package.json +2 -1
- package/src/composer-view.ts +222 -0
- package/src/composer.ts +525 -0
- package/src/edit-card.ts +138 -0
- package/src/index.ts +7 -0
- package/src/media-actions.ts +55 -0
- package/src/media-analyzer.ts +293 -0
- package/src/reasoning.ts +90 -0
- package/src/region-edit.ts +8 -0
- package/src/result-format.ts +34 -0
- package/src/unique-id.ts +6 -0
package/README.md
CHANGED
|
@@ -14,9 +14,10 @@
|
|
|
14
14
|
|
|
15
15
|
The headless core behind CHAI's components: the data types, the
|
|
16
16
|
Request → Run → Result model a submitted prompt flows through, and the
|
|
17
|
-
pluggable generation engines that actually call models
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
pluggable generation engines that actually call models, and the components'
|
|
18
|
+
behavior as small framework-free stores. No framework, no rendering:
|
|
19
|
+
`@chai-ui/react` wraps the stores in hooks, and a Vue binding will wrap the
|
|
20
|
+
same stores.
|
|
20
21
|
|
|
21
22
|
## Layout
|
|
22
23
|
|
|
@@ -29,6 +30,9 @@ binding would depend on this package the same way.
|
|
|
29
30
|
- `suggested-models.ts` — the suggested model lists per use case (Fal for generation, OpenRouter for analysis), each model with its verified aspect ratios and Fal input format; `suggestedModels(useCase)`.
|
|
30
31
|
- `check-suggested-models.ts` — `checkSuggestedModels()`: checks those lists against Fal's and OpenRouter's catalogs as they are today. No key, no model run.
|
|
31
32
|
- `model-routing.ts` — auto-select: `buildModelRoutingPrompt`, `parseModelRoutingReply`, and `routeModel`, which falls back to the first listed model instead of throwing.
|
|
33
|
+
- `reasoning.ts` — the reasoning engine and models a `ChaiProvider` shares: `createReasoning`, `pickReasoning`, `reasoningModelFor` and the suggested defaults.
|
|
34
|
+
- `composer.ts` — `createComposerStore`, what `useComposer` wraps: submit payload → runs, auto-select routing, Enhance, cancel, and image edit versions. Plus the Composer's shared types (`ComposerSubmitPayload`, `EditVersion`, …).
|
|
35
|
+
- `media-analyzer.ts` — `createMediaAnalyzerStore`, what `useMediaAnalyzer` wraps.
|
|
32
36
|
- `server/` — `createChaiHandler` and `toNodeHandler`, exported from `@chai-ui/core/server` (server-only).
|
|
33
37
|
|
|
34
38
|
## Suggested models, and checking them
|
|
@@ -73,8 +77,8 @@ Set `FAL_KEY` and `OPENROUTER_API_KEY` in the server's environment (never
|
|
|
73
77
|
with a `VITE_` or `NEXT_PUBLIC_` prefix). A missing key comes back as a
|
|
74
78
|
clear error, e.g. "FAL_KEY isn't set on the server."
|
|
75
79
|
|
|
76
|
-
**Where it runs.**
|
|
77
|
-
|
|
80
|
+
**Where it runs.** The route lives in your app's framework (React or Vue)
|
|
81
|
+
or on the API server behind it. Mount it at
|
|
78
82
|
`/api/chai`, where the components send their requests. `handle(request)`
|
|
79
83
|
takes a standard web `Request` and returns a `Response`; `GET`, `POST` and
|
|
80
84
|
`PUT` (Fal's cancel call) are the same function. When the browser
|
|
@@ -84,6 +88,7 @@ disconnects, the provider call is aborted too.
|
|
|
84
88
|
|---|---|
|
|
85
89
|
| Next.js (App Router) | `export const { GET, POST, PUT } = createChaiHandler();` in `app/api/chai/[...path]/route.ts` |
|
|
86
90
|
| Remix / React Router | `export const loader = ({ request }) => chai.handle(request); export const action = loader;` in `app/routes/api.chai.$.ts` |
|
|
91
|
+
| Nuxt | `export default defineEventHandler((event) => chai.handle(toWebRequest(event)));` in `server/api/chai/[...path].ts` |
|
|
87
92
|
| Hono | `app.all("/api/chai/*", (c) => chai.handle(c.req.raw))` |
|
|
88
93
|
| Bun, Deno | route `/api/chai/*` to `chai.handle` in `Bun.serve` / `Deno.serve` |
|
|
89
94
|
| Cloudflare Workers | `createChaiHandler({ falKey: env.FAL_KEY, openRouterKey: env.OPENROUTER_API_KEY }).handle(request)` |
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the Composer component shows and submits, worked out from its props:
|
|
3
|
+
* the same in every framework binding. Pure; nothing here renders.
|
|
4
|
+
*/
|
|
5
|
+
import type { ComposerAttachment, ComposerSubmitPayload, ComposerUseCase } from "./composer.js";
|
|
6
|
+
import type { EditRegion } from "./region-edit.js";
|
|
7
|
+
import type { MediaKind, ModelOption, ParameterOption } from "./types.js";
|
|
8
|
+
export type ComposerAttachMenuAction = "add-media" | "create-image" | "create-video" | "edit-media";
|
|
9
|
+
/** The `+` menu, in order. "Add media" is the only item with a divider after it. */
|
|
10
|
+
export declare const COMPOSER_ATTACH_MENU_ITEMS: {
|
|
11
|
+
action: ComposerAttachMenuAction;
|
|
12
|
+
label: string;
|
|
13
|
+
divider?: boolean;
|
|
14
|
+
}[];
|
|
15
|
+
/**
|
|
16
|
+
* Past this length a rewritten prompt appears at once: a long reveal reads
|
|
17
|
+
* as sluggish, and a long prompt is when a person wants the result now.
|
|
18
|
+
*/
|
|
19
|
+
export declare const MAX_ANIMATE_ENHANCE_LENGTH = 260;
|
|
20
|
+
/** How long the Enhance reveal takes: time-driven, between 300ms and 900ms. */
|
|
21
|
+
export declare function enhanceRevealDurationMs(charCount: number): number;
|
|
22
|
+
/** The Composer props `composerView` reads. Callbacks only matter by being there. */
|
|
23
|
+
export interface ComposerViewInput {
|
|
24
|
+
value: string;
|
|
25
|
+
placeholder?: string;
|
|
26
|
+
attachments?: ComposerAttachment[];
|
|
27
|
+
useCase?: ComposerUseCase | null;
|
|
28
|
+
defaultUseCase?: ComposerUseCase;
|
|
29
|
+
multiSelectUseCases?: boolean;
|
|
30
|
+
useCases?: ComposerUseCase[];
|
|
31
|
+
modelsByKind?: Partial<Record<MediaKind, ModelOption[]>>;
|
|
32
|
+
multiSelectModels?: boolean;
|
|
33
|
+
modelIds?: string[];
|
|
34
|
+
models?: ModelOption[];
|
|
35
|
+
modelId?: string | null;
|
|
36
|
+
onModelChange?: unknown;
|
|
37
|
+
onModelIdsChange?: unknown;
|
|
38
|
+
autoSelectModel?: boolean;
|
|
39
|
+
aspectRatios?: ParameterOption<string>[];
|
|
40
|
+
aspectRatio?: string | null;
|
|
41
|
+
submitError?: string | null;
|
|
42
|
+
submitDisabled?: boolean;
|
|
43
|
+
submitting?: boolean;
|
|
44
|
+
onAbort?: unknown;
|
|
45
|
+
regions?: EditRegion[];
|
|
46
|
+
disabled?: boolean;
|
|
47
|
+
}
|
|
48
|
+
export declare function composerView(props: ComposerViewInput): {
|
|
49
|
+
pickedUseCases: ComposerUseCase[];
|
|
50
|
+
activeUseCases: ComposerUseCase[];
|
|
51
|
+
editing: boolean;
|
|
52
|
+
isSubmitDisabled: boolean;
|
|
53
|
+
placeholder: string;
|
|
54
|
+
showStop: boolean;
|
|
55
|
+
multiModel: boolean;
|
|
56
|
+
modelSections: {
|
|
57
|
+
options: ModelOption[];
|
|
58
|
+
suggested: boolean;
|
|
59
|
+
label: string;
|
|
60
|
+
kind: MediaKind;
|
|
61
|
+
}[];
|
|
62
|
+
pickedModelIds: string[];
|
|
63
|
+
canPickModel: boolean;
|
|
64
|
+
modelTriggerLabel: string;
|
|
65
|
+
showAspectRatio: boolean;
|
|
66
|
+
aspectOptions: ParameterOption<string>[];
|
|
67
|
+
offeredAspect: string | null;
|
|
68
|
+
selectedAspect: ParameterOption<string> | null;
|
|
69
|
+
/** The model ids after a row click: the one picked, or with multi-select that one toggled. */
|
|
70
|
+
toggledModelIds: (id: string) => string[];
|
|
71
|
+
/** Everything a submit sends. */
|
|
72
|
+
payload: () => ComposerSubmitPayload;
|
|
73
|
+
};
|
|
74
|
+
export type ComposerView = ReturnType<typeof composerView>;
|
|
75
|
+
/** The `+` menu items that can work: "Add media" needs somewhere to put files, the use-case items a handler. */
|
|
76
|
+
export declare function composerAttachMenuItems(actions: ComposerAttachMenuAction[] | undefined, { canAddMedia, canSelect }: {
|
|
77
|
+
canAddMedia: boolean;
|
|
78
|
+
canSelect: boolean;
|
|
79
|
+
}): {
|
|
80
|
+
action: ComposerAttachMenuAction;
|
|
81
|
+
label: string;
|
|
82
|
+
divider?: boolean;
|
|
83
|
+
}[];
|
|
84
|
+
/**
|
|
85
|
+
* The attachments after picking files: each image, video or audio file
|
|
86
|
+
* added in the order picked. Editing works on one image, so its first image
|
|
87
|
+
* replaces what's there (and with none, every file is unsupported).
|
|
88
|
+
*/
|
|
89
|
+
export declare function composerAttachmentsFromFiles(files: Iterable<File>, current: ComposerAttachment[], editing: boolean): Promise<{
|
|
90
|
+
attachments: ComposerAttachment[] | null;
|
|
91
|
+
unsupported: string[];
|
|
92
|
+
}>;
|
|
93
|
+
//# sourceMappingURL=composer-view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composer-view.d.ts","sourceRoot":"","sources":["../src/composer-view.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { uniqueId } from "./unique-id.js";
|
|
2
|
+
import { TEXT_USE_CASE } from "./composer.js";
|
|
3
|
+
import { readMediaFiles } from "./media-analyzer.js";
|
|
4
|
+
import { deriveGenerationUseCase } from "./run.js";
|
|
5
|
+
import { suggestedModels } from "./suggested-models.js";
|
|
6
|
+
/** The `+` menu, in order. "Add media" is the only item with a divider after it. */
|
|
7
|
+
export const COMPOSER_ATTACH_MENU_ITEMS = [
|
|
8
|
+
{ action: "add-media", label: "Add media", divider: true },
|
|
9
|
+
{ action: "create-image", label: "Create image" },
|
|
10
|
+
{ action: "create-video", label: "Create video" },
|
|
11
|
+
{ action: "edit-media", label: "Edit image" },
|
|
12
|
+
];
|
|
13
|
+
/**
|
|
14
|
+
* Past this length a rewritten prompt appears at once: a long reveal reads
|
|
15
|
+
* as sluggish, and a long prompt is when a person wants the result now.
|
|
16
|
+
*/
|
|
17
|
+
export const MAX_ANIMATE_ENHANCE_LENGTH = 260;
|
|
18
|
+
/** How long the Enhance reveal takes: time-driven, between 300ms and 900ms. */
|
|
19
|
+
export function enhanceRevealDurationMs(charCount) {
|
|
20
|
+
return Math.min(900, Math.max(300, charCount * 6));
|
|
21
|
+
}
|
|
22
|
+
export function composerView(props) {
|
|
23
|
+
const { value, attachments = [], useCase = null, defaultUseCase = TEXT_USE_CASE, multiSelectUseCases = false, useCases = [], modelsByKind, multiSelectModels = false, modelIds = [], models, modelId = null, autoSelectModel = false, aspectRatios, aspectRatio = null, submitError = null, submitting = false, regions = [], disabled = false, } = props;
|
|
24
|
+
// What the person picked, and what actually runs: with nothing picked, the
|
|
25
|
+
// builder's default use case (a text request unless they chose otherwise).
|
|
26
|
+
const pickedUseCases = multiSelectUseCases ? useCases : useCase ? [useCase] : [];
|
|
27
|
+
const activeUseCases = pickedUseCases.length > 0 ? pickedUseCases : [defaultUseCase];
|
|
28
|
+
// An edit needs an image, then a change: a prompt for the whole image, a
|
|
29
|
+
// region with its own instruction, or both.
|
|
30
|
+
const editing = activeUseCases.some((u) => u.edit);
|
|
31
|
+
const hasImage = attachments.some((a) => a.kind === "image");
|
|
32
|
+
const hasContent = editing
|
|
33
|
+
? hasImage && (value.trim().length > 0 || regions.length > 0)
|
|
34
|
+
: value.trim().length > 0 || attachments.length > 0;
|
|
35
|
+
const isSubmitDisabled = submitError ? disabled : (props.submitDisabled ?? (disabled || !hasContent));
|
|
36
|
+
const placeholder = props.placeholder ??
|
|
37
|
+
(editing
|
|
38
|
+
? hasImage
|
|
39
|
+
? "Describe a change across the whole image, or leave this empty"
|
|
40
|
+
: "Attach an image to edit"
|
|
41
|
+
: "Describe media to create");
|
|
42
|
+
// The stop icon only appears with somewhere for its click to go.
|
|
43
|
+
const showStop = submitting && Boolean(props.onAbort);
|
|
44
|
+
const multiModel = multiSelectModels || multiSelectUseCases;
|
|
45
|
+
const rawPickedIds = multiModel ? modelIds : modelId ? [modelId] : [];
|
|
46
|
+
// The app's list for a use case, or Chai's suggested models when it gave none.
|
|
47
|
+
const rosterFor = (u) => {
|
|
48
|
+
const given = multiSelectUseCases ? modelsByKind?.[u.kind] : models;
|
|
49
|
+
if (given)
|
|
50
|
+
return { options: given, suggested: false };
|
|
51
|
+
return { options: suggestedModels(u.edit ? "image-edit" : deriveGenerationUseCase(u, attachments)), suggested: true };
|
|
52
|
+
};
|
|
53
|
+
// One menu section per use case with multi-use-case select; otherwise one flat roster.
|
|
54
|
+
const modelSections = (multiSelectUseCases ? activeUseCases : activeUseCases.slice(0, 1))
|
|
55
|
+
.map((u) => ({ label: multiSelectUseCases ? u.label : "", kind: u.kind, ...rosterFor(u) }))
|
|
56
|
+
.filter((s) => s.options.length > 0);
|
|
57
|
+
const allModels = modelSections.flatMap((s) => s.options);
|
|
58
|
+
// A pick that isn't in the current list (e.g. the edit model after leaving
|
|
59
|
+
// edit mode) is shown as unpicked and never submitted. With no list at
|
|
60
|
+
// all, the app's pick is passed through as given. With nothing picked
|
|
61
|
+
// from a suggested list (and auto-select off), its first model is the pick.
|
|
62
|
+
const validPicks = allModels.length > 0 ? rawPickedIds.filter((id) => allModels.some((m) => m.id === id)) : rawPickedIds;
|
|
63
|
+
const pickedModelIds = validPicks.length > 0 || autoSelectModel ? validPicks : modelSections.filter((s) => s.suggested).map((s) => s.options[0].id);
|
|
64
|
+
const pickedModels = allModels.filter((m) => pickedModelIds.includes(m.id));
|
|
65
|
+
// No menu that can't change anything: without its handler, the Model menu hides (the default pick still runs).
|
|
66
|
+
const canPickModel = Boolean(multiModel ? props.onModelIdsChange : props.onModelChange);
|
|
67
|
+
const modelTriggerLabel = pickedModels.length > 1
|
|
68
|
+
? `${pickedModels.length} models`
|
|
69
|
+
: (pickedModels[0]?.label ?? (autoSelectModel ? "Auto-select" : "Select models"));
|
|
70
|
+
// An edit keeps the source image's shape.
|
|
71
|
+
const showAspectRatio = activeUseCases.some((u) => !u.edit && (u.kind === "image" || u.kind === "video"));
|
|
72
|
+
// Only ratios every model that might run takes: the picked ones, or with
|
|
73
|
+
// none picked (or auto-select on) the whole list, so whichever runs can
|
|
74
|
+
// honor it. A model with no `aspectRatios` sets its own shape: no menu.
|
|
75
|
+
const ratioModels = pickedModels.length > 0 && !autoSelectModel ? pickedModels : allModels;
|
|
76
|
+
const sharedRatios = ratioModels.reduce((shared, m) => (shared ?? m.aspectRatios ?? []).filter((r) => m.aspectRatios?.includes(r)), null) ??
|
|
77
|
+
[];
|
|
78
|
+
const aspectOptions = aspectRatios
|
|
79
|
+
? aspectRatios.filter((o) => sharedRatios.includes(o.value))
|
|
80
|
+
: sharedRatios.map((r) => ({ value: r, label: r }));
|
|
81
|
+
// A pick the current models don't take is shown as unpicked and never sent.
|
|
82
|
+
const offeredAspect = showAspectRatio && aspectOptions.some((o) => o.value === aspectRatio) ? aspectRatio : null;
|
|
83
|
+
const selectedAspect = aspectOptions.find((o) => o.value === offeredAspect) ?? null;
|
|
84
|
+
const selections = () => activeUseCases.map((u) => ({
|
|
85
|
+
useCase: u,
|
|
86
|
+
models: rosterFor(u).options,
|
|
87
|
+
modelIds: multiSelectUseCases ? pickedModelIds.filter((id) => rosterFor(u).options.some((m) => m.id === id)) : pickedModelIds,
|
|
88
|
+
}));
|
|
89
|
+
return {
|
|
90
|
+
pickedUseCases,
|
|
91
|
+
activeUseCases,
|
|
92
|
+
editing,
|
|
93
|
+
isSubmitDisabled,
|
|
94
|
+
placeholder,
|
|
95
|
+
showStop,
|
|
96
|
+
multiModel,
|
|
97
|
+
modelSections,
|
|
98
|
+
pickedModelIds,
|
|
99
|
+
canPickModel,
|
|
100
|
+
modelTriggerLabel,
|
|
101
|
+
showAspectRatio,
|
|
102
|
+
aspectOptions,
|
|
103
|
+
offeredAspect,
|
|
104
|
+
selectedAspect,
|
|
105
|
+
/** The model ids after a row click: the one picked, or with multi-select that one toggled. */
|
|
106
|
+
toggledModelIds: (id) => (modelIds.includes(id) ? modelIds.filter((m) => m !== id) : [...modelIds, id]),
|
|
107
|
+
/** Everything a submit sends. */
|
|
108
|
+
payload: () => ({
|
|
109
|
+
value,
|
|
110
|
+
attachments,
|
|
111
|
+
useCase: activeUseCases[0],
|
|
112
|
+
modelId: pickedModelIds[0] ?? null,
|
|
113
|
+
aspectRatio: offeredAspect,
|
|
114
|
+
selections: selections(),
|
|
115
|
+
autoSelectModel,
|
|
116
|
+
regions: editing ? regions : [],
|
|
117
|
+
}),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/** The `+` menu items that can work: "Add media" needs somewhere to put files, the use-case items a handler. */
|
|
121
|
+
export function composerAttachMenuItems(actions, { canAddMedia, canSelect }) {
|
|
122
|
+
return COMPOSER_ATTACH_MENU_ITEMS.filter((item) => (actions ?? COMPOSER_ATTACH_MENU_ITEMS.map((i) => i.action)).includes(item.action) &&
|
|
123
|
+
(item.action === "add-media" ? canAddMedia : canSelect));
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* The attachments after picking files: each image, video or audio file
|
|
127
|
+
* added in the order picked. Editing works on one image, so its first image
|
|
128
|
+
* replaces what's there (and with none, every file is unsupported).
|
|
129
|
+
*/
|
|
130
|
+
export async function composerAttachmentsFromFiles(files, current, editing) {
|
|
131
|
+
const list = [...files];
|
|
132
|
+
if (editing) {
|
|
133
|
+
const image = list.find((f) => f.type.startsWith("image/"));
|
|
134
|
+
if (!image)
|
|
135
|
+
return { attachments: null, unsupported: list.map((f) => f.name) };
|
|
136
|
+
const { media, unsupported } = await readMediaFiles([image]);
|
|
137
|
+
return { attachments: media.length > 0 ? media.map((m) => ({ ...m, id: uniqueId() })) : null, unsupported };
|
|
138
|
+
}
|
|
139
|
+
const { media, unsupported } = await readMediaFiles(list);
|
|
140
|
+
return { attachments: [...current, ...media.map((m) => ({ ...m, id: uniqueId() }))], unsupported };
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=composer-view.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composer-view.js","sourceRoot":"","sources":["../src/composer-view.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Composer's behavior with no framework: turns a submit payload into
|
|
3
|
+
* `Request` → `Run` → `Result` (§6), fanning out across `engine.generate`
|
|
4
|
+
* calls and folding each one back into state as it settles. A small store
|
|
5
|
+
* (`getState` + `subscribe`) that `useComposer` (React) and the Vue
|
|
6
|
+
* composable wrap; the pure transitions live in `run.ts`.
|
|
7
|
+
*/
|
|
8
|
+
import { type GenerationEngine } from "./engine.js";
|
|
9
|
+
import { type ModelRoutingInput, type ModelRoutingResult } from "./model-routing.js";
|
|
10
|
+
import { type EditRegion } from "./region-edit.js";
|
|
11
|
+
import { type Reasoning } from "./reasoning.js";
|
|
12
|
+
import { type ResultStatus, type Run } from "./run.js";
|
|
13
|
+
import type { DroppedMedia, GenerationUseCase, MediaKind, ModelOption } from "./types.js";
|
|
14
|
+
export interface ComposerAttachment extends DroppedMedia {
|
|
15
|
+
id: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The selected generation use case, shown as a removable chip (reference:
|
|
19
|
+
* the mock's "Video"/"Image" chip) — deliberately independent of
|
|
20
|
+
* `attachments`: a use case can be picked from the attach menu with nothing
|
|
21
|
+
* attached yet (e.g. "Create video"). Composer never derives this from
|
|
22
|
+
* `attachments` itself (that's app-level policy, not a Composer opinion —
|
|
23
|
+
* the design). With none picked, `defaultUseCase` applies.
|
|
24
|
+
*/
|
|
25
|
+
export interface ComposerUseCase {
|
|
26
|
+
kind: MediaKind;
|
|
27
|
+
label: string;
|
|
28
|
+
/**
|
|
29
|
+
* An edit of the attached image rather than a new one: no aspect ratio,
|
|
30
|
+
* region chips when `regions` is set, and a submit needs only an image and
|
|
31
|
+
* either a prompt or a region. Images only for now.
|
|
32
|
+
*/
|
|
33
|
+
edit?: boolean;
|
|
34
|
+
}
|
|
35
|
+
/** A plain text request — what a submit means when no use case is picked, unless the builder sets `defaultUseCase`. */
|
|
36
|
+
export declare const TEXT_USE_CASE: ComposerUseCase;
|
|
37
|
+
/** Editing the attached image, the attach menu's "Edit image". Pair it with `useComposer`'s `editImage` and an `EditCard`. */
|
|
38
|
+
export declare const EDIT_IMAGE_USE_CASE: ComposerUseCase;
|
|
39
|
+
/** One use case to run and the models picked for it. Empty `modelIds` means the engine's default model. */
|
|
40
|
+
export interface ComposerSelection {
|
|
41
|
+
useCase: ComposerUseCase;
|
|
42
|
+
modelIds: string[];
|
|
43
|
+
/** The models offered for this use case: what auto-select routes among. */
|
|
44
|
+
models: ModelOption[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Everything Composer itself tracks, assembled into one object at submit
|
|
48
|
+
* time — an honest snapshot of the component's own state, handed to
|
|
49
|
+
* `onSubmit` so a builder doesn't have to re-derive it from five
|
|
50
|
+
* separately-controlled props they already hold.
|
|
51
|
+
*/
|
|
52
|
+
export interface ComposerSubmitPayload {
|
|
53
|
+
value: string;
|
|
54
|
+
attachments: ComposerAttachment[];
|
|
55
|
+
/** The use case to run — the picked one, or `defaultUseCase` when none is picked. The first one with `multiSelectUseCases`. */
|
|
56
|
+
useCase: ComposerUseCase;
|
|
57
|
+
/** The first picked model, or null for the engine's default. */
|
|
58
|
+
modelId: string | null;
|
|
59
|
+
aspectRatio: string | null;
|
|
60
|
+
/** Everything to run: one entry per use case with its picked models. A single entry unless `multiSelectUseCases` is on. */
|
|
61
|
+
selections: ComposerSelection[];
|
|
62
|
+
/** When true, the model is chosen at submit (`useComposer` routes among each selection's `models`), not by the picks. */
|
|
63
|
+
autoSelectModel: boolean;
|
|
64
|
+
/** An edit's marked regions, each with its own instruction. Empty unless the use case is an edit. */
|
|
65
|
+
regions?: EditRegion[];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* One version of the image being edited: the original, or the result of an
|
|
69
|
+
* edit. The composer's `edit.versions` builds these from its runs.
|
|
70
|
+
*/
|
|
71
|
+
export interface EditVersion {
|
|
72
|
+
id: string;
|
|
73
|
+
/** The image, once there is one. */
|
|
74
|
+
src?: string;
|
|
75
|
+
/** The image this version was edited from, shown under the progress spinner until `src` arrives. */
|
|
76
|
+
from?: string;
|
|
77
|
+
status: ResultStatus;
|
|
78
|
+
/** The regions this version was made with (none for the original). Shown faintly, for reference. */
|
|
79
|
+
regions: EditRegion[];
|
|
80
|
+
error?: string;
|
|
81
|
+
}
|
|
82
|
+
/** A result's `modelId` when nothing was picked: the engine runs its own default model. */
|
|
83
|
+
export declare const DEFAULT_MODEL_ID = "default";
|
|
84
|
+
export interface ComposerOptions {
|
|
85
|
+
/** The generation engine a submitted run actually calls. Defaults to `mockEngine`. */
|
|
86
|
+
engine?: GenerationEngine;
|
|
87
|
+
/**
|
|
88
|
+
* Engines per use-case kind, overriding `engine` for that kind — needed
|
|
89
|
+
* for multi-use-case select, since one Fal engine outputs one kind, e.g.
|
|
90
|
+
* `{ image: createFalEngine({ outputKind: "image" }), video: createFalEngine({ outputKind: "video" }) }`.
|
|
91
|
+
*/
|
|
92
|
+
engineByKind?: Partial<Record<MediaKind, GenerationEngine>>;
|
|
93
|
+
/**
|
|
94
|
+
* The engine for text requests (a Composer with no use case picked, or a
|
|
95
|
+
* text use case). Defaults to `reasoningEngine`, and to a mock text engine
|
|
96
|
+
* when neither is set, so a text prompt always gets a reply.
|
|
97
|
+
*/
|
|
98
|
+
textEngine?: GenerationEngine;
|
|
99
|
+
/** The model text requests use when none is picked. Defaults to the reasoning model for the attachments' kinds, then the text engine's own default. */
|
|
100
|
+
textModel?: string;
|
|
101
|
+
/**
|
|
102
|
+
* The reasoning engine Enhance calls — deliberately separate from
|
|
103
|
+
* `engine`: Fal's own text/vision access is itself an
|
|
104
|
+
* OpenRouter proxy, so defaulting Enhance to a Fal `engine` would
|
|
105
|
+
* silently double-proxy. Must return text. Set together with
|
|
106
|
+
* `reasoningModel` to override the nearest `ChaiProvider`'s pair; with
|
|
107
|
+
* neither set here nor a provider, `enhance` stays `undefined`, same
|
|
108
|
+
* shape as `Composer`'s own "omit `onEnhance` to hide the button" convention.
|
|
109
|
+
*/
|
|
110
|
+
reasoningEngine?: GenerationEngine;
|
|
111
|
+
/** Set with `reasoningEngine` to override the provider's pair; used for every kind (§5.5). */
|
|
112
|
+
reasoningModel?: string;
|
|
113
|
+
/** Overrides the instruction wrapping a raw prompt for Enhance. Defaults to a generic still/video-aware rewrite instruction. */
|
|
114
|
+
enhancePrompt?: (value: string, mode?: GenerationUseCase) => string;
|
|
115
|
+
/**
|
|
116
|
+
* Auto-select: with `autoSelectModel` on in the payload, the reasoning
|
|
117
|
+
* model picks one model per use case at submit, then these fire with the
|
|
118
|
+
* pick so the Composer's trigger shows it. Wire them to the same state as
|
|
119
|
+
* Composer's `onModelChange` / `onModelIdsChange`.
|
|
120
|
+
*/
|
|
121
|
+
onModelChange?: (modelId: string) => void;
|
|
122
|
+
onModelIdsChange?: (modelIds: string[]) => void;
|
|
123
|
+
/** Replaces the routing instruction (`buildModelRoutingPrompt`). */
|
|
124
|
+
routingPrompt?: (input: ModelRoutingInput) => string;
|
|
125
|
+
/**
|
|
126
|
+
* Fires when auto-select couldn't route and fell back to the first listed
|
|
127
|
+
* model: no reasoning model, a failed reasoning call (e.g. a bad key), or
|
|
128
|
+
* a reply naming no listed model. The request still runs.
|
|
129
|
+
*/
|
|
130
|
+
onRoutingFallback?: (result: Extract<ModelRoutingResult, {
|
|
131
|
+
status: "fallback";
|
|
132
|
+
}>) => void;
|
|
133
|
+
/**
|
|
134
|
+
* The image to edit, when the Composer's use case is an edit (e.g.
|
|
135
|
+
* `EDIT_IMAGE_USE_CASE`) and an image is attached. While it's set, `edit`
|
|
136
|
+
* returns props for an `EditCard`, and each edit's results become new
|
|
137
|
+
* versions of the image. Changing it to another image starts over.
|
|
138
|
+
*/
|
|
139
|
+
editImage?: DroppedMedia | null;
|
|
140
|
+
/** Replaces how an edit's prompt and regions become the model's prompt. Defaults to `buildRegionEditPrompt`, in the model's `regionFormat`. */
|
|
141
|
+
editPrompt?: (args: {
|
|
142
|
+
prompt: string;
|
|
143
|
+
regions: EditRegion[];
|
|
144
|
+
model?: ModelOption;
|
|
145
|
+
}) => string;
|
|
146
|
+
onRun?: (run: Run) => void;
|
|
147
|
+
onResult?: (run: Run, resultId: string) => void;
|
|
148
|
+
onError?: (run: Run, resultId: string) => void;
|
|
149
|
+
}
|
|
150
|
+
export interface ComposerState {
|
|
151
|
+
/** One run per use case submitted: a single run unless the Composer has `multiSelectUseCases` on. */
|
|
152
|
+
runs: Run[];
|
|
153
|
+
enhancing: boolean;
|
|
154
|
+
routing: boolean;
|
|
155
|
+
/** Edit mode. Each edit's runs are kept (not replaced by the next submit), since every result is a version of the image the person can page back to. */
|
|
156
|
+
editRuns: Run[];
|
|
157
|
+
regions: EditRegion[];
|
|
158
|
+
activeVersion: number;
|
|
159
|
+
/** The image the edit state belongs to. Another image starts over. */
|
|
160
|
+
editSource: string | null;
|
|
161
|
+
/** Numbers each image, so its original version has its own id and EditCard starts it clean. */
|
|
162
|
+
editImageCount: number;
|
|
163
|
+
}
|
|
164
|
+
/** Props for an `EditCard` (spread them in), and `regions` for `Composer`. */
|
|
165
|
+
export interface ComposerEdit {
|
|
166
|
+
versions: EditVersion[];
|
|
167
|
+
activeVersion: number;
|
|
168
|
+
onActiveVersionChange: (index: number) => void;
|
|
169
|
+
regions: EditRegion[];
|
|
170
|
+
onRegionsChange: (regions: EditRegion[]) => void;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* `getOptions` is read on every call, so options can change between
|
|
174
|
+
* renders; `getProvided` is the nearest provider's reasoning, if any.
|
|
175
|
+
*/
|
|
176
|
+
export declare function createComposerStore(getOptions: () => ComposerOptions, getProvided?: () => Reasoning | undefined): {
|
|
177
|
+
getState: () => ComposerState;
|
|
178
|
+
subscribe(listener: () => void): () => undefined;
|
|
179
|
+
submit: (payload: ComposerSubmitPayload) => void;
|
|
180
|
+
cancel: () => void;
|
|
181
|
+
enhance: (value: string) => Promise<string>;
|
|
182
|
+
edit: (s: ComposerState, editImage: DroppedMedia | null | undefined) => ComposerEdit | null;
|
|
183
|
+
reasoning: () => Reasoning | undefined;
|
|
184
|
+
};
|
|
185
|
+
export type ComposerStore = ReturnType<typeof createComposerStore>;
|
|
186
|
+
/** One console warning per message per page load: auto-select is on with no reasoning model to route with. */
|
|
187
|
+
export declare function warnNoReasoningOnce(consequence: string): void;
|
|
188
|
+
//# sourceMappingURL=composer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composer.d.ts","sourceRoot":"","sources":["../src/composer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAKL,KAAK,gBAAgB,EACtB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAc,KAAK,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACjG,OAAO,EAA8C,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC/F,OAAO,EAAoC,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAClF,OAAO,EAUL,KAAK,YAAY,EACjB,KAAK,GAAG,EACT,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE1F,MAAM,WAAW,kBAAmB,SAAQ,YAAY;IACtD,EAAE,EAAE,MAAM,CAAC;CACZ;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,uHAAuH;AACvH,eAAO,MAAM,aAAa,EAAE,eAAiD,CAAC;AAE9E,8HAA8H;AAC9H,eAAO,MAAM,mBAAmB,EAAE,eAAoE,CAAC;AAEvG,2GAA2G;AAC3G,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,eAAe,CAAC;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,2EAA2E;IAC3E,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAED;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,kBAAkB,EAAE,CAAC;IAClC,+HAA+H;IAC/H,OAAO,EAAE,eAAe,CAAC;IACzB,gEAAgE;IAChE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,2HAA2H;IAC3H,UAAU,EAAE,iBAAiB,EAAE,CAAC;IAChC,yHAAyH;IACzH,eAAe,EAAE,OAAO,CAAC;IACzB,qGAAqG;IACrG,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,oCAAoC;IACpC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oGAAoG;IACpG,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,YAAY,CAAC;IACrB,oGAAoG;IACpG,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,2FAA2F;AAC3F,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAE1C,MAAM,WAAW,eAAe;IAC9B,sFAAsF;IACtF,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC,CAAC;IAC5D;;;;OAIG;IACH,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,uJAAuJ;IACvJ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,gBAAgB,CAAC;IACnC,8FAA8F;IAC9F,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gIAAgI;IAChI,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,iBAAiB,KAAK,MAAM,CAAC;IACpE;;;;;OAKG;IACH,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAChD,oEAAoE;IACpE,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,MAAM,CAAC;IACrD;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,kBAAkB,EAAE;QAAE,MAAM,EAAE,UAAU,CAAA;KAAE,CAAC,KAAK,IAAI,CAAC;IAC1F;;;;;OAKG;IACH,SAAS,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAChC,+IAA+I;IAC/I,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,UAAU,EAAE,CAAC;QAAC,KAAK,CAAC,EAAE,WAAW,CAAA;KAAE,KAAK,MAAM,CAAC;IAC9F,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;IAC3B,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;CAChD;AAED,MAAM,WAAW,aAAa;IAC5B,qGAAqG;IACrG,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,wJAAwJ;IACxJ,QAAQ,EAAE,GAAG,EAAE,CAAC;IAChB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,sEAAsE;IACtE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,+FAA+F;IAC/F,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,8EAA8E;AAC9E,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,qBAAqB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,eAAe,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC;CAClD;AAmBD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,eAAe,EAAE,WAAW,GAAE,MAAM,SAAS,GAAG,SAA2B;;wBA8RzG,MAAM,IAAI;sBA1HP,qBAAqB;;qBAqFhB,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;cAqBrC,aAAa,aAAa,YAAY,GAAG,IAAI,GAAG,SAAS,KAAG,YAAY,GAAG,IAAI;;EA0BjG;AAED,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAGnE,8GAA8G;AAC9G,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,QAMtD"}
|