OpenRouter AI
uniflow.plugin.openrouter
•
Category: Cloud AI / Multimodal
•
Version: v1.4.0
•
Min Uniflow Version: Uniflow ≥ v1.4.0
OpenRouter AI Plugin Reference Manual
1. Overview
Plugin Name: OpenRouter AI
Type: Cloud AI / Multimodal
Identifier: uniflow.plugin.openrouter
Platform: CrossPlatform (Windows & Linux x64/ARM64)
Description
Connects Uniflow directly to cloud-hosted Multimodal Artificial Intelligence models (Vision, Audio, Text, PDF, and Video) via the unified OpenRouter REST API gateway. The plugin allows industrial rule workflows to execute visual inspection, PPE safety monitoring, license plate object detection, voice command recognition, audio analysis, PDF document data extraction, and AI media generation (Image/Video/TTS) using state-of-the-art AI models (e.g. OpenAI GPT-4o, Anthropic Claude 3.5 Sonnet, Google Gemini 1.5 Pro/Flash, Meta Llama 3.2 Vision, Luma Photon, Whisper).
2. Technical Architecture
The OpenRouter AI plugin provides a 100% self-contained integration layer between the Uniflow Rule Engine and cloud inference providers.
Core Architectural Features
/v1/chat/completions): Uses OpenRouter's standardized API endpoint, eliminating custom SDK code per model provider.429 Rate Limit or 5xx Server Error, the client automatically retries using the specified fallback model (e.g., falling back from google/gemini-flash-1.5 to openai/gpt-4o-mini).OpenRouterMediaResolver): Transparently handles media payloads provided as disk file paths, HTTP URLs, Base64 Data URIs (data:image/jpeg;base64,...), or raw Base64 strings.MaxImageDimension (1024px) and applies JPEG compression to prevent vision token size inflation and reduce latency.JsonObjects (plugin.json): Ships with 6 pre-packaged JSON schemas for structured result binding across image generation, video generation, text-to-speech, speech-to-text, audio understanding, and PDF analysis./v1/auth/key), track remaining credit balances (USD), monitor rate limits, and push periodic telemetry updates.Base64LogSanitizer): All API debug logs (_logger.Debug) automatically strip and replace large Base64 image and audio payloads with compact placeholders (e.g. {base64: 45210 bytes}), preventing log file flooding.prompt input parameter of an Output Target Action Node.2.1 Memory Safety, Resource Efficiency & Log Protection
To ensure high-throughput execution in 24/7 industrial production environments, the plugin implements strict memory allocation boundaries:
1. Chunked Streaming File Downloads: FileDownloadQueueManager downloads files directly from the network stream to disk (FileStream) using fixed 8 KB memory buffers via HttpCompletionOption.ResponseHeadersRead. Memory consumption remains O(1) constant (~8 KB per download) regardless of whether the file size is 10 MB or 5 GB.
2. 50 MB Inline Base64 File Size Ceiling: When reading local non-image media files (audio, video, PDF) into memory for inline API transport, OpenRouterMediaResolver enforces a strict 50 MB safety ceiling to prevent Large Object Heap (LOH) fragmentation and memory spikes.
3. ImageSharp Image Resizing & Allocation Controls: Camera snapshot images are downscaled to MaxImageDimension in memory and disposed immediately using using var image = await Image.LoadAsync(...). Memory streams and image memory buffers are reclaimed by GC promptly. MaxImageDimension is fully configurable in the Source Editor UI (default 1024 px, editable up to 4096 px, or set to 0 to disable downscaling and preserve 100% original full resolution).
4. Log Shielding (Base64LogSanitizer): To avoid polluting disk storage and CPU overhead during DBG log generation, regex sanitizers replace raw Base64 data strings with lightweight string placeholders prior to writing log entries.
System Interaction & Exposed Catalog Routes
The OpenRouter AI plugin interfaces with OpenRouter's LLM gateway (https://openrouter.ai/api/v1/chat/completions). It builds multimodal payloads (text prompts, Base64 images, audio, PDF files), enforces strict JSON Schema outputs, and returns structured data.
Catalog Routes & Node Integration
Input Event Triggers (Input Nodes):
openrouter.response_generated - Emitted on LLM prompt completion.openrouter.structured_json_extracted - Emitted when JSON Schema validation succeeds.openrouter.request_failed - API error or timeout event.Executable Actions (Action Nodes):
openrouter.prompt_completion - Sends a text prompt to specified LLM model.openrouter.analyze_media - Submits an image/audio file for AI analysis.openrouter.extract_document_json - Parses PDF document into structured JSON.Architecture Diagram
3. Configuration Parameters
The following configuration settings are available in the WPF User Interface (OpenRouterSourceEditorView) when creating or configuring an instance of this plugin source:
| Configuration Setting | Description | Default Value |
|---|---|---|
| Source Name | Friendly identifier for this OpenRouter plugin instance. | New OpenRouter AI Source |
| API Key (sk-or-v1-...) | OpenRouter Bearer authentication key. | *(Required)* |
| Base URL | OpenRouter REST API base URL. | https://openrouter.ai/api/v1 |
| Default Model | Primary AI model identifier used for unassigned requests. Selected via editable dropdown populated dynamically from OpenRouter (GET /api/v1/models) with static fallback list. | google/gemini-flash-1.5 |
| Fallback Model | Secondary model identifier used if primary model returns 429 or 5xx errors. Selected via editable dropdown populated dynamically from OpenRouter (GET /api/v1/models) with static fallback list. | openai/gpt-4o-mini |
| Timeout (ms) | Maximum HTTP request execution timeout in milliseconds (minimum 60000ms enforced for generation models). | 60000 |
| Max Retries | Maximum retry count for transient network faults. Defaulted to 0 to prevent duplicate prompt postings and billing. | 0 |
| Temperature | Model randomness parameter (0.0 = deterministic/logical, 1.0 = creative). | 0.2 |
| Max Tokens | Completion token limit for model responses. | 1024 |
| Max Image Dimension | Maximum width/height pixel dimension for downscaling images before Base64 encoding. Set to 0 to disable downscaling and preserve 100% original resolution. | 1024 |
| JPEG Quality | Image compression quality percentage (1 to 100) to optimize vision token usage. | 80 |
| Max Audio Sec | Maximum sound recording duration allowed for speech recognition operations. | 60 |
3.1 Preset Prompt Templates & Dynamic UI Schema Visibility
The plugin allows administrators to build a table of Preset Prompt Templates stored inside the plugin configuration. Each preset is assigned a PresetType:
| Preset Type Enum | Category | Has Built-in Schema | UI Enforcement Section Visibility |
|---|---|---|---|
ImageGeneration | Image Generation | True | Hidden (Uses Built-in Schema) |
VideoGeneration | Video Generation | True | Hidden (Uses Built-in Schema) |
TextToSpeech | Text to Speech | True | Hidden (Uses Built-in Schema) |
SpeechToText | Speech to Text | True | Hidden (Uses Built-in Schema) |
AudioUnderstanding | Audio Understanding | True | Hidden (Uses Built-in Schema) |
PdfAnalysis | PDF Analysis | True | Hidden (Uses Built-in Schema) |
ImageUnderstanding | Image Understanding | False | Visible (Supports Custom JSON Schema) |
VideoUnderstanding | Video Understanding | False | Visible (Supports Custom JSON Schema) |
HasBuiltInSchema = true): The WPF preset edit dialog automatically hides the "Structured Output Enforcement" section and binds to the pre-packaged JsonObject distributed with plugin.json.HasBuiltInSchema = false): The WPF preset edit dialog displays the "Structured Output Enforcement" section, allowing users to select a central system JsonObject or supply inline custom JSON schemas (response_format: { type: "json_object" }).3.2 Model Endpoints Catalog Helper Window & Dynamic Parameter Binding
Because supported resolutions, aspect ratios, streaming capabilities, and pricing vary per provider endpoint, the plugin features a dedicated 3-Column Model Endpoints Catalog Helper Window (OpenRouterModelCatalogDialog):
1. Access: Click the Helper button (🔍) on the OpenRouter source row in the Sources list, "🌐 Browse Model Endpoints Catalog..." in the Source Editor view, or "🌐 Inspect Endpoints" in the Preset Edit dialog.
2. Layout & Capabilities:
Image Generation, Video Generation, Text to Speech, Speech to Text, Audio Understanding, PDF Analysis, Image Understanding, Video Understanding, All Models Catalog).3. Background Auto-Refresh (30 Minutes): Endpoint metadata is automatically fetched from OpenRouter GET /api/v1/models every 30 minutes in the background, or refreshed immediately on demand via Refresh Endpoint Catalog.
4. Dynamic Output Target Parameter Binding: When configuring presets or Output Target nodes, the plugin queries the cached endpoint specs for the target model and populates resolution (["1K", "2K", "4K"] or ["1024x1024", "512x512"]), aspect_ratio, and seed options dynamically.
4. Exposed Routes & Data Types
This plugin exposes catalog fields across Input Source (telemetry data), Output Target (action sinks), and Event Input (trigger sources) rule graph nodes:
4.1 Input Source Telemetry Fields
The Input Source node reads live operational metrics and credit usage from the OpenRouter gateway:
| Display Name | Data Type | Description |
|---|---|---|
| API Status String | ||
| ↳ | Current gateway status (Connected, Error: Missing API Key, Idle). | |
| Remaining Credits (USD) Double | ||
| ↳ | Remaining account credit balance calculated from OpenRouter /auth/key. If no limit is configured on the API key (limit: null), displays total USD spending instead of negative values. | |
| Rate Limit Remaining Requests Int32 | ||
| ↳ | Remaining requests before rate limit reset (x-ratelimit-remaining). | |
| Last Execution Time (ms) Int32 | ||
| ↳ | Duration in milliseconds of the last executed multimodal inference call. | |
| Total Tokens Used Int64 | ||
| ↳ | Cumulative total of prompt and completion tokens processed. | |
4.2 Output Target Action Nodes
The Output Target node acts as an action sink to execute AI multimodal requests or enqueue file downloads:
| Target Display Name | Data Type | Associated Parameters | Parameter Data Type | Required | Description |
|---|---|---|---|---|---|
| Download File String | |||||
| ↳ | urlpathfilenamepayload | StringStringStringString | True True True False | Enqueues a remote HTTP URL or Base64 Data URI for file/model download and decoding directly to local disk. | |
| [Configured Preset] String | |||||
| ↳ | audio_inputtext_inputmedia_inputpromptpreset_idpayloadmodel | StringStringStringStringStringStringString | True False False False False False False | Executes a specific user-configured preset prompt template (automatically routes to Image, Video, Text-to-Speech, Speech-to-Text, Audio Understanding, PDF, or Chat Completion API based on its configured PresetType). | |
4.3 Event Input Trigger Nodes
The Event Input node triggers downstream rule logic upon completion of an AI preset prompt operation or background file download:
| Event Display Name | Family | Description |
|---|---|---|
| Download File Completed EVENT | ||
| ↳ | Triggers when a queued file/model download finishes writing to disk or exhausts max retries. | |
| [Configured Preset Name] Completed EVENT | ||
| ↳ | Triggers when a specific user-configured preset prompt execution completes (e.g. SpeechToText Completed, GenVoiceAI Completed, AudioAnalysis Completed). | |
4.4 Event Output Telemetry Fields
When an Event Input node triggers, it exposes the following output fields for rule execution:
Preset Completion Events (event:preset_<id>)
| Field Name | Data Type | Description |
|---|---|---|
Success Bool | ||
| ↳ | true if OpenRouter API returned a 200 OK completion without error. | |
Content String | ||
| ↳ | Primary output text / AI response content. | |
Text String | ||
| ↳ | Alias for primary output text. | |
AudioSummary String | ||
| ↳ | Summary text for audio understanding models. | |
DocumentSummary String | ||
| ↳ | Summary text for PDF document analysis models. | |
Transcript String | ||
| ↳ | Raw transcribed text for Speech-to-Text models. | |
Payload String | ||
| ↳ | Correlation tracking string passed in payload during request dispatch. | |
MediaInput String | ||
| ↳ | Original media input string passed to the request. | |
MediaType String | ||
| ↳ | Detected transport format (FilePath, Url, DataUri, Base64). | |
MediaKind String | ||
| ↳ | Detected media modality (Image, Audio, Video, Pdf, Text). | |
PresetName String | ||
| ↳ | Name of the preset prompt template executed. | |
ModelUsed String | ||
| ↳ | Actual AI model identifier used for completion (e.g. google/gemini-2.5-flash). | |
StructuredResultJson String | ||
| ↳ | Complete JSON response body returned by the AI model (contains Success, Content, Text, AudioSummary, Url, B64Json, ModelUsed, ExecutionTimeMs). | |
ExecutionTimeMs Int | ||
| ↳ | Total round-trip execution duration in milliseconds. | |
PromptTokens Int | ||
| ↳ | Number of tokens consumed by the prompt/media input. | |
CompletionTokens Int | ||
| ↳ | Number of tokens generated in the completion output. | |
TotalTokens Int | ||
| ↳ | Total combined token count consumed by the API call. | |
ErrorMessage String | ||
| ↳ | Detailed error description if Success is false. | |
File Downloaded Event (event:file_downloaded)
| Field Name | Data Type | Description |
|---|---|---|
Success Bool | ||
| ↳ | true if file download or Base64 decoding succeeded within 5 retry attempts. | |
Payload String | ||
| ↳ | Correlation tracking string passed in payload during request dispatch. | |
DownloadStatus String | ||
| ↳ | Detailed completion status (Success, FailedDirectoryCreation, MaxRetriesExceeded). | |
Filename String | ||
| ↳ | Destination filename saved on disk. | |
Path String | ||
| ↳ | Destination folder path directory. | |
FullFilePath String | ||
| ↳ | Full absolute path to the downloaded file. | |
Url String | ||
| ↳ | Remote HTTP URL or Base64 Data URI saved to disk. | |
FileSize Int | ||
| ↳ | Size of the downloaded file in bytes. | |
ExecutionTimeMs Int | ||
| ↳ | Total download duration in milliseconds. | |
ErrorMessage String | ||
| ↳ | Error details if download failed after 5 retry attempts. | |
5. Usage Examples & Workflows
5.1 AI Image Generation: 2-Step Request ➔ Event & Download to Disk Workflow
In asynchronous AI image generation workflows, execution happens in two distinct steps across two rules:
1. Rule 1 (Send Request): An industrial trigger (e.g., Modbus coil, camera sensor, or timer) dispatches the image generation request with specific parameters (prompt, resolution, aspect_ratio, style, payload).
2. Rule 2 (Receive Result & Save to Disk): When the OpenRouter API finishes generating the image, it raises a completion event (event:preset_<id> or event:generate_image). Rule 2 catches this event, parses StructuredResultJson, extracts the image URL or Base64 Data URI, and triggers OpenR / Download File to write the image file directly to disk (D:\_AiGen\ImageGen.jpg).
Step 1: Rule 1 Graph Configuration ("0_CoilTriggerGenImageAI")
Input Source (LocalModbus, reading COIL_0).Output Target (OpenR / ImageGen preset, ItemId: openrouter:preset_<id>):triggermode = OnceOnTrueprompt = "Generate a futuristic image representing a hub of software plugins"resolution = "256x256"aspect_ratio = "1:1"style = "futuristic"payload = "ASDF1234" *(Correlation tracking string)*COIL_0 flips to true, the node sends POST /api/v1/chat/completions to OpenRouter with resolution, aspect_ratio, style, and payload in the request body.Step 2: Rule 2 Graph Configuration ("1_ImageGenerated")
Event Input listening for event:preset_<id> (OpenR):Success, Payload, StructuredResultJson, ErrorMessage.Success (Bool), Payload (String = "ASDF1234"), StructuredResultJson (String).JSON Deserialize (OpenRouter Image Generation Result):json port connected from StructuredResultJson output port of Event Input.Success (Bool), Url (String), B64Json (String), ModelUsed (String).Output Target (OpenR / Download File, ItemId: openrouter:download_file):trigger port connected from Success output port of JSON Deserialize.url port connected from Url output port of JSON Deserialize (handles both http:// URLs and Base64 Data URIs data:image/jpeg;base64,...).path = "D:\\_AiGen"filename = "ImageGen.jpg"payload = "RequestDownload_ASDF123"1. When OpenRouter completes generation, it publishes event:preset_<id>.
2. JSON Deserialize reads StructuredResultJson, outputting Success = true and Url = "data:image/jpeg;base64,...".
3. Output Target: Download File receives Trigger = true, decodes the Base64 Data URI, and saves the image directly to D:\_AiGen\ImageGen.jpg.
4. The plugin publishes event:file_downloaded with DownloadStatus = Success and FullFilePath = D:\_AiGen\ImageGen.jpg.
5.2 Custom JSON Schema Enforcement
In physical security, perimeter surveillance, and industrial access control environments, AI models can analyze audio recordings, camera snapshots, or video clips and respond with structured JSON output enforcing a specific schema.
Step 1: Configure Schema Format Mode in Preset Editor
When creating a preset (e.g., PresetType.AudioUnderstanding, PresetType.ImageUnderstanding, or PresetType.VideoUnderstanding):
1. In the Preset Editor, set Format Mode to JsonObjectRef (or BuiltInJsonObject).
2. Select your custom JSON Object schema created in Uniflow's "Json Objects" manager.
3. The plugin automatically attaches response_format: { "type": "json_object" } to the OpenRouter request and appends JSON formatting instructions.
Security Scenario A: Audio Security Threat Analysis (Perimeter Microphone / Intercom)
An audio microphone near a restricted fence line records an audio clip (D:\_AiGen\tts.mp3). The AI determines if a security threat exists.
Custom JSON Object Schema (Security Audio Threat Analysis):
Preset Prompt Template (Configured in Preset Editor for Perimeter_Audio_Guard):
User Input Parameters (Sent in Output Target Action Node):
media_input: "D:\\_AiGen\\tts.mp3" *(Path to local audio file, Data URI, or URL)*prompt: "what this audio is about?" *(User prompt passed to the action node to override or refine analysis)*payload: "AudioReq_101" *(Correlation tracking string)*model: "google/gemini-2.5-flash" *(Optional model override)*Rule Execution Flow:
1. Rule 1 (Send Audio): Triggered by perimeter sound sensor → Dispatches Output Target: OpenR / Perimeter_Audio_Guard with the input parameters above.
2. Rule 2 (Evaluate Threat & Fire Alarm): Listens for Event Input: OpenR / Perimeter_Audio_Guard Completed → Connects StructuredResultJson to JSON Deserialize (Security Audio Threat Analysis).
3. Downstream logic: If ThreatDetected == true AND UrgencyLevel == "High" → Triggers TCP / Send Data to transmit an alarm to the central VMS control room.
Security Scenario B: Gate PPE & Vehicle Inspection (Access Control Camera)
A fixed camera at a security entrance gate captures a worker and vehicle (D:\Snapshots\gate_worker.jpg).
Custom JSON Object Schema (Gate PPE Safety Inspection):
Preset Prompt Template (Configured in Preset Editor for Gate_PPE_Inspection):
User Input Parameters (Sent in Output Target Action Node):
media_input: "D:\\Snapshots\\gate_worker.jpg"prompt: "Inspect worker for safety helmet and high-vis vest compliance."payload: "GateCheck_202"Rule Execution Flow:
1. Rule 1: Gate motion sensor triggers snapshot → Dispatches Output Target: OpenR / Gate_PPE_Inspection with the input parameters above.
2. Rule 2: Listens for Gate_PPE_Inspection Completed → JSON Deserialize (Gate PPE Safety Inspection).
3. If AccessGranted == true → Set LocalModbus / GATE_BARRIER coil to true (opens gate).
4. If AccessGranted == false → Sound strobe warning light and log ViolationDetails.
Security Scenario C: Video CCTV Intrusion Analysis (Surveillance Camera Clip)
A VMS plugin captures a 5-second video recording clip (D:\VideoClips\camera_4_intrusion.mp4) when a motion perimeter is breached after hours.
Custom JSON Object Schema (CCTV Intrusion Event Analysis):
Preset Prompt Template (Configured in Preset Editor for CCTV_Fence_Guard):
User Input Parameters (Sent in Output Target Action Node):
media_input: "D:\\VideoClips\\camera_4_intrusion.mp4"prompt: "Check video clip for unauthorized human intruder scaling fence."payload: "VidAlarm_303"Scenario A: Image Object Detection & Safety Inspection
To detect whether safety helmets and reflective vests are present in an image captured from an ONVIF camera:
1. Configure an ONVIF plugin rule to save snapshot images to C:\Snapshots\gate1.jpg.
2. Add an Output Target Action Node targeting openrouter:understand_image with:
media_input = C:\Snapshots\gate1.jpgprompt = Inspect this image. Return a JSON object with fields: "HelmetDetected" (boolean), "VestDetected" (boolean), "WorkerCount" (integer).3. Add an Event Input Node listening to event:understand_image.
4. Connect downstream conditional nodes evaluating HelmetDetected == false to sound a local warning alarm.
Logic Flow Diagram:
Scenario B: Voice Command Recognition (Speech-to-Text)
To process audio voice recordings captured from an intercom or PA microphone:
1. Ingest the audio recording file path (e.g. C:\Recordings\command.wav).
2. Add an Output Target Action Node targeting openrouter:speech_to_text with media_input = C:\Recordings\command.wav.
3. Add an Event Input Node listening to event:speech_to_text.
4. Use the Transcript field output in downstream string matching nodes (str_contains) to trigger industrial machinery actions.
Logic Flow Diagram:
Scenario C: Dynamic Prompt Overriding from Rule Graph
To dynamically inject custom inspection instructions built by an upstream rule node:
1. Construct a dynamic prompt string (e.g. using a string concatenation node: "Inspect cargo container " + container_id + " for physical damage").
2. Connect the string output port of the concatenation node into the prompt input port of an Output Target Action Node configured for openrouter:preset_cargo_inspector.
3. The plugin will execute the call using the connected dynamic prompt, overriding the preset's default template.
Logic Flow Diagram:
Scenario D: Two-Rule AI Generation & Asynchronous Model/File Download Workflow
To generate a model/image asset via OpenRouter and automatically download the resulting remote file:
Rule 1 (Generation Request):
1. Add an Output Target Action Node configured for openrouter:generate_image (or openrouter:generate_video).
2. Provide prompt = "Industrial warning sign icon, high resolution".
3. Execution dispatches the request to OpenRouter.
Rule 2 (Event Completion & Download Dispatch):
1. Add an Event Input Node listening for event:generate_image.
2. Evaluate Success == true.
3. Extract the generated media URL from Url output port (or StructuredResultJson).
4. Add an Output Target Action Node targeting openrouter:download_file (or openrouter:download_model) with parameters:
url = connected from Url output portpath = C:\Uniflow\Downloadsfilename = warning_sign.png5. The download queue manager ensures unique URL handling and executes up to 5 retry attempts logging progress at DBG level.
6. When complete, an event:file_downloaded event is published with DownloadStatus = Success and FullFilePath = C:\Uniflow\Downloads\warning_sign.png.