(DEFAULT_IMAGE_MODEL);
+ const imageModelMenu = useImageModelMenu();
useEffect(() => {
function handleChatRunning(event: Event) {
@@ -96,34 +73,6 @@ export default function CreatePage() {
window.removeEventListener("agentNative.chatRunning", handleChatRunning);
}, []);
- // Hydrate the saved image-model default so the picker reflects the user's
- // last choice across sessions.
- useEffect(() => {
- let cancelled = false;
- void readClientAppState<{ model?: string }>(IMAGE_MODEL_STATE_KEY)
- .then((state) => {
- const stored = state?.model;
- if (
- !cancelled &&
- stored &&
- IMAGE_MODEL_OPTIONS.some((option) => option.value === stored)
- ) {
- setImageModel(stored);
- }
- })
- .catch(() => {});
- return () => {
- cancelled = true;
- };
- }, []);
-
- const handleImageModelChange = useCallback((value: string) => {
- setImageModel(value);
- void writeClientAppState(IMAGE_MODEL_STATE_KEY, { model: value }).catch(
- () => {},
- );
- }, []);
-
return (
(
)}
- imageModelMenu={{
- value: imageModel,
- options: IMAGE_MODEL_OPTIONS.map((option) => ({
- value: option.value,
- label:
- "descriptorKey" in option && option.descriptorKey
- ? `${option.modelName} · ${t(option.descriptorKey)}`
- : option.modelName,
- })),
- onChange: handleImageModelChange,
- label: t("create.imageModel"),
- }}
+ imageModelMenu={imageModelMenu}
showHeader={false}
showTabBar={false}
dynamicSuggestions={false}
diff --git a/templates/assets/app/routes/library.tsx b/templates/assets/app/routes/library.tsx
index f209566d1c..ec19adbd6a 100644
--- a/templates/assets/app/routes/library.tsx
+++ b/templates/assets/app/routes/library.tsx
@@ -1,4 +1,5 @@
import {
+ AgentToggleButton,
appPath,
getBrowserTabId,
getEmbedAuthToken,
@@ -18,6 +19,10 @@ import {
createEmbeddedAppBridge,
type EmbeddedAppBridge,
} from "@agent-native/core/embedding";
+import {
+ EMBED_MODE_QUERY_PARAM,
+ EMBED_TOKEN_QUERY_PARAM,
+} from "@agent-native/core/shared";
import {
IconArrowUpRight,
IconCheck,
@@ -114,6 +119,7 @@ const ASPECT_RATIOS = ["16:9", "1:1", "9:16", "4:3", "3:4", "21:9"] as const;
const GENERATION_COUNTS = [1, 2, 3, 4, 6] as const;
const STARTER_PRESET = DEFAULT_LIBRARY_PRESETS[0];
const STARTER_LIBRARY_ID = `starter:${STARTER_PRESET.id}`;
+const MCP_APP_CHAT_BRIDGE_QUERY_PARAM = "__an_mcp_chat_bridge";
const PICKER_INLINE_SELECT_CLASS =
"h-7 w-auto min-w-0 max-w-full rounded-md border-0 bg-transparent px-1.5 py-1 text-xs font-medium text-muted-foreground shadow-none ring-offset-transparent transition hover:bg-accent/50 hover:text-foreground focus:ring-0 focus:ring-offset-0 sm:px-2 [&>svg]:ms-1 [&>svg]:size-3.5 [&>svg]:opacity-60";
type PickerMediaType = "image" | "video";
@@ -266,6 +272,24 @@ function normalizeCandidateRunIds(value: unknown): string[] | undefined {
return ids;
}
+function searchParamsEnableEmbeddedLibrary(params: URLSearchParams): boolean {
+ const embedMode = params.get(EMBED_MODE_QUERY_PARAM);
+ return (
+ params.has(EMBED_TOKEN_QUERY_PARAM) ||
+ embedMode === "1" ||
+ embedMode === "true"
+ );
+}
+
+function searchParamsRequestPicker(params: URLSearchParams): boolean {
+ const mcpChatBridge = params.get(MCP_APP_CHAT_BRIDGE_QUERY_PARAM);
+ return (
+ params.get("__an_picker") === "1" ||
+ mcpChatBridge === "1" ||
+ mcpChatBridge === "true"
+ );
+}
+
function normalizeHostConfig(value: unknown): HostConfig {
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
const record = value as Record;
@@ -870,6 +894,7 @@ function LibraryShellHeader({
aria-label={t("library.kitActions")}
/>
) : null}
+
@@ -1892,32 +1917,34 @@ export function LibraryWorkspace({
return (
- {routeSelectedLibraryId || hasLibraries ? (
-
-
setCreateOpen(true)}
- />
-
-
- {routeSelectedLibraryId ? (
-
- ) : (
-
- )}
-
-
- ) : (
- setCreateOpen(true)} />
- )}
+
+
setCreateOpen(true)}
+ />
+ {routeSelectedLibraryId || hasLibraries ? (
+ <>
+
+
+ {routeSelectedLibraryId ? (
+
+ ) : (
+
+ )}
+
+ >
+ ) : (
+ setCreateOpen(true)} />
+ )}
+
{
const params = new URLSearchParams(searchParamsKey);
return {
@@ -1959,7 +1985,13 @@ export function AssetPickerSurface() {
} satisfies HostConfig;
}, [searchParamsKey]);
const bridgeRef = useRef(null);
- const embedded = useMemo(() => isEmbeddedWindow() || isEmbedAuthActive(), []);
+ const embedded = useMemo(
+ () =>
+ searchParamsEnableEmbeddedLibrary(searchParams) ||
+ isEmbeddedWindow() ||
+ isEmbedAuthActive(),
+ [searchParams],
+ );
const pickerVariantScopeId = useMemo(
() =>
typeof window === "undefined" ? null : `picker:${getBrowserTabId()}`,
@@ -2862,14 +2894,17 @@ export function AssetPickerSurface() {
)}
- {mediaType === "image" && selectedLibraryId && pickerVariantScopeId && (
-
- )}
+ {mediaType === "image" &&
+ selectedLibraryId &&
+ !usingStarterLibrary &&
+ pickerVariantScopeId && (
+
+ )}
{!selectedLibraryId && (
@@ -3070,8 +3105,8 @@ export default function LibraryRoute() {
const { pickerRequested, queryLibraryId } = useMemo(() => {
const params = new URLSearchParams(searchParamsKey);
const requested =
- params.get("__an_picker") === "1" ||
- params.get("__an_mcp_chat_bridge") === "1";
+ searchParamsRequestPicker(params) ||
+ searchParamsEnableEmbeddedLibrary(params);
return {
pickerRequested: requested,
queryLibraryId: requested ? null : params.get("libraryId"),