Generator Dispatch - cprima-forks/uipath-ai-skills GitHub Wiki
Generator Dispatch Mechanism
generate_workflow.py uses a registry-and-dispatch architecture to route each JSON spec activity to its generator function.
_GenEntry and _REGISTRY
Every generator is registered as a _GenEntry frozen dataclass:
@dataclasses.dataclass(frozen=True, slots=True)
class _GenEntry:
fn: object # the generator function
idref: str # IdRef prefix, e.g. "NTypeInto"
required: tuple # required arg names for spec validation
container: bool # True = fn is a manual container handler
_REGISTRY is a dict mapping gen name strings to _GenEntry objects. All 93 core generators are registered at module load time using the _e() shorthand:
_REGISTRY = {
"ntypeinto": _e(gen_ntypeinto, "NTypeInto", ("display_name", "selector", "text_variable")),
"nclick": _e(gen_nclick, "NClick", ("display_name", "selector")),
"try_catch": _e(_handle_try_catch, "TryCatch", container=True),
...
}
_auto_dispatch
For non-container generators, dispatch goes through _auto_dispatch, which maps the JSON args dict to the generator function's parameters using runtime signature introspection:
def _auto_dispatch(fn, args: dict, **extra) -> str:
sig = _cached_signature(fn) # LRU-cached inspect.signature()
kwargs = {}
for name, param in sig.parameters.items():
if name in extra:
kwargs[name] = extra[name] # framework args: id_ref, scope_id, indent
elif name in args:
kwargs[name] = args[name] # from JSON spec
elif param.default is not inspect.Parameter.empty:
pass # use function default
return fn(**kwargs)
Framework args (id_ref, scope_id, indent) are injected by the caller. Optional generator args (is_secure, empty_field_mode, etc.) fall back to function defaults if not in the spec. Missing required args cause a Python TypeError at generation time.
_generate_activity Dispatch Flow
The unified entry point _generate_activity(spec, scope_id, counter, indent) handles the full dispatch sequence:
- Extract
genname andargsfrom spec - Auto-detection hooks (desktop context,
multiple_assigntype enrichment, Object Repository wiring) - Blocked generator check —
delayraisesValueError - Special-case:
log_message/logmessage— custom arg mapping outside the registry - Registry lookup → if
entry.container: callentry.fn(spec, args, scope_id, counter, indent)directly; else: call_auto_dispatch - Plugin generator fallback — same
_auto_dispatchpath as core ValueErrorif gen name is unknown
Special Case: log_message
log_message and its alias logmessage are not in _REGISTRY. They use a custom arg mapping: message_expr maps to the message parameter with explicit bracket wrapping. This predates the unified registry and was never migrated into it.
IdRef Prefix Derivation
The idref field in _GenEntry is the prefix for sap2010:WorkflowViewState.IdRef values. If not explicitly set, _derive_idref_prefix converts the gen name to PascalCase with acronym corrections:
"read_csv" → "ReadCSV" (not "ReadCsv")
"read_pdf_text" → "ReadPDFText"
Plugin Generators
Plugins registered via register_generator() in plugin_loader.py are stored separately from _REGISTRY but go through the same _auto_dispatch path. They are checked after core registry lookup, before the unknown-gen error.