112 lines
2.9 KiB
Markdown
112 lines
2.9 KiB
Markdown
# Plugin configuration
|
|
|
|
English | [中文](config.zh.md)
|
|
|
|
Accept configuration supplied through `cordis.yml`.
|
|
|
|
## Define the Config type
|
|
|
|
Export a `Config` type and a same-named Schemastery schema. Put defaults directly on the schema fields:
|
|
|
|
```ts
|
|
import type { Context } from 'cordis'
|
|
import Schema from 'schemastery'
|
|
|
|
export const name = 'my-plugin'
|
|
|
|
export interface Config {
|
|
greeting: string
|
|
maxRetries: number
|
|
verbose?: boolean
|
|
}
|
|
|
|
export const Config: Schema<Config> = Schema.object({
|
|
greeting: Schema.string().default('Hello'),
|
|
maxRetries: Schema.number().default(3),
|
|
verbose: Schema.boolean().default(false),
|
|
})
|
|
|
|
export function apply(ctx: Context, config: Config) {
|
|
console.log(config.greeting) // User value or schema default.
|
|
}
|
|
```
|
|
|
|
Configure it in `cordis.yml`:
|
|
|
|
```yaml
|
|
- name: './src/my-plugin.ts'
|
|
config:
|
|
greeting: 'Hi there'
|
|
maxRetries: 5
|
|
```
|
|
|
|
When loading the plugin, Cordis uses the exported schema to validate configuration and fill defaults. Do not export a plain object as `Config`; it does not implement the Standard Schema interface required by Cordis.
|
|
|
|
## Schema validation
|
|
|
|
Use Schemastery to express stricter validation:
|
|
|
|
```ts
|
|
import type { Context } from 'cordis'
|
|
import Schema from 'schemastery'
|
|
|
|
export const name = 'validated-plugin'
|
|
|
|
export interface Config {
|
|
apiKey: string
|
|
timeout: number
|
|
mode: 'fast' | 'accurate'
|
|
}
|
|
|
|
export const Config = Schema.object({
|
|
apiKey: Schema.string().required(),
|
|
timeout: Schema.number().default(30000),
|
|
mode: Schema.union(['fast', 'accurate']).default('fast'),
|
|
})
|
|
|
|
export function apply(ctx: Context, config: Config) {
|
|
// config is validated and type-safe.
|
|
}
|
|
```
|
|
|
|
The schema runs while the plugin loads. Invalid configuration fails the load with an actionable error.
|
|
|
|
## Design principles
|
|
|
|
### Do not hardcode tunable values
|
|
|
|
Harness requires **anything that two deployments may want to set differently to be a configuration field**.
|
|
|
|
```ts
|
|
// Wrong: hardcoded timeout.
|
|
const TIMEOUT = 30000
|
|
|
|
// Correct: configurable.
|
|
export interface Config {
|
|
timeoutMs: number // Defaults to 30000.
|
|
}
|
|
```
|
|
|
|
The test is whether `cordis.yml` can change the value without a code edit.
|
|
|
|
### Fail loudly on invalid configuration
|
|
|
|
If configuration refers to a missing model or another nonexistent resource, fail early instead of silently skipping it:
|
|
|
|
```ts ignore-check
|
|
export function apply(ctx: Context, config: Config) {
|
|
if (!ctx.llm.models().includes(config.model)) {
|
|
throw new Error(`Model "${config.model}" is not registered by any LLM adapter`)
|
|
}
|
|
}
|
|
```
|
|
|
|
## Work with HMR
|
|
|
|
A configuration edit hot-replaces the plugin: the framework unloads the old instance and loads a new one. Because registrations are effects and clean themselves up, replacement does not retain the old instance's registrations.
|
|
|
|
## Next steps
|
|
|
|
- [Plugins and lifecycle](../framework/) — understand the full plugin lifecycle
|
|
- [Services and dependencies](../framework/service.md) — provide a service to other plugins
|