Inference and credential extension boundaries

How a provider client and a credentials provider are supplied to an annotation run. Annotators themselves are documented in rfgen.annotation: a domain writes one class and one Markdown prompt, and a run names it by import path.

This page was rfgen.annotators, a package that no longer exists. Its annotator-side contents — BaseAnnotator, MetadataAnnotator, Prompt, ClosedVocab, whitelist_filter, resolve_annotation_output_schema — were removed with the templated caption path. The filename is kept because three pages link to the section anchors below.

Inference-client extension boundary

BaseInferenceClient is the provider-neutral library contract. A plugin registers a subclass under the rfgen.inference_clients entry-point group, declares non-empty provider_name and model_id, and implements from_llm_config(config, credentials_provider=...). The factory receives the validated LLMConfig and optional credentials provider, and must return a client instance. complete(prompt=..., json_schema=..., max_tokens=..., request_id=..., template_id=..., run_id=...) returns an InferenceResponse with text, optional schema-validated parsed payload, token usage, finish reason, provider-reported model ID, and request ID.

One client ships. GeminiClient (provider_name="gemini", registered under the entry-point keys gemini and gemini-3.1-flash-lite) calls the google-genai SDK and serves the local_concurrent backend. The vertex_batch backend does not go through this registry at all: it is driver-only and builds its own Vertex Batch executor, registered under rfgen.annotation_executors.

rfgen annotate submit uses this selection path: AnnotationRunConfig.inference.provider selects the registered client class, and AnnotationRunConfig.inference.endpoints resolves one client instance per configured base_url/model pair. See rfgen.annotation for the run that drives them.

resolve_provider_api_key(raw, provider_name=...), exported from rfgen.inference.protocols, is the shared credential key-lookup contract. It reads api_key, then {provider_name}_api_key, then {PROVIDER_NAME}_API_KEY, stopping at the first name present in the mapping and returning the stripped key. A present entry whose value is None resolves to None; a present entry whose value is a blank string (or whitespace-only), or any other value that is not a usable string, raises ValueError instead. Client implementations and any caller that wants to reject a missing credential before construction should both go through this function, so a pre-construction check can never accept a credential the client would resolve to nothing.

Credentials-provider extension boundary

BaseCredentialsProvider.resolve(scope) returns a fresh ResolvedCredentials for storage, llm, or executor; it rejects an unknown scope and must not return expired credentials. StaticCredentialsProvider is the shipped local/CI implementation: it resolves a configured scope or raises ConfigError rather than returning an empty mapping. Providers may register under rfgen.annotation.credentials. rfgen ships StaticCredentialsProvider and a module-level credentials_registry, but does not declare a bundled package-metadata entry point for that group. Summaries must remain redacted.