Skip to main content

Using services in another plugin

Import public types from @dsh-ai-providers/core, then declare each runtime service through Cordis injection. Consumer code should not need a vendor package.

The complete list of services, shared call options, and stable error codes is in Core contract reference.

import type { Context } from '@deepseek-ai/cordis'
import type {} from '@dsh-ai-providers/core'

export const inject = ['embeddings']

export function apply(ctx: Context) {
ctx.on('ready', async () => {
const {vectors} = await ctx.embeddings.embed(['first document', 'second document'])
ctx.logger.info('received %d vectors', vectors.length)
})
}

Use optional injection when your plugin can operate without the capability:

export const inject = { optional: ['streamingSpeechToText'] }

The selected service owns credentials, endpoints, and vendor-specific transport. A direct vendor import bypasses that boundary and prevents provider selection from doing its job.

Choose required or optional injection​

Use required injection when the plugin cannot perform its advertised job without the service. DSH then controls startup order and reports the missing dependency instead of letting the plugin fail on its first call. Use optional injection only when you have a real fallback or can disable the affected feature cleanly.

Capability services identify the active provider and model. Record those fields when they help diagnose a result, but do not use them to branch into vendor-specific request code. A consumer that needs a vendor extension should make that dependency explicit rather than assuming the selected provider supports it.

Call priority and cancellation​

Capability calls accept shared call options where supported:

const result = await ctx.rerankers.rerank(query, documents, {
priority: 'background',
signal: abortController.signal,
})

Use foreground priority for work blocking an active user interaction. Use background priority for indexing, prefetching, and maintenance. Pass an AbortSignal whenever the caller has a meaningful cancellation lifecycle.

Streams​

Consume or explicitly cancel returned streams. The concurrency gate holds capacity until a stream completes or is discarded.

For live transcription, first check whether ctx.streamingSpeechToText is present. Start a session, send audio chunks in order, consume transcript events, then close or abort the session according to the core contract.

Manage a local model​

ctx.aiModels resolves model controls by LLM route. The service is present when the runtime plugin is loaded, but each route decides which operations it supports. Check operations() before showing a control or calling it.

import type { Context } from '@deepseek-ai/cordis'
import type {} from '@dsh-ai-providers/core'

export const inject = ['aiModels']

export async function unloadWhenIdle(ctx: Context, route: string, model: string) {
if (!ctx.aiModels.operations(route).includes('unload')) return
await ctx.aiModels.unload(route, model)
}

The available methods are status(route, model), load(route, model), and unload(route, model). Each accepts an optional AbortSignal. status() returns a provider-neutral state and may include memoryBytes when the server reports it.

Loading and unloading change the provider process. They are not scoped to the calling chat, and unloading can disrupt another request using the same model. Tie these calls to an explicit user action or to a scheduler that owns the server. Do not unload a model after every inference call.

An unknown route fails with not-configured. A route without model controls, or without the requested operation, fails with unsupported. Authentication failures are rejected; transport and server failures are unavailable.

Handling failures​

Catch AiError and branch on its category. Treat message text as diagnostic information, not as an API contract. Preserve the error cause when wrapping it for your own plugin.

CodeConsumer response
not-configuredExplain which capability must be selected in settings.
invalid-inputCorrect or report the caller's input; retrying it unchanged will not help.
unsupportedDisable the unsupported option or ask for a compatible provider.
rejectedSurface a concise configuration, credential, quota, or model error.
unavailableRetry only when the operation is safe to repeat, preferably with backoff.
cancelledEnd quietly when cancellation was expected; otherwise preserve the cause.

Integration checklist​

  • Depend on @dsh-ai-providers/core for contracts, not a vendor implementation.
  • Declare every context service through Cordis injection.
  • Pass signal from the lifecycle that owns the request.
  • Mark indexing and maintenance calls as background.
  • Fully consume or cancel streams.
  • Check ctx.aiModels.operations(route) before offering a model-management action.
  • Treat load and unload as shared server operations, not chat cleanup.
  • Treat returned model names, dimensions, token counts, voices, and media metadata as provider results rather than fixed constants.
  • Test not-configured, cancellation, unload, and a provider-side failure in addition to the successful path.