# בוררים, ערכות ופרומפטים

> קריאת האפשרויות של הבוררים, מילוי בוררים מתיאור, ניהול ערכות, פלטות ומודבורדים ושיפור פרומפטים עם אשף הפרומפטים מ-TypeScript.

Source: https://nodaro.ai/he/docs/developers/sdk/pickers-and-prompts

**בוררים** הם רכיבי הבקרות היצירתיות, כגון הבורר [מצב־רוח](https://nodaro.ai/docs/nodes/creative-controls/mood) או הבורר עדשה, שהבחירה בהם מוסיפה לפרומפט ניסוח שנבדק. המשאבים **`client.pickerCatalogs`** ו-**`client.catalogs`** מחזירים את האפשרויות התקינות של כל בורר, והמתודה `analyzeText()` ממלאת בוררים מתיאור של סצנה. המשאב **`client.presets`** מנהל הגדרות שמורות של רכיבים, ב-**`client.palettes`** וב-**`client.moodboards`** נשמרים הצבעים וייחוסי הסגנון שלכם, והמשאב **`client.promptHelper`** הוא אשף הפרומפטים, שמשפר פרומפטים לכל רכיב יצירה. המושגים מוסברים במדריך [בקרות יצירתיות](https://nodaro.ai/docs/guides/creative-controls) ובדף [קטלוגי הבוררים](https://nodaro.ai/docs/developers/picker-catalogs).

## מתודות
| מתודה | מה היא עושה |
| --- | --- |
| [`pickerCatalogs.list()`](#pickercatalogslist) | רשימת כל הבוררים והקטלוגים שלהם |
| [`pickerCatalogs.get(nodeType, opts?)`](#pickercatalogsgetnodetype-opts) | קריאת האפשרויות של בורר אחד |
| [`pickerCatalogs.analyzeText(params)`](#pickercatalogsanalyzetextparams) | מילוי הבחירות בבוררים מתיאור טקסט |
| [`catalogs.list(opts?)`](#catalogslistopts) | קבלת כל הקטלוגים של הפריסה הזו בקריאה אחת |
| [`presets.list(nodeType?)`](#presetslistnodetype) | רשימת הערכות השמורות שלכם |
| [`presets.listGroups(nodeType?)`](#presetslistgroupsnodetype) | רשימת התיקיות והמקטעים של הערכות שלכם |
| [`presets.listFactory(nodeType)`](#presetslistfactorynodetype) | רשימת הערכות המובנות של סוג רכיב, בלי התחברות |
| [`presets.create(input)`](#presetscreateinput) ועוד | יצירה, עדכון, מחיקה, ייבוא וסידור מחדש של הערכות שלכם |
| [`presets.favorites(nodeType)`](#preset-favorites-and-folders) ועוד | ניהול המועדפים והתיקיות של הערכות |
| [`palettes.create(input)`](#clientpalettes) ועוד | שמירת פלטות צבעים לשימוש ברכיב יצירת תמונה |
| [`moodboards.create(input)`](#clientmoodboards) ועוד | שמירת מודבורדים לשימוש ברכיב יצירת תמונה |
| [`promptHelper.analyze(input)`](#prompthelperanalyzeinput) | הפיכת רעיון גולמי לשאלות |
| [`promptHelper.generate(input)`](#prompthelpergenerateinput) | בניית פרומפט מהתשובות |
| [`promptHelper.enhance(input)`](#prompthelperenhanceinput) | שיפור פרומפט בצעד אחד |

## client.pickerCatalogs
רשימות האפשרויות של רכיבי הבוררים. שתי מתודות הקריאה ציבוריות ולא דורשות אסימון, והשרת יכול לשמור את התגובות שלהן במטמון למשך 5 דקות. אם הקוד שלכם יכול לייבא את `@nodaro/prompts`, אותם קטלוגים מגיעים שם כנתונים עם הגדרות טיפוסים; המתודות האלה מיועדות ללקוחות שלא יכולים לכלול את החבילה.

### pickerCatalogs.list()‎
מחזירה את רשימת כל הבוררים (`GET /v1/picker-catalogs`).

```ts
list(): Promise<{ data: PickerCatalogSummary[] }>
```

```ts
const { data: pickers } = await client.pickerCatalogs.list()
const mood = pickers.find((p) => p.nodeType === "mood")
```

בכל רשומה יש `nodeType`, `label`, `catalogId`, `kind` (`single` או `multi`), `valueField` בבורר חד־ממדי או `fields` בבורר רב־ממדי, `optionCount` ו-`imageCount`, מספר האפשרויות שיש להן תמונה.

### pickerCatalogs.get(nodeType, opts?)‎
מחזירה את האפשרויות של בורר אחד (`GET /v1/picker-catalogs/:nodeType`). לבורר חד־ממדי, כגון הבורר מצב־רוח, יש `options`. לבורר רב־ממדי, כגון הבורר אדם, יש `dimensions`, כל אחד בצורה `{ field, label, options }`. לכמה בוררים חד־ממדיים יש גם הגדרות נוספות לצד הבחירה הראשית: ל-`transition` ול-`character-fx` יש `position`, `duration` ו-`intensity`, ול-`character-motion` יש `position` ו-`pace`.

```ts
get(nodeType: string, opts?: { detail?: "compact" | "full"; category?: string; field?: string }): Promise<{ data: PickerCatalog }>
```

<TypeTable
type={{
nodeType: { type: 'string', required: true, description: "סוג הרכיב של הבורר, כגון mood, lens או person." },
detail: { type: '"compact" | "full"', default: '"compact"', description: "הערך compact מחזיר id, label, category, term, icon ו-imageUrl. הערך full מוסיף את ה-description ואת ה-promptHint של כל אפשרות." },
category: { type: 'string', description: "בבוררים חד־ממדיים: רק אפשרויות מהקטגוריה הזו." },
field: { type: 'string', description: "רק ממד אחד של בורר רב־ממדי, או הגדרה נוספת אחת של בורר חד־ממדי." },
}}
/>

```ts
const { data } = await client.pickerCatalogs.get("mood", { detail: "full" })
const serene = data.options?.find((o) => o.id === "serene")
console.log(serene?.term)       // the short phrase, added in Compact mode
console.log(serene?.promptHint) // the full sentence, added in Full mode
```

כשסוג הרכיב לא מוכר, המתודה זורקת `NotFoundError`.

**הציגו את `label`, הוסיפו את `term`.** לכל אפשרות יש `term` בשתי רמות הפירוט: הביטוי המקצועי הקצר שמכניסים לפרומפט. השדה `label` מיועד לתצוגה בלבד. אף פעם אל תגזרו את האחד מהשני. לאפשרות שלא מוסיפה כלום, כגון `auto` או `none`, יש `term` ריק.

**סגנונות לתמונות ולווידאו.** לאפשרות של `style` שמוצעת לסוג פלט אחד בלבד יש `media`, בשתי רמות הפירוט: הערך `["video"]` בסגנונות לווידאו בלבד. אפשרות בלי `media` מוצעת לשני הסוגים. רשימת סגנונות לתמונה משמיטה אפשרות שב-`media` שלה אין `"image"`. לאפשרות של `style` שלא מופיעה ברשימת הסגנונות לעיצוב מחדש של קליפ מצולם יש `restyle: false`. השדה `promptHint` של אפשרות `style` הוא ניסוח התמונה שלה. פרומפט של וידאו מוסיף במקומו את ניסוח הווידאו של הסגנון, שה-API לא מחזיר. ראו את הסעיף [פרומפטים לווידאו והניסוח של הבורר סגנון](https://nodaro.ai/docs/developers/picker-catalogs#video-prompts-and-the-style-wording) בדף קטלוגי הבוררים.

**תמונות.** לאפשרות עם תמונה יש `imageUrl` מוחלט, בשתי רמות הפירוט. הבוררים `person` ו-`styling` מחזירים גם `sections`: התחומים שהעורך מקבץ תחתם את ההגדרות שלהם, כל אחד בצורה `{ label, fields, imageUrl? }`. את הצילומים מגישה ההתקנה עצמה. התצוגות המקדימות המרונדרות של בוררי המראה, וב-Nodaro Cloud גם הרינדורים הצילומיים של בוררי המוזיקה והקול, מגיעים מה-CDN של Nodaro. התקנה באירוח עצמי מגישה במקומם גרפיקה משלה לבוררי המוזיקה והקול. לתמונה מה-CDN של Nodaro יש גם `imageSrcSet`: אותה תמונה ברוחבים מ-240 עד 1,920 px, לשימוש ב-`<img srcset>`. בשמות הקבצים יש גיבוב של התוכן, ולכן אפשר לשמור את התמונות במטמון בלי תאריך תפוגה.

```ts
const { data: person } = await client.pickerCatalogs.get("person")
for (const section of person.sections ?? []) {
const settings = person.dimensions?.filter((d) => section.fields.includes(d.field)) ?? []
for (const setting of settings) {
for (const option of setting.options) renderTile(option.label, option.imageUrl)
}
}
```

**תנועת דמות.** לאפשרויות של `character-motion` יש אובייקט `motion` אופציונלי, בשתי רמות הפירוט. האובייקט מתאר מה תנועה צריכה ובאיזה מצב היא משאירה את הדמות: `requires`, `startPose` ו-`endPose`, `endVisibility`, `handsAfter`, `needsFreeHands`, `kind`, `fixedPace`, `counterpart`, `aliases` לחיפוש ו-`deprecated` עם `replacementId`. שדה חסר פירושו שהערך לא ידוע. כשאתם טוענים תהליכים שמורים, השאירו את המזהים שהוסרו מהקטלוג, והסתירו אותם מבחירות חדשות. ראו את הדף [תנועת דמות](https://nodaro.ai/docs/nodes/creative-controls/character-motion).

### pickerCatalogs.analyzeText(params)‎
ממלאת את הבחירות בבוררים מתיאור חופשי של סצנה (`POST /v1/text-to-picker`). זו גרסת הטקסט של רכיב [תיאור לבורר](https://nodaro.ai/docs/nodes/image/describe-to-picker). המתודה מחזירה את `pickerJson`, שמסודר לפי סוג הבורר, בתוכו לפי הממד, ובתוכו המזהה או המזהים שנבחרו. טענו ממנו את הבוררים כמו שהוא, ואז תנו למשתמש לשנות אותם. ההרצה מחויבת לפי הטוקנים שהקריאות שלה השתמשו בהם, בתעריף של המודל בשירות שטיפל בכל קריאה, כמו ברכיב תיאור לבורר. הרצה עם ברירות המחדל קוראת את הקטלוג של כל בורר, ולכן היא משתמשת ביותר טקסט מניתוח של תמונה אחת. קודם משוריינים קרדיטים, וכשהיתרה נמוכה מהשריון, הבקשה נדחית. Claude Opus 5.5 רץ כברירת מחדל ברמה `high`, ב-API של Anthropic עצמה. כדי לקבל אומדן מחיר של הרצה טיפוסית, העבירו את `llmPriceKey("text-to-picker", model)` ל-[`credits.modelCosts()`](https://nodaro.ai/docs/developers/sdk/models-and-credits#creditsmodelcostsids). ראו את הסעיף [איך מחויבות קריאות LLM](https://nodaro.ai/docs/concepts/credits#llm-calls) בדף קרדיטים.

```ts
analyzeText(params: TextToPickerParams): Promise<{
jobId: string
pickerJson: Record<string, Record<string, string | string[]>>
gaps?: { missingItems: object[]; missingCategories: object[] }
}>
```

<TypeTable
type={{
text: { type: 'string', required: true, description: "התיאור של הסצנה או של השוט." },
targetPickers: { type: 'string[]', description: "סוגי הבוררים למילוי. השמיטו אותו כדי למלא כל בורר שאפשר לנתח." },
instructions: { type: 'string', description: "הוראות נוספות לניתוח." },
llmModel: { type: 'string', description: "מזהה המודל. השמיטו אותו כדי להשתמש במודל ברירת המחדל, Gemini 3.8 Flash. גם Claude Fable 5 מוצע." },
reasoningEffort: { type: 'string', description: "מאמץ החשיבה, לפי מה שהמודל תומך בו. כשהוא מושמט ב-Claude Opus 5.5, ההרצה משתמשת ב-high. כל מודל אחר שומר על ברירת המחדל שלו." },
origin: { type: 'string', description: "השם של האפליקציה שלכם, שנשמר במשימה." },
}}
/>

```ts
const { pickerJson, gaps } = await client.pickerCatalogs.analyzeText({
text: "Neon-soaked Tokyo alley at night, rain, handheld tracking shot, moody synthwave",
})
console.log(pickerJson["setting"], pickerJson["camera-motion"])
```

ממדים שהטקסט לא אומר עליהם כלום נשארים בחוץ: הניתוח לא מנחש. השדה `gaps` מפרט, ב-`missingItems` וב-`missingCategories`, את מה שהטקסט מתאר ואף אפשרות בקטלוג לא מייצגת היטב. הציגו אותו למשתמש בהודעה כמו ״לא מצאנו התאמה ל-X; בחרו בעצמכם״.

## client.catalogs
### catalogs.list(opts?)‎
מחזירה את כל קטלוגי הבוררים בקריאה אחת, כפי שהפריסה הזו מגישה אותם (`GET /v1/catalogs`). פריסה יכולה לרשום חבילות קטלוגים שמחליפות, מרחיבות או מסתירות אפשרויות. לקוח שמציג בוררים בעיצוב משלו צריך לקרוא את הרשימה הזו כדי לכבד אותן. הנתיב ציבורי, ואפשר לשמור את התגובה שלו במטמון למשך 5 דקות.

```ts
list(opts?: { detail?: "compact" | "full" }): Promise<{
curated: boolean
packs: number
version: number
data?: ProjectedCatalog[]
}>
```

<TypeTable
type={{
detail: { type: '"compact" | "full"', default: '"compact"', description: "הערך compact מחזיר id, label, category, term ו-icon. הערך full מוסיף את description ואת promptHint." },
}}
/>

```ts
const { curated, data } = await client.catalogs.list({ detail: "full" })
if (curated) {
const setting = data?.find((c) => c.catalogId === "setting")
console.log(setting?.options?.[0]?.term)
}
```

השדה `data` מופיע רק כשהפריסה רשמה חבילות קטלוגים (`curated: true`). בלי חבילות, הקטלוגים הם הקטלוגים הרגילים: קבלו אותם אחד אחד עם `pickerCatalogs.get()`. לאפשרויות יש אותו `imageUrl`, ול-`person` ול-`styling` יש אותם `sections`.

## client.presets
הערכות השמורות שלכם, המועדפים שלכם וקטלוג הערכות המובנות. השדה `data` של ערכה הוא ההגדרות השמורות של רכיב. כדי להחיל ערכה, מזגו את ה-`data` שלה לתוך הנתונים של רכיב כשאתם בונים תהליך, או העבירו `presetId` ל[הרצה של רכיב יצירת תמונה](https://nodaro.ai/docs/developers/sdk/nodes#presets-on-generate-image). ראו את הדף [ערכות](https://nodaro.ai/docs/concepts/presets).

קטלוג הערכות המובנות מ-`listFactory()` ציבורי ולא דורש אסימון. לערכות שלכם, אסימון OAuth צריך את `presets:read` לקריאה ואת `assets:write` לכתיבה. אסימון ה-API שלכם לא צריך אף אחת מהן, אבל אסימון שמוגבל לתהליכים מסוימים לא יכול לגשת לערכות שלכם.

בכל ערכה, שלכם או מובנית, יש עוד שני שדות, ובערכה מובנית יכולים להיות עוד שלושה. שרתים מגרסה שקודמת לשדות האלה משמיטים אותם.

- **`minReferences`** הוא מספר תמונות הייחוס המחוברות שהערכה עובדת מהן, והשדה `needsImage` הוא `true` כשהמספר הזה גדול מ-0. הערכות שבתיקיות גיליון ייחוס, שינויי פורטרט ועריכות, וכל תבנית פרומפט שמשתמשת ב-`{image:N}`, צריכות תמונה אחת לפחות. הריצו ערכה כזו עם תמונות ייחוס במספר הזה.
- **`previewUrl`** הוא תמונת דוגמה, או `null`. בערכות שלכם, זו התמונה ששמרתם עם הערכה.
- **`previewSrcSet`**, בערכה מובנית, הוא אותה תמונה בשני הגדלים שלה, ברוחב 512 px וברוחב של עד 1024 px, לשימוש ב-`<img srcset>`. השדה מופיע רק בערכה ששני הגדלים קיימים בה.
- **`section`** ו-**`platforms`**, בערכה מובנית, הם כותרת המשנה שלה בתוך ה-`group` שלה, כגון נושא של יוטיוב, והמקומות שבהם התוצאה מיועדת להתפרסם, מהמתאים ביותר והלאה. הם מופיעים רק בערכה שיש לה אותם, ולכן קבצו וסננו לפיהם רק במקרה הזה.

### presets.list(nodeType?)‎
מחזירה את רשימת הערכות השמורות שלכם, מהחדש לישן (`GET /v1/node-presets`).

```ts
list(nodeType?: string): Promise<NodePreset[]>
```

<TypeTable
type={{
nodeType: { type: 'string', description: "רק ערכות של סוג הרכיב הזה, כגון generate-image." },
}}
/>

```ts
const presets = await client.presets.list("generate-image")
const cinematic = presets.find((p) => p.name === "Cinematic Portrait")
// apply: spread cinematic.data into the node's data when you create the workflow
```

ל-`NodePreset` יש `id`, `nodeType`, `name`, `description`, `data`, `groupId`, `tags`, `sortOrder`, `minReferences`, `needsImage`, `previewUrl`, `createdAt` ו-`updatedAt`.

### presets.listGroups(nodeType?)‎
מחזירה את רשימת התיקיות והמקטעים של הערכות שלכם (`GET /v1/node-preset-groups`).

```ts
listGroups(nodeType?: string): Promise<NodePresetGroup[]>
```

<TypeTable
type={{
nodeType: { type: 'string', description: "רק קבוצות של סוג הרכיב הזה." },
}}
/>

```ts
const groups = await client.presets.listGroups("generate-image")
```

לכל קבוצה יש `id`, `nodeType`, `name`, `kind` (`folder` או `section`), `sortOrder`, `createdAt` ו-`updatedAt`.

### presets.listFactory(nodeType)‎
מחזירה את רשימת הערכות המובנות של סוג רכיב (`GET /v1/node-presets/factory`).

```ts
listFactory(nodeType: string): Promise<{ data: FactoryPreset[] }>
```

<TypeTable
type={{
nodeType: { type: 'string', required: true, description: "סוג הרכיב, כגון generate-video." },
}}
/>

**ההתחברות אופציונלית.** הקטלוג ציבורי, ולכן גם לקוח בלי פרטי גישה יכול לקרוא אותו. הציגו למבקר את השמות, את תמונות הדוגמה ואת מספר הצילומים שכל ערכה צריכה, ובקשו ממנו להתחבר רק כשהוא יוצר.

```ts
// Signed out: a client with no credential can still read the catalog
const visitor = createClient({ baseUrl, auth: { getToken: async () => null } })
const { data } = await visitor.presets.listFactory("generate-image")
const withPicture = data.filter((p) => p.previewUrl)

// A preset that works from photos runs with at least minReferences of them.
const board = data.find((p) => p.id === "generate-image/character-board")!
if (board.needsImage && photos.length >= (board.minReferences ?? 0)) {
await client.nodes.runAndWait("generate-image", { presetId: board.id, referenceImageUrls: photos })
}
```

### presets.create(input)‎
שומרת ערכה (`POST /v1/node-presets`).

```ts
create(input: CreateNodePresetInput): Promise<NodePreset>
```

<TypeTable
type={{
nodeType: { type: 'string', required: true, description: "סוג הרכיב, כגון generate-image." },
name: { type: 'string', required: true, description: "ייחודי לכל סוג רכיב. בקשה עם שם שכבר בשימוש אצלכם נכשלת עם 409 name_taken." },
data: { type: 'Record<string, unknown>', required: true, description: "הגדרות הרכיב, עד 64 KB. מפתחות של זמן ריצה מוסרים." },
description: { type: 'string', description: "תיאור." },
groupId: { type: 'string', description: "התיקייה או המקטע שבהם הערכה תישמר." },
tags: { type: 'string[]', description: "תגיות." },
sortOrder: { type: 'number', description: "המיקום של הערכה." },
previewUrl: { type: 'string', description: "אחת מהתמונות שלכם בפלטפורמה הזו: העלאה או תוצאה שהסתיימה. בקשה עם כל כתובת אחרת נכשלת עם 400 validation_error." },
}}
/>

```ts
const preset = await client.presets.create({
nodeType: "generate-image",
name: "Studio portrait",
data: { provider: "gpt-image-2", aspectRatio: "3:4", prompt: "{image:1:person}, studio portrait" },
previewUrl: imageUrl, // the image of one of your completed jobs, or an upload
})
preset.needsImage // true, because the prompt names {image:1}
```

הערכה שומרת עותק משלה של התמונה, ולכן השדה `previewUrl` שחוזר הוא הכתובת של העותק. בחשבון יכולות להיות עד 5,000 ערכות. מעבר לזה, הקריאה נכשלת עם `409 limit_reached`.

### presets.update(id, patch, opts?)‎ ו-delete(id, opts?)‎
```ts
update(id: string, patch: UpdateNodePresetInput, opts?: { expectedUpdatedAt?: string }): Promise<NodePreset>
delete(id: string, opts?: { expectedUpdatedAt?: string }): Promise<{ success: true }>
```

המתודה `update()` משנה כל אחד מהשדות `name`, `description`, `data`, `groupId`, `tags`, `sortOrder` ו-`previewUrl` (הערך `null` מסיר את התמונה). המתודה `delete()` מוחקת את הערכה, ונכשלת עם 404 כשהערכה לא שלכם. העבירו את ה-`updatedAt` שקראתם בתור `expectedUpdatedAt`, והקריאה תיכשל עם `409 conflict` אם מישהו שינה את הערכה מאז.

### presets.import(presets)‎ ו-reorder(input)‎
```ts
import(presets: ImportNodePresetInput[]): Promise<{ imported: number }>
reorder(input: ReorderNodePresetsInput): Promise<{ ok: true }>
```

המתודה `import()` שומרת עד 500 ערכות בבת אחת, כל אחת בצורה `{ nodeType, name, description?, data, previewUrl? }`. ערכה עם שם שכבר בשימוש אצלכם נשמרת בשם `… (imported 2)` (יובא 2). מדלגים על ערכה שה-`data` שלה ריק אחרי שמפתחות זמן הריצה מוסרים. אפשר להעביר כמו שהן את הרשומות של הקובץ שהפקודה `nodaro presets export` כותבת.

המתודה `reorder()` מקבלת `{ groups?: [{ id, sortOrder }], presets?: [{ id, groupId?, sortOrder }] }`. המתודה קובעת מיקומים ומעבירה ערכות לתוך תיקייה, או מוציאה אותן מתיקייה עם `groupId: null`.

### מועדפים ותיקיות של ערכות
```ts
favorites(nodeType: string): Promise<string[]>
addFavorite(input: { nodeType: string; presetId: string }): Promise<{ success: true }>
removeFavorite(input: { nodeType: string; presetId: string }): Promise<{ success: true }>

createGroup(input: { nodeType: string; name: string; kind?: "folder" | "section"; sortOrder?: number }): Promise<NodePresetGroup>
updateGroup(id: string, patch: { name?: string; sortOrder?: number }): Promise<NodePresetGroup>
deleteGroup(id: string): Promise<{ success: true }>
```

מועדף הוא מזהה של ערכה מובנית, כגון `"generate-image/character-board"`, או מזהה של אחת מהערכות שלכם. אפשר לחזור על הוספה ועל הסרה של מועדף בלי חשש. מחיקת תיקייה מוציאה ממנה את הערכות שבה, ולא מוחקת אף אחת מהן.

## client.palettes
**פלטה** היא 2–12 צבעים בפורמט `#RRGGBB`, תחת שם אחד. ב-`generate-image`, פלטה היא ערך של `direction`: הגדירו את `direction.colorLook` ל-`paletteDirectionId(id)`, כלומר `"palette:<id>"`. כל צבע נכנס אז לפרומפט, בשם יומיומי ובקוד ההקסדצימלי שלו. פלטות שייכות לכם בלבד: מזהה של אדם אחר נדחה עם 404.

```ts

const palette = await client.palettes.create({ name: "Harbour", colors: ["#0F4C5C", "#E3B23C", "#F28C7A"] })
await client.nodes.runAndWait("generate-image", {
prompt: "a lighthouse at dusk",
direction: { colorLook: paletteDirectionId(palette.id) },
})
```

| מתודה | מה חוזר | הערות |
| --- | --- | --- |
| `list(params?: ListPalettesParams)` | `Promise<PalettePage>` | מהחדש לישן. הפרמטרים `limit` (1–100, ברירת המחדל: 50) ו-`cursor`. בעמוד יש `nextCursor`. |
| `get(id: string)` | `Promise<ColorPalette>` | פלטה אחת. |
| `create(input: CreatePaletteInput)` | `Promise<ColorPalette>` | השדות `name` (1–80 תווים), `colors` (2–12 ערכי `#RRGGBB` באותיות גדולות או קטנות, שנשמרים באותיות גדולות) ו-`description` (הערה שלכם, עד 500 תווים, שאף פעם לא נכנסת לפרומפט). |
| `update(id: string, input: UpdatePaletteInput)` | `Promise<ColorPalette>` | כותבת רק את השדות שאתם שולחים. הערך `description: null` מוחק את ההערה. |
| `delete(id: string)` | `Promise<void>` | הרצה מאוחרת יותר שמציינת את הפלטה נכשלת עם 404 `direction_not_found`. |

## client.moodboards
**מודבורד** הוא תיאור יחד עם 1–12 תמונות. ב-`generate-image`, מודבורד הוא ערך של `direction`: הגדירו את `direction.style` ל-`moodboardDirectionId(id)`, כלומר `"moodboard:<id>"`. התיאור נכנס לפרומפט, והתמונות נשלחות למודל כייחוסי סגנון. הן באות אחרי הייחוסים שלכם, עד מגבלת הייחוסים של המודל. התמונות הן קישורים, לעולם לא עותקים, והן חייבות להיות כתובות `http(s)` שהן לא `localhost` ולא כתובת פרטית.

```ts

const board = await client.moodboards.create({
name: "Nordic calm",
description: "Moody Nordic interiors, soft daylight, linen and oak",
images: [{ url: "https://example.com/a.png", caption: "soft daylight" }, { url: "https://example.com/b.png" }],
})
const out = await client.nodes.run("generate-image", {
prompt: "a reading corner",
direction: { style: moodboardDirectionId(board.id) },
})
// out.warnings: [{ code: "moodboard_images_not_sent", message }] when some images did not fit
```

| מתודה | מה חוזר | הערות |
| --- | --- | --- |
| `list(params?: ListMoodboardsParams)` | `Promise<MoodboardPage>` | מהחדש לישן. הפרמטרים `limit` (1–100, ברירת המחדל: 50) ו-`cursor`. בעמוד יש `nextCursor`. |
| `get(id: string)` | `Promise<Moodboard>` | מודבורד אחד. |
| `create(input: CreateMoodboardInput)` | `Promise<Moodboard>` | השדות `name` (1–80 תווים), `description` (עד 1,000 תווים, המילים שנכנסות לפרומפט) ו-`images` (1–12 פריטים בצורה `{ url, caption? }`, כל כיתוב עד 200 תווים). |
| `update(id: string, input: UpdateMoodboardInput)` | `Promise<Moodboard>` | כותבת רק את השדות שאתם שולחים. השדה `images` מחליף את כל התמונות. הערך `description: null` מוחק את התיאור. |
| `delete(id: string)` | `Promise<void>` | מוחקת רק את המודבורד. התמונות המקושרות לא נפגעות. |

### כללים לשניהם
- הקבועים `PALETTE_DIRECTION_PREFIX` (`"palette:"`) ו-`MOODBOARD_DIRECTION_PREFIX` (`"moodboard:"`) והפונקציות `paletteDirectionId(id)` ו-`moodboardDirectionId(id)` בונים את הערכים של `direction`.
- הטיפוס של `GenerateImageParams.direction` הוא `DirectionFields`, ובטיפוס של התגובה להרצה מופיע `warnings?: RunNodeWarning[]`.
- ערך פגום נדחה עם 400. מזהה שלא שייך לכם נדחה עם 404 `direction_not_found`. בשני המקרים הקריאה נכשלת לפני שמשהו נוצר ולפני שנגבים קרדיטים.
- אי אפשר לשלב פלטה או מודבורד עם `presetId`. הרצה כזו נדחית עם 400 `validation_error`, וכך גם הרצה עם ערכה שנשמרה עם פלטה או מודבורד ב-`direction` שלה.
- אסימונים של אפליקציות OAuth צריכים את `assets:read` לקריאה ואת `assets:write` לכתיבה.

## client.promptHelper
אשף הפרומפטים: עזרה של AI בכתיבת פרומפטים לרכיבי יצירה. כל שלוש המתודות שולחות את הבקשה שלהן ל-`POST /v1/prompt-helper/wizard`, וכל קריאה מחויבת לפי הטוקנים שהיא השתמשה בהם, בתעריף של המודל. לגרסת ה-REST, ראו את דף ה-API [אשף הפרומפטים](https://nodaro.ai/docs/developers/api/prompt-wizard).

שלוש המתודות מקבלות את השדות המשותפים האלה:

<TypeTable
type={{
nodeType: { type: 'string', required: true, description: "הרכיב שהפרומפט מיועד לו, כגון generate-image או generate-video." },
provider: { type: 'string', description: "המודל שהפרומפט מיועד לו." },
style: { type: 'string', description: "סגנון שהפרומפט צריך לכוון אליו." },
aspectRatio: { type: 'string', description: "יחס הגובה־רוחב של התוצאה." },
duration: { type: 'number', description: "אורך הקליפ הרצוי, בווידאו." },
llmModel: { type: 'string', description: "מודל השפה שכותב את הפרומפט." },
reasoningEffort: { type: 'string', description: "none, low, medium, high, xhigh או max, לפי המודל. לרמת המאמץ אין מחיר משלה: רמה גבוהה יותר עולה יותר רק בגלל הטוקנים שהמודל כותב. במודל Claude, כל רמת מאמץ מריצה את הקריאה ב-API של היצרן עצמו, בתעריף של אותו שירות." },
advancedMode: { type: 'boolean', description: "מודלי Gemini ו-Claude: הקריאה רצה ב-API של היצרן עצמו, ומחויבת בתעריף של אותו שירות." },
temperature: { type: 'number', description: "עם advancedMode: טמפרטורת הדגימה." },
maxTokens: { type: 'number', description: "עם advancedMode: האורך המרבי של התשובה, בטוקנים." },
nodeContext: { type: 'WizardNodeContext', description: "מה עוד מחובר לרכיב, כדי שהאשף יוכל להתחשב בזה." },
userPreference: { type: 'string', description: "העדפה שהאשף צריך לפעול לפיה." },
workflowId: { type: 'string', description: "תהליך שההרצה הזו תופיע תחתיו." },
}}
/>

ה-CLI מציע את אותן פעולות דרך `nodaro prompt wizard`, `analyze`, `generate` ו-`enhance`, עם `--llm-model` ו-`--reasoning-effort`. ראו את הדף [CLI](https://nodaro.ai/docs/developers/cli).

### promptHelper.analyze(input)‎
הופכת רעיון גולמי לשאלות מנחות לסוג רכיב. ענו עליהן, ואז העבירו את התשובות ל-`generate()`.

```ts
analyze(input: AnalyzeInput): Promise<{ jobId: string; questions: WizardQuestion[] }>
```

<TypeTable
type={{
prompt: { type: 'string', description: "הרעיון הגולמי." },
'...': { type: 'common fields', description: "השדה nodeType והשדות המשותפים שלמעלה." },
}}
/>

```ts
const { questions } = await client.promptHelper.analyze({
nodeType: "generate-image",
prompt: "a snow leopard",
})
```

### promptHelper.generate(input)‎
בונה פרומפט משופר אחד מהתשובות שנבחרו. כל בחירה היא בצורה `{ category, value, isCustom }`.

```ts
generate(input: GenerateInput): Promise<{ jobId: string; prompt: string; recommendedModel?: RecommendedModel }>
```

<TypeTable
type={{
selections: { type: 'WizardSelection[]', required: true, description: "התשובות שנבחרו, כל אחת בצורה ‎{ category, value, isCustom }‎." },
originalPrompt: { type: 'string', description: "הרעיון הגולמי שממנו נוצרו השאלות." },
'...': { type: 'common fields', description: "השדה nodeType והשדות המשותפים שלמעלה." },
}}
/>

```ts
const { prompt, recommendedModel } = await client.promptHelper.generate({
nodeType: "generate-image",
selections: [{ category: "subject", value: "snow leopard", isCustom: false }],
})
```

### promptHelper.enhance(input)‎
משפרת פרומפט בצעד אחד, בלי השאלות.

```ts
enhance(input: EnhanceInput): Promise<{ jobId: string; prompt: string; recommendedModel?: RecommendedModel }>
```

<TypeTable
type={{
prompt: { type: 'string', description: "הפרומפט לשיפור." },
'...': { type: 'common fields', description: "השדה nodeType והשדות המשותפים שלמעלה." },
}}
/>

```ts
const { prompt } = await client.promptHelper.enhance({
nodeType: "generate-image",
prompt: "snow leopard on a rock",
reasoningEffort: "high",
})
```

## שאלות נפוצות

### איך מוצאים את המזהים התקינים לאובייקט direction?

קראו למתודה client.pickerCatalogs.list()‎ כדי לקבל את כל הבוררים, ואז למתודה client.pickerCatalogs.get(nodeType)‎ כדי לקבל את האפשרויות של בורר אחד. ה-id של כל אפשרות הוא הערך ש-direction ורכיבי הבוררים מקבלים.

### מה ההבדל בין label, term ו-promptHint?

השדה label הוא שם התצוגה. השדה term הוא הביטוי המקצועי הקצר שהבורר מוסיף במצב מקוצר. השדה promptHint הוא המשפט הארוך יותר שהבורר מוסיף במצב מלא, והוא חוזר רק כש-detail הוא full.

### איך משפרים פרומפט עם ה-SDK?

קראו למתודה client.promptHelper.enhance עם ה-nodeType של רכיב היעד ועם הפרומפט שלכם. המתודה מחזירה פרומפט משופר, ולפעמים גם מודל מומלץ. כל קריאה עולה קרדיטים.

### האם ה-SDK יכול ליצור ערכות או לשנות אותן?

כן. המשאב client.presets יוצר, מעדכן, מוחק, מייבא ומסדר מחדש את הערכות שלכם, ומנהל את המועדפים ואת התיקיות. קטלוג הערכות המובנות מ-listFactory לא דורש התחברות.

### איך משתמשים בצבעים שלי בהרצה של רכיב יצירת תמונה?

שמרו פלטה עם client.palettes.create, ואז שלחו ל-generate-image את direction.colorLook עם הערך paletteDirectionId(palette.id)‎. כל צבע נכנס לפרומפט בשם יומיומי ובקוד ההקסדצימלי שלו.
