Skip to main content

Availability

The Service API provides rich management capabilities for plugins to interact with the platform. Access is available through the Unified Plugin SDK via the Context.Services interface.

Overview

Service API access is available to all plugins using the unified SDK (pkg/plugin_sdk), with different capabilities depending on the runtime:

Universal Services (Both Runtimes)

  • KV Storage: Key-value storage (PostgreSQL in Studio, local DB in Gateway)
  • Logger: Structured logging

Runtime-Specific Services

  • Gateway Services: App management, LLM info, budget status, credential validation
  • Studio Services: Full management API (LLMs, tools, apps, filters, tags, CallLLM)

Access Pattern

All services are accessed through the Context.Services interface provided to your plugin handlers:
Expandable

Initialization and Connection Warmup

For Service API access in AI Studio, plugins use a session-based broker pattern. The SDK handles most of the setup automatically, but there’s a critical pattern you must follow for reliable Service API access.

The Connection Warmup Pattern

Critical: The go-plugin broker only accepts ONE connection per broker ID. If your plugin uses both the Event Service and the Management Service API, whichever service dials first will succeed, and the connection is shared between them. To ensure reliable Service API access, implement SessionAware and warm up the connection in OnSessionReady:
Expandable

Why Warmup Is Required

Without the warmup pattern, you may encounter “timeout waiting for connection info” errors when your plugin tries to use the Service API during an RPC call. This happens because:
  1. The broker connection is time-sensitive and must be established early
  2. Dialing late (during an RPC call from the UI) may fail if timing is off
  3. Event subscriptions and Service API calls share the same underlying connection

Legacy Pattern (Still Supported)

The older pattern of extracting the broker ID manually during Initialize still works but is not recommended:
Expandable
Note: The SDK now handles broker ID extraction automatically via OpenSession. You only need to implement SessionAware and warm up the connection.

Universal Services

These services are available in both Studio and Gateway runtimes.

KV Storage

Key-value storage for plugin data:
  • Studio: PostgreSQL-backed, shared across hosts, durable
  • Gateway: Local database, per-instance, ephemeral

Write Data

Returns error if write fails. Example:

Read Data

Returns error if key doesn’t exist. Example:

Delete Data

Example:

List Keys

Example:

Logger

Structured logging with key-value pairs:
Example:
Expandable

Event Service

The Event Service enables plugins to publish and subscribe to events using the Event Bridge system. This allows plugins to communicate across the distributed architecture (edge ↔ control) using a pub/sub pattern. Key Features:
  • Publish events to the local event bus
  • Subscribe to events by topic or all events
  • Events can flow across the hub-spoke architecture based on direction
  • Automatic cleanup of subscriptions when plugin disconnects

Event Directions

Events have a direction that controls routing:

Publish Event

Publish an event with a JSON-serializable payload:
Example:
Expandable

Publish Raw Event

Publish an event with pre-serialized JSON payload (avoids double-serialization):
Example:

Subscribe to Events

Subscribe to events on a specific topic:
Example:
Expandable

Subscribe to All Events

Subscribe to all events regardless of topic:
Example:

Unsubscribe

Remove a subscription:
Example:
Note: Subscriptions are automatically cleaned up when the plugin process terminates, but it’s good practice to explicitly unsubscribe in Shutdown().

Event Structure

Events have the following fields:

Complete Example: Event-Driven Cache Invalidation

Expandable

Event Service Best Practices

  1. Use Appropriate Directions:
    • DirLocal for metrics and debugging within a single node
    • DirUp for edge plugins sending data to control
    • DirDown for control pushing updates to edges
  2. Handle Payload Parsing Errors: Always validate and handle JSON unmarshaling errors in event handlers.
  3. Avoid Blocking in Handlers: Event handlers should be fast. For heavy processing, spawn a goroutine or queue work.
  4. Clean Up Subscriptions: Unsubscribe in Shutdown() for explicit cleanup.
  5. Use Meaningful Topics: Use dot-separated topic names for clarity (e.g., cache.invalidate, config.updated, metrics.report).
  6. Include Context in Payloads: Add timestamps, correlation IDs, or source info to payloads for debugging.

System CRUD Events

AI Studio emits built-in system events when core objects are created, updated, or deleted. These events are published to the local event bus (control-plane only) and can be subscribed to by any plugin.

Available System Events

Event Payload Structure

All system CRUD events use a consistent payload structure:

Subscribing to System Events

Expandable

Example: Audit Log Plugin

Expandable
Note: System events are published with DirLocal direction, meaning they stay on the control plane and are not forwarded to edge instances.

Studio Services

Available when ctx.Runtime == plugin_sdk.RuntimeStudio.

LLM Operations

Requires: llms.read, llms.write, or llms.proxy scope

List LLMs

Alternative (direct SDK call):
Example:
Expandable

Get LLM

Alternative (direct SDK call):

Call LLM (Streaming)

Requires: llms.proxy scope
Example:
Expandable

Call LLM (Simple)

Convenience method for simple calls:
Example:

Get LLMs Count

Example:
Note: For complete Studio Services documentation including Tools, Apps, Plugins, Datasources, and Filters, see the examples in the working plugins at examples/plugins/studio/service-api-test/.

Gateway Services

Available when ctx.Runtime == plugin_sdk.RuntimeGateway. Gateway Services provide read-only access to essential gateway information.

Get App

Returns app configuration. Type assert to *gwmgmt.GetAppResponse. Example:

List Apps

Returns all apps accessible to the gateway. Type assert to *gwmgmt.ListAppsResponse.

Get LLM

Returns LLM configuration. Type assert to *gwmgmt.GetLLMResponse.

List LLMs

Returns all LLMs configured for the gateway. Type assert to *gwmgmt.ListLLMsResponse.

Get Budget Status

Returns current budget status for an app. Type assert to *gwmgmt.GetBudgetStatusResponse. Example:
Expandable

Get Model Price

Returns pricing information for a model. Type assert to *gwmgmt.GetModelPriceResponse.

Validate Credential

Validates a credential token. Type assert to *gwmgmt.ValidateCredentialResponse. Example:

Tool Operations (Studio Only)

Requires: tools.read, tools.write, or tools.execute scope

List Tools

Example:

Get Tool by ID

Example:

Execute Tool

Requires: tools.execute scope
Example:

Plugin Operations

Requires: plugins.read or plugins.write scope

List Plugins

Example:

Get Plugin by ID

Example:

Get Plugins Count

Example:

App Operations

Requires: apps.read or apps.write scope

List Apps

Example:

List Apps with Filters

ListAppsOptions supports filtering by:
  • IsActive *bool — Filter by active/inactive status
  • Namespace string — Filter by namespace (empty = all namespaces)
  • UserID *uint32 — Filter by owner user ID
Example — list only the current user’s apps:
Example — list active apps in a namespace:
The original ListApps(ctx, page, limit) function is still available for backward compatibility and returns all apps without filtering.

Get App by ID

Example:

Patch App Metadata

Atomically updates a single metadata key on an app without requiring a full app update. This is safer than UpdateAppWithMetadata for concurrent modifications since it uses database-level transactions with row locking. Set a metadata key (value must be JSON-encoded):
Set complex values:
Delete a metadata key:
Via the plugin_sdk interface:
Requires: apps.write scope.

KV Storage Operations

Requires: kv.read or kv.readwrite scope

Write Data

Returns true if created, false if updated. Pass nil for expireAt for no expiration. Example:
Expandable

Write Data with TTL

Convenience function that writes data with a relative time-to-live. The entry is automatically expired and cleaned up after the TTL elapses. Example:
Expired keys are automatically cleaned up by the platform. Reads on expired keys return a not-found error.

Read Data

Example:

Delete Data

Example:

List Keys

Example:

Data Types

LLMMessage

LLMTool (for tool calling)

Tool

Plugin

App

Error Handling

Service API calls return standard Go errors:
Common error types:
  • Permission denied: Missing required scope
  • Not found: Resource doesn’t exist
  • Invalid argument: Bad request parameters
  • Unavailable: Service not ready

Rate Limiting

Service API calls are subject to rate limiting:
  • Default: 1000 requests/minute per plugin
  • Configurable via platform settings
  • Implement exponential backoff for retries
Example retry logic:
Expandable

Context and Timeouts

Always use contexts with timeouts:

Best Practices

  1. Check SDK Initialization:
  2. Handle Pagination:
    Expandable
  3. Cache Results:
  4. Error Logging:

Scope Requirements Summary

RAG & Embedding Services

AI Studio provides comprehensive RAG (Retrieval-Augmented Generation) capabilities through the Service API, enabling plugins to build custom document ingestion and semantic search workflows.

Overview

The RAG Service APIs allow plugins to:
  • Generate embeddings using configured embedders (OpenAI, Ollama, Vertex, etc.)
  • Store pre-computed embeddings with custom chunking strategies
  • Query vector stores with semantic search
  • Build complex ingestion plugins (GitHub, Confluence, custom document processors)
Key Benefit: Plugins have full control over chunking, embedding generation, and storage - no forced workflows.

Core RAG APIs

GenerateEmbedding

Generate embeddings for text chunks without storing them.
Expandable
Required Scope: datasources.embeddings Use Case: Custom chunking workflows where you generate embeddings first, then decide what to store.

StoreDocuments

Store pre-computed embeddings in the vector store without regenerating them.
Expandable
Required Scope: datasources.embeddings Use Case: Complete control over embeddings - use custom models, external services, or cached embeddings. Supported Vector Stores:
  • ✅ Pinecone
  • ✅ PGVector
  • ✅ Chroma (v0.2.5+)
  • ✅ Weaviate
  • ⚠️ Qdrant (requires SDK installation)
  • ⚠️ Redis (requires RediSearch configuration)

ProcessAndStoreDocuments

Convenience method that generates embeddings and stores in one step.
Expandable
Required Scope: datasources.embeddings Use Case: Simplified workflow when you don’t need to inspect or cache embeddings.

QueryDatasource

Semantic search using a text query (embedding generated automatically).
Expandable
Required Scope: datasources.query Use Case: Standard semantic search - plugin provides text, system handles embedding.

QueryDatasourceByVector

Semantic search using a pre-computed embedding vector.
Expandable
Required Scope: datasources.query Use Case: Advanced workflows with custom query embeddings or hybrid search strategies. Supported Vector Stores:
  • ✅ Pinecone
  • ✅ PGVector
  • ✅ Chroma
  • ✅ Weaviate
  • ⚠️ Qdrant (requires SDK)
  • ⚠️ Redis (requires RediSearch)

Complete Custom Ingestion Example

Building a GitHub repository documentation ingestion plugin:
Expandable

Datasource Configuration

For RAG APIs to work, datasources must be configured with: Embedder Configuration:
  • EmbedVendor: Embedder provider ("openai", "ollama", "vertex", "googleai")
  • EmbedModel: Model name (e.g., "text-embedding-3-small" for OpenAI, "nomic-embed-text" for Ollama)
  • EmbedAPIKey: API key if required by embedder
  • EmbedUrl: Embedder endpoint URL
Vector Store Configuration:
  • DBSourceType: Vector store type ("pinecone", "chroma", "pgvector", "qdrant", "redis", "weaviate")
  • DBConnString: Connection URL for vector store
  • DBConnAPIKey: API key if required
  • DBName: Collection/namespace/table name
Important: EmbedModel must be the actual model name (e.g., "text-embedding-3-small"), NOT the vendor name!

RAG Workflow Patterns

Pattern 1: Separate Generate & Store (Full Control)

Best for: Custom chunking algorithms, caching embeddings, using external embedding services.

Pattern 2: Process & Store (Convenience)

Best for: Simple ingestion when you don’t need to inspect or cache embeddings.
Best for: Advanced search strategies, query expansion, multi-vector search.

Datasource Management APIs

For managing datasources programmatically:
Expandable
Required Scopes: datasources.read (list/get/search), datasources.write (create/update/delete)

Error Handling

Expandable
Common Errors:
  • "datasource does not have embedder configured" - Set EmbedVendor/EmbedModel/EmbedAPIKey
  • "datasource does not have vector store configured" - Set DBSourceType/DBConnString/DBName
  • "failed to generate embeddings with openai/openai" - EmbedModel should be model name, not vendor!
  • "vector store connection failed" - Ensure vector store is running and accessible

Advanced Datasource Operations

These operations provide fine-grained control over vector store data through metadata filtering and namespace management.

Delete Documents by Metadata

Delete specific documents from vector stores using metadata filters:
Expandable
Parameters:
  • metadataFilter: map of metadata key-value pairs to match
  • filterMode: "AND" (all conditions must match) or "OR" (any condition matches)
  • dryRun: if true, returns count without deleting
Returns: Number of documents deleted (or would be deleted if dry-run) Scope Required: datasources.write

Query by Metadata Only

Query documents using only metadata filters (no vector similarity):
Expandable
Parameters:
  • metadataFilter: metadata key-value pairs to match
  • filterMode: "AND" or "OR"
  • limit: max results per page (1-100, default: 10)
  • offset: pagination offset
Returns: Array of results and total count (for pagination) Scope Required: datasources.query

List Namespaces

List all namespaces/collections in a vector store:
Returns: Array of namespace info with document counts Scope Required: datasources.read Note: Document count may be -1 if not supported by the vector store.

Delete Namespace

Delete an entire namespace/collection (bulk operation):
Parameters:
  • namespace: namespace/collection name to delete
  • confirm: must be true to proceed (safety check)
Scope Required: datasources.write Warning: This is a destructive operation that deletes all documents in the namespace. Use with caution. Supported Vector Stores:
  • ✅ Full support: Chroma, PGVector, Pinecone, Weaviate
  • ⚠️ Limited: Redis (delete/query by metadata not fully supported)
  • ⚠️ Partial: Qdrant (namespace management only)

Schedule Management

Scope Required: scheduler.manage Available in: AI Studio only Plugins can programmatically manage their scheduled tasks using the Schedule Management API. This complements manifest-based schedule declarations.

Overview

Schedules can be created in two ways:
  1. Manifest Schedules: Declared in plugin.manifest.json, auto-registered when plugin loads
  2. API Schedules: Created programmatically via SDK during Initialize() or at runtime
Both types execute via the ExecuteScheduledTask() capability method.

CreateSchedule

Create a new schedule for your plugin:
Returns: *mgmtpb.ScheduleInfo with schedule details Errors: AlreadyExists if schedule_id already exists for this plugin

GetSchedule

Retrieve schedule details by manifest schedule ID:
Returns: *mgmtpb.ScheduleInfo Errors: NotFound if schedule doesn’t exist

ListSchedules

Get all schedules for your plugin:
Returns: []*mgmtpb.ScheduleInfo array

UpdateSchedule

Update schedule fields (all fields optional):
Returns: *mgmtpb.ScheduleInfo with updated schedule Errors: NotFound if schedule doesn’t exist

DeleteSchedule

Remove a schedule:
Errors: NotFound if schedule doesn’t exist

Complete Example

Expandable

Manifest vs API Schedules

Use Manifest When:
  • Schedule is core to plugin functionality
  • Configuration is static
  • Want schedules registered automatically
Use API When:
  • Schedules are dynamic (based on external data)
  • Need runtime modification
  • Want conditional schedule creation
  • Building schedule management UI
Example: Plugin manifest declares one immutable daily report, creates hourly syncs via API based on configured data sources.

Best Practices Summary

  1. Connection Warmup: Implement SessionAware and warm up Service API in OnSessionReady - this is critical for reliable API access
  2. Runtime Detection: Always check ctx.Runtime before calling runtime-specific services
  3. Type Assertions: Gateway and Studio services return interface{}, type assert to correct response types
  4. Error Handling: Always check errors from Service API calls
  5. Logging: Use ctx.Services.Logger() for consistent structured logging
  6. KV Storage: Understand storage differences between Studio (durable) and Gateway (ephemeral)
  7. Shared Connections: Event Service and Management Service API share the same broker connection - one warmup establishes both
  8. Context Timeouts: Use context timeouts for external calls
  9. Caching: Cache frequently accessed data in KV storage to reduce API calls

Complete Examples

For complete working examples of Service API usage:
  • Studio: examples/plugins/studio/service-api-test/ - Comprehensive Studio Services testing
  • Gateway: examples/plugins/gateway/gateway-service-test/ - Gateway Services examples
  • Rate Limiter: examples/plugins/studio/llm-rate-limiter-multiphase/ - Multi-capability plugin with KV storage
  • Scheduler: examples/plugins/studio/scheduler-demo/ - Scheduled tasks with manifest and API patterns