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 theContext.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, implementSessionAware 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:- The broker connection is time-sensitive and must be established early
- Dialing late (during an RPC call from the UI) may fail if timing is off
- Event subscriptions and Service API calls share the same underlying connection
Legacy Pattern (Still Supported)
The older pattern of extracting the broker ID manually duringInitialize still works but is not recommended:
Expandable
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
Read Data
Delete Data
List Keys
Logger
Structured logging with key-value pairs: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:
Topics that start with
system. are reserved for the object change events of AI Studio. The control plane drops system.* events that come from an edge. Gateway plugins must publish events under their own topics.
Publish Event
Publish an event with a JSON-serializable payload:Expandable
Publish Raw Event
Publish an event with pre-serialized JSON payload (avoids double-serialization):Subscribe to Events
Subscribe to events on a specific topic:Expandable
Subscribe to All Events
Subscribe to all events regardless of topic:Unsubscribe
Remove a subscription:Shutdown().
Event Structure
Events have the following fields:Complete Example: Event-Driven Cache Invalidation
Expandable
Event Service Best Practices
-
Use Appropriate Directions:
DirLocalfor metrics and debugging within a single nodeDirUpfor edge plugins sending data to controlDirDownfor control pushing updates to edges
- Handle Payload Parsing Errors: Always validate and handle JSON unmarshaling errors in event handlers.
- Avoid Blocking in Handlers: Event handlers should be fast. For heavy processing, spawn a goroutine or queue work.
-
Clean Up Subscriptions: Unsubscribe in
Shutdown()for explicit cleanup. -
Use Meaningful Topics: Use dot-separated topic names for clarity (e.g.,
cache.invalidate,config.updated,metrics.report). - 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
Topics must match exactly. The event bus does not support wildcards, so
Subscribe("system.app.*", ...) never receives an event. Subscribe to each topic that you need (system.app.created, system.app.updated, and so on), or use SubscribeAll and filter on ev.Topic. SubscribeAll sends every event on the bus to your handler. Check the topic first, before you decode the payload.Expandable
Example: Audit Log Plugin
Expandable
DirLocal direction, meaning they stay on the control plane and are not forwarded to edge instances.
Studio Services
Available whenctx.Runtime == plugin_sdk.RuntimeStudio.
Notifications
From v2.2.0, plugins can create in-app notifications. AI Studio shows them in the notification bell, and also sends them by email when SMTP is configured. A notification can go to all administrators, to one user, or to both. Requires:notifications.write scope. Studio only.
Resource Type Registration (Runtime)
AI Studio registers the resource types in the manifest when the plugin loads. If the plugin defines its types at runtime (for example, administrators define them inside the plugin), register the types withSyncResourceTypes.
Requires: resource-types.manage scope. Studio only.
ListResourceInstances method for each type. Do not hold locks that this method needs. For more information, refer to Resource Provider Plugins.
Permission Resources (Runtime)
Every plugin with an admin UI has a row in the role editor:plugin:<manifest id>, with read, write, and execute. Declare sub-resources that you know in advance in the rbac block of the manifest. Refer to Permissions (RBAC) Block. Register resources that exist only at runtime with RegisterPermissionResources.
Requires: rbac.register scope. Studio only.
plugins:execute have every plugin permission. Grants for each plugin limit access further.
To check a permission in an RPC handler, implement UserAwareRPCHandler and use the user context:
Can also accepts platform permissions, for example user.Can("llms:read"). AI Studio gives the plugin the permissions of the caller, with the plugin’s own grants included. For this reason, users with plugins:execute and full administrators pass the check. On a host that does not support permissions for each plugin, Can uses IsAdmin. AI Studio checks the admin RPC methods in the rbac.rpc_methods block of the manifest before the call reaches the plugin. Methods that are not in the list need the base write permission of the plugin.
Team Access to Resource Instances (Runtime)
From v2.2.1, a plugin can control which Teams see its resource instances. By default, AI Studio grants every active instance of a plugin resource type to the Default Team. Every user is a member of this Team, so every user sees the instance in the AI Portal. For a type whose instances must reach only specific Teams, register the type withDefaultAccess: plugin_sdk.DefaultAccessExplicit (manifest: "default_access": "explicit"). The plugin then manages the grants itself.
Requires: resource-access.manage scope. Studio only. Each call works only for resource types that this plugin registered. Other calls return PermissionDenied.
- These grants are the same grants that the Teams page edits. The calls read the changes that an administrator makes on the Teams page.
- An instance must be active (
ResourceInstance.IsActive) to appear anywhere. - The Community Edition has no Team segmentation. It ignores
explicit, and instances always join the Default Team. - Active instances of
autotypes (the default) join the Default Team at registration. They also join it when the plugin reports a change withNotifyResourceInstanceChanged.
LLM Operations
Requires:llms.read, llms.write, or llms.proxy scope
List LLMs
Expandable
Get LLM
Call LLM (Streaming)
Requires:llms.proxy scope
Expandable
Call LLM (Simple)
Convenience method for simple calls:Get LLMs Count
examples/plugins/studio/service-api-test/.
Model Prices
From v2.1.0, Studio plugins can list model prices from the control plane. Requires:pricing.read scope.
Governed Metadata (Enterprise)
From v2.2.0, Studio plugins can read, validate, write, and delete the governed metadata of LLMs, tools, data sources, and plugin resource types that support metadata. For schemas, enforcement, and the compliance report, refer to Governed Metadata.- Object types are
llm,tool,datasource, orplugin_resource:<plugin_id>:<slug>. For its own resource types, a plugin can useplugin_resource:self:<slug>(plugin_sdk.SelfResourceObjectType), and AI Studio resolves it. - Object IDs are the numeric ID as a string, or the resource instance ID.
- Scopes:
metadata.read(get, resolve schema, validate, and read the change history) andmetadata.write(set and delete). Declare them underpermissions.servicesin the manifest. - In the Community Edition, writes fail with
FailedPrecondition.
- If the
governed_metadataobject hook of another plugin rejects a write, the call returnsPermissionDenied. - AI Studio audits every successful write or delete with the source
plugin:<id>, and emitssystem.governed_metadata.updatedorsystem.governed_metadata.deleted. - If you use
plugin_resource:self:without a plugin context, the call returnsInvalidArgument. - In the Community Edition,
ListObjectMetadataAuditreturns an empty list.
Governance Reads (Enterprise)
From v2.2.1, governance plugins can read the parts of AI Studio objects and their audit records. For example, an asset catalog can map which agents depend on which LLMs, tools, and MCP servers. Studio only.ListAuditRecordsuses the resource type names of the audit trail:llm,tool,datasource,mcp_server,model_router,semantic_router, andapp.- The Community Edition returns
Unimplementedfor the audit trail and routers. A node that does not store audit records in the database returnsFailedPrecondition. GetAppandListApps(apps.read) return every binding of the App:LlmIds,ToolIds,DatasourceIds,McpServerIds,ModelRouterIds,SemanticRouterIds, andPluginResources({PluginId, ResourceTypeSlug, InstanceId}).
App Lifecycle Control
From v2.2.1, a governance plugin can suspend or reactivate an App, and set flags on it. For example, an asset catalog can suspend the App of an agent when its review lapses. The plugin cannot change what the App can access. Bindings, credentials, and budgets needapps.write, and a governance plugin must not ask for that scope.
Requires: apps.lifecycle scope. Studio only.
- If
isActiveisnil, the App state does not change. You can send only flags. - AI Studio stores flags on the App under
metadata.governance_flags.<name>, as{value, reason, set_by: "plugin:<id>", at}. The App details page shows them. - A call can set a maximum of 16 flags. Flag names can have a maximum of 64 characters, without spaces. Values can have a maximum of 256 characters.
- The
governance_flagskey is reserved. App edits keep the stored flags, App creation drops a suppliedgovernance_flags, andPatchAppMetadatarefuses the key withInvalidArgument. - AI Studio writes each change to the audit trail as
Plugin Update App Governance State, with the reason. - A state change emits
system.app.updated. A plugin that subscribes to this topic also receives its own changes, so its handler must be idempotent.
Gateway Services
Available whenctx.Runtime == plugin_sdk.RuntimeGateway.
Gateway Services provide read-only access to essential gateway information.
Get App
*gwmgmt.GetAppResponse.
Example:
List Apps
*gwmgmt.ListAppsResponse.
Get LLM
*gwmgmt.GetLLMResponse.
List LLMs
*gwmgmt.ListLLMsResponse.
Get Budget Status
*gwmgmt.GetBudgetStatusResponse.
Example:
Expandable
Get Model Price
*gwmgmt.GetModelPriceResponse.
Validate Credential
*gwmgmt.ValidateCredentialResponse.
Example:
Store App
From v2.1.0, gateway plugins can write an App into the local Edge Gateway database. Auth plugins use this to provision Apps without waiting for the next configuration sync. For example, the OAuth2 client-credentials plugin stores an App that AI Studio created for a new client. Requires:apps.write scope. Gateway only. The stored App gets the LLMs, tools, and data sources that the plugin sets, so grant apps.write only to plugins that you trust. The Studio runtime returns an error, so multi-runtime plugins must check ctx.Runtime.
StoreApp creates the App if it does not exist, and updates it if it exists. On update, it replaces the tool and data source associations in one transaction.
Tool Operations (Studio Only)
Requires:tools.read, tools.write, or tools.execute scope
List Tools
Get Tool by ID
Execute Tool
Requires:tools.execute scope
Plugin Operations
Requires:plugins.read or plugins.write scope
List Plugins
Get Plugin by ID
Get Plugins Count
App Operations
Requires:apps.read or apps.write scope
List Apps
List Apps with Filters
ListAppsOptions supports filtering by:
IsActive *bool— Filter by active/inactive statusNamespace string— Filter by namespace (empty = all namespaces)UserID *uint32— Filter by owner user ID
ListApps(ctx, page, limit) function is still available for backward compatibility and returns all apps without filtering.
Get App by ID
Patch App Metadata
UpdateAppWithMetadata for concurrent modifications since it uses database-level transactions with row locking.
Requires: apps.write scope. In versions before 2.2.0, the scope was not mapped, and calls to PatchAppMetadata failed. The key governance_flags is reserved and returns InvalidArgument.
Set a metadata key (value must be JSON-encoded):
apps.write scope.
KV Storage Operations
Requires:kv.read or kv.readwrite scope
Write Data
true if created, false if updated. Pass nil for expireAt for no expiration.
Example:
Expandable
Write Data with TTL
Read Data
Delete Data
List Keys
Data Types
LLMMessage
LLMTool (for tool calling)
Tool
Plugin
App
Error Handling
Service API calls return standard Go errors:- 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
Expandable
Context and Timeouts
Always use contexts with timeouts:Best Practices
-
Check SDK Initialization:
-
Handle Pagination:
Expandable
-
Cache Results:
-
Error Logging:
Scope Requirements Summary
Valid UTF-8 in Protobuf Strings
Protobuf string fields must contain valid UTF-8. From v2.1.0, the SDK cleans strings at its own gRPC boundary, for example inCall() and PortalCall(). If your plugin puts external data (file content, third-party responses) into a protobuf string field, clean the data first. Otherwise the call fails with string field contains invalid UTF-8.
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)
Core RAG APIs
GenerateEmbedding
Generate embeddings for text chunks without storing them.Expandable
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
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
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
datasources.query
Use Case: Standard semantic search - plugin provides text, system handles embedding.
QueryDatasourceByVector
Semantic search using a pre-computed embedding vector.Expandable
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 embedderEmbedUrl: Embedder endpoint URL
DBSourceType: Vector store type ("pinecone","chroma","pgvector","qdrant","redis","weaviate")DBConnString: Connection URL for vector storeDBConnAPIKey: API key if requiredDBName: Collection/namespace/table name
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)
Pattern 2: Process & Store (Convenience)
Pattern 3: Hybrid Search
Datasource Management APIs
For managing datasources programmatically:Expandable
datasources.read (list/get/search), datasources.write (create/update/delete)
Error Handling
Expandable
"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
metadataFilter: map of metadata key-value pairs to matchfilterMode:"AND"(all conditions must match) or"OR"(any condition matches)dryRun: iftrue, returns count without deleting
datasources.write
Query by Metadata Only
Query documents using only metadata filters (no vector similarity):Expandable
metadataFilter: metadata key-value pairs to matchfilterMode:"AND"or"OR"limit: max results per page (1-100, default: 10)offset: pagination offset
datasources.query
List Namespaces
List all namespaces/collections in a vector store:datasources.read
Note: Document count may be -1 if not supported by the vector store.
Delete Namespace
Delete an entire namespace/collection (bulk operation):namespace: namespace/collection name to deleteconfirm: must betrueto proceed (safety check)
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:- Manifest Schedules: Declared in
plugin.manifest.json, auto-registered when plugin loads - API Schedules: Created programmatically via SDK during
Initialize()or at runtime
ExecuteScheduledTask() capability method.
CreateSchedule
Create a new schedule for your plugin:*mgmtpb.ScheduleInfo with schedule details
Errors: AlreadyExists if schedule_id already exists for this plugin
GetSchedule
Retrieve schedule details by manifest schedule ID:*mgmtpb.ScheduleInfo
Errors: NotFound if schedule doesn’t exist
ListSchedules
Get all schedules for your plugin:[]*mgmtpb.ScheduleInfo array
UpdateSchedule
Update schedule fields (all fields optional):*mgmtpb.ScheduleInfo with updated schedule
Errors: NotFound if schedule doesn’t exist
DeleteSchedule
Remove a schedule: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
- Schedules are dynamic (based on external data)
- Need runtime modification
- Want conditional schedule creation
- Building schedule management UI
Best Practices Summary
- Connection Warmup: Implement
SessionAwareand warm up Service API inOnSessionReady- this is critical for reliable API access - Runtime Detection: Always check
ctx.Runtimebefore calling runtime-specific services - Type Assertions: Gateway and Studio services return
interface{}, type assert to correct response types - Error Handling: Always check errors from Service API calls
- Logging: Use
ctx.Services.Logger()for consistent structured logging - KV Storage: Understand storage differences between Studio (durable) and Gateway (ephemeral)
- Shared Connections: Event Service and Management Service API share the same broker connection - one warmup establishes both
- Context Timeouts: Use context timeouts for external calls
- 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