docs: clarify widget serialize vs options.serialize in types and JSDoc (#9105)

## Summary

Clarifies the two distinct `serialize` properties on widgets via
improved TypeScript types and JSDoc:

- **`IWidgetOptions.serialize`** — controls whether the widget value is
included in the **API prompt** sent for execution
- **`IBaseWidget.serialize`** — controls whether the widget value is
persisted in the **workflow JSON** (`widgets_values`)

These two properties are easily confused. This PR adds cross-linking
JSDoc, explicit `@default` tags, and a clarifying comment at the check
site in `executionUtil.ts`.

## Changes

| File | Change |
|------|--------|
| `src/lib/litegraph/src/types/widgets.ts` | Add `serialize?: boolean`
to `IWidgetOptions` with JSDoc; expand JSDoc on `IBaseWidget.serialize`
|
| `src/utils/executionUtil.ts` | Clarifying comment at the
`widget.options.serialize` check |
| `src/types/metadataTypes.ts` | Connect `ComfyMetadataTags` enum values
to their corresponding serialize properties |

## Related

- Companion doc: #9102 (`WIDGET_SERIALIZATION.md`)
- Issue: #1757

## Verification

- `vue-tsc --noEmit` passes clean
- `eslint` passes clean on all 3 files
- No runtime changes — JSDoc and types only

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9105-docs-clarify-widget-serialize-vs-options-serialize-in-types-and-JSDoc-3106d73d36508155b618ee56cf18f969)
by [Unito](https://www.unito.io)
This commit is contained in:
Christian Byrne
2026-02-22 18:13:48 -08:00
committed by GitHub
parent 5687b44422
commit ddc2159bed
3 changed files with 26 additions and 4 deletions

View File

@@ -4,7 +4,7 @@ Two properties named `serialize` exist at different levels of a widget object. T
**`widget.serialize`** — Controls **workflow persistence**. Checked by `LGraphNode.serialize()` and `configure()` when reading/writing `widgets_values` in the workflow JSON. When `false`, the widget is skipped in both serialization and deserialization. Used for UI-only widgets (image previews, progress text, audio players). Typed as `IBaseWidget.serialize` in `src/lib/litegraph/src/types/widgets.ts`.
**`widget.options.serialize`** — Controls **prompt/API serialization**. Checked by `executionUtil.ts` when building the API payload sent to the backend. When `false`, the widget is excluded from prompt inputs. Used for client-side-only controls (`control_after_generate`, combo filter lists) that the server doesn't need. Not currently typed in `IWidgetOptions` — set at runtime via the options bag.
**`widget.options.serialize`** — Controls **prompt/API serialization**. Checked by `executionUtil.ts` when building the API payload sent to the backend. When `false`, the widget is excluded from prompt inputs. Used for client-side-only controls (`control_after_generate`, combo filter lists) that the server doesn't need. Typed as `IWidgetOptions.serialize` in `src/lib/litegraph/src/types/widgets.ts`.
These correspond to the two data formats in `ComfyMetadata` embedded in output files (PNG, GLTF, WebM, AVIF, etc.): `widget.serialize``ComfyMetadataTags.WORKFLOW`, `widget.options.serialize``ComfyMetadataTags.PROMPT`.
@@ -22,7 +22,7 @@ These correspond to the two data formats in `ComfyMetadata` embedded in output f
- `addWidget('combo', name, value, cb, { serialize: false })` puts `serialize` into `widget.options`, **not** onto `widget` directly. These are different properties consumed by different systems.
- `LGraphNode.serialize()` checks `widget.serialize === false` (line 967). It does **not** check `widget.options.serialize`. A widget with `options.serialize = false` is still included in `widgets_values`.
- `LGraphNode.serialize()` only writes `widgets_values` if `this.widgets` is truthy. Nodes that create widgets dynamically (like `PrimitiveNode`) will have no `widgets_values` in serialized output if serialized before widget creation — even if `this.widgets_values` exists on the instance from a prior `configure()` call.
- `widget.options.serialize` is not typed in `IWidgetOptions`. If you add it to the type definition, update this doc.
- `widget.options.serialize` is typed as `IWidgetOptions.serialize` — both properties share the name `serialize` but live at different levels of the widget object.
## Code references

View File

@@ -47,6 +47,19 @@ export interface IWidgetOptions<TValues = unknown> {
/** Used as a temporary override for determining the asset type in vue mode*/
nodeType?: string
/**
* Whether the widget value should be included in the API prompt sent to
* the backend for execution. Checked by {@link executionUtil} when
* building the prompt payload.
*
* This is distinct from {@link IBaseWidget.serialize}, which controls
* whether the value is persisted in the workflow JSON file.
*
* @default true
* @see IBaseWidget.serialize — workflow persistence
*/
serialize?: boolean
values?: TValues
/** Optional function to format values for display (e.g., hash → human-readable name) */
getOptionLabel?: (value?: string | null) => string
@@ -349,8 +362,15 @@ export interface IBaseWidget<
vueTrack?: () => void
/**
* Whether the widget value should be serialized on node serialization.
* Whether the widget value is persisted in the workflow JSON
* (`widgets_values`). Checked by {@link LGraphNode.serialize} and
* {@link LGraphNode.configure}.
*
* This is distinct from {@link IWidgetOptions.serialize}, which controls
* whether the value is included in the API prompt sent for execution.
*
* @default true
* @see IWidgetOptions.serialize — API prompt inclusion
*/
serialize?: boolean

View File

@@ -92,7 +92,9 @@ export const graphToPrompt = async (
const inputs: ComfyApiWorkflow[string]['inputs'] = {}
const { widgets } = node
// Store all widget values
// Store all widget values in the API prompt.
// Note: widget.options.serialize controls prompt inclusion (checked here).
// widget.serialize controls workflow persistence (checked by LGraphNode).
if (widgets) {
for (const [i, widget] of widgets.entries()) {
if (!widget.name || widget.options?.serialize === false) continue