Migración a la configuración tipada de plugins
La configuración de instancia tipada introduce un cambio incompatible para cualquier complemento anterior a la versión 1.0 que lea la configuración del operador. Esta página es el documento de migración para autores de complementos y operadores: qué se rompe, por qué y los pasos exactos para corregir un paquete.
El comportamiento descrito aquí se comprueba con crates/zeroclaw-plugins/src/config.rs, crates/zeroclaw-plugins/src/instance.rs y la ruta de admisión en crates/zeroclaw-plugins/src/host.rs.
Decisión de lanzamiento
La aplicación de la restricción se incluye con la funcionalidad. No hay ninguna capa de compatibilidad, período de gracia ni indicador de exclusión. Los complementos son una superficie experimental anterior a la versión 1.0, por lo que el proyecto acepta el cambio incompatible en lugar de mantener permanentemente una ruta de configuración más débil: un respaldo sin tipos tendría que entregar a un invitado valores que el host no puede tipar, nombrar ni acotar, que es exactamente el agujero que cierra esta funcionalidad.
Los paquetes que no migran dejan de detectarse. Nada se degrada silenciosamente y ninguna configuración parcial llega al código invitado.
Qué se rompe
Tres cosas, de forma independiente:
- Un manifiesto que solicita
config_readsinconfig_schemaya no se detecta ni se instala. La relación entre ambos es bicondicional: un esquema sin el permiso también no es válido. - Las entradas de configuración cuya clave es el nombre del paquete o de la vinculación ya no se consultan. Los valores de los operadores ahora se encuentran bajo una clave de instancia completa derivada del paquete, la capacidad y la vinculación.
- Los invitados reciben JSON tipado, no un mapa de cadenas. Un invitado que antes analizaba las cadenas por sí mismo ahora obtiene valores booleanos, números, matrices y objetos reales.
Por qué el host necesita un esquema
Los valores del operador se almacenan como un mapa de cadenas marcado como secreto y cifrado en reposo, y el invitado es código de terceros no confiable. Sin un contrato declarado, el host no puede responder a dos preguntas que debe responder antes de que se inicie el invitado: qué claves puede recibir este paquete y qué tipo tiene cada valor. Los mundos WIT son fijos y compartidos entre todos los plugins, por lo que los tipos de configuración específicos de cada paquete no pueden residir en la ABI. El manifiesto es el único lugar donde se puede declarar el contrato, y additionalProperties = false junto con un mapa properties explícito es lo que hace que la concesión config_read tenga un alcance enumerable.
Pasos de autoría
1. Declara el esquema
Añade un objeto cerrado de Draft 2020-12 que cubra exactamente las claves que lee tu plugin. Cada propiedad de nivel superior debe resolverse en un tipo explícito: string, boolean, integer, number, array u object.
name = "my-plugin"
version = "0.2.0"
wasm_path = "my_plugin.wasm"
capabilities = ["channel"]
permissions = ["config_read"]
[config_schema]
"$schema" = "https://json-schema.org/draft/2020-12/schema"
type = "object"
required = ["bot_token"]
additionalProperties = false
[config_schema.properties.bot_token]
type = "string"
minLength = 1
[config_schema.properties.poll_interval_secs]
type = "integer"
minimum = 1
[config_schema.properties.allowed_chats]
type = "array"
El host impone estos límites al propio esquema: 64 KiB serializado, como máximo 32 niveles de anidamiento, sin $id, y los destinos de $ref deben ser punteros JSON locales. Las referencias remotas se rechazan, por lo que un esquema nunca provoca una solicitud de red.
Las palabras clave de claves dinámicas no forman parte de este dialecto: patternProperties, propertyNames y unevaluatedProperties se rechazan en la raíz, porque el host materializa un valor solo para una clave cuyo nombre aparece en el mapa properties de la raíz, por lo que las claves admitidas por pattern nunca llegarían a tu plugin.
pattern usa el dialecto de expresiones regulares de tiempo lineal
El host resuelve la configuración recompilando y volviendo a validar tu esquema en cada llamada, y ese trabajo se ejecuta en el host, no dentro del presupuesto de combustible de tu componente. Por eso, pattern está restringido a expresiones regulares cuyo coste el host pueda predecir:
- Las referencias inversas y las aserciones de búsqueda se rechazan.
(\w+)\s\1,(?=...),(?<=...)y similares necesitan un motor con retroceso. En su lugar, los patrones se compilan con el dialecto linealregex, que realiza la coincidencia en un tiempo proporcional a la longitud del valor, independientemente de cómo esté escrito el patrón. - Un solo patrón no puede compilarse en más de 256 KiB de programa. Esto afecta a los recuentos de repetición grandes:
^[\s\S]{0,200}$está bien,^[\s\S]{0,1000}$no. UsamaxLengthpara los límites de longitud; no cuesta nada comprobarlo y expresa lo que quieres decir.
Ambos rechazos se producen durante la instalación con un error InvalidManifest que indica el esquema, por lo que un complemento cuyo pattern el host no puede acotar nunca llega a ejecutarse. Los patrones estructurales se comportan como cabría esperar: los slugs, los UUID, las direcciones de correo electrónico, las URL y el texto libre corto con límites definidos se compilan correctamente.
2. Haga coincidir las codificaciones de los valores
El almacenamiento del operador sigue siendo un mapa de cadenas. El esquema indica al host cómo leer cada cadena almacenada:
| Tipo declarado | Lo que almacena el operador | Lo que recibe el huésped |
|---|---|---|
string | secret-value | "secret-value" |
boolean | true | true |
integer | 4 | 4 |
number | 0.5 | 0.5 |
array | ["a","b"] | ["a","b"] |
object | {"k":"v"} | {"k":"v"} |
Todo lo que no se pueda analizar sintácticamente como el tipo declarado se rechaza antes de que se ejecute el código.
3. Decide qué es obligatorio y qué es opcional para cada clave
Las concesiones efectivas se comprueban por separado de las solicitudes del manifiesto. Cuando se solicita config_read pero no se concede, el host valida un objeto vacío contra tu esquema:
- Un esquema con todos los campos opcionales recibe
{}, así que proporciona un valor predeterminado del lado del invitado para cada campo. - Un campo
requiredfalla de forma cerrada, que es lo que quieres para las credenciales. Un canal que no puede autenticarse debe negarse a iniciarse en lugar de ejecutarse con una configuración incompleta.
4. Deserializar JSON tipado en el invitado
Reemplaza el análisis de cadenas por una única deserialización del objeto inyectado. Los complementos de herramientas leen la clave reservada __config, que el host combina con los argumentos de la llamada después de eliminar cualquier valor proporcionado por el modelo con ese nombre.
5. Recompila y vuelve a firmar
config_schema está cubierta por la firma del manifiesto, por lo que un paquete firmado debe volver a firmarse después de añadirla. Consulta Distribución de plugins para ver el flujo de firma.
Pasos del operador
Los bloques [[plugins.entries]] existentes que tienen el nombre de un paquete o un enlace no se leen. La ruta de migración disponible depende de la capacidad del complemento.
Instancias de herramientas
Los comandos install e info pueden derivar una instancia de herramienta a partir de la vinculación de herramienta predeterminada del paquete. Para mover los valores de la herramienta a la nueva clave:
- Ejecuta
zeroclaw plugin info <package>para imprimir la clave de instancia completa, que tiene el formatozpi1_.... - Cambia el
namede la entrada existente por esa clave, o reinstala el complemento para crear la entrada y, a continuación, establece los valores conzeroclaw config set plugins.entries.<instance-key>.config.<key>. - Guarda la configuración. Los valores permanecen cifrados en reposo.
La clave es una codificación versionada y reversible del paquete, la capacidad y el enlace, por lo que dos paquetes pueden usar un enlace denominado main sin compartir credenciales. Las instalaciones nuevas inicializan e imprimen automáticamente esta clave de la herramienta.
Instancias de canal
Una clave de canal incluye el alias de canal configurado. zeroclaw plugin install y zeroclaw plugin info conocen el paquete, pero no son propietarios de ese alias, por lo que no pueden derivar, imprimir ni inicializar una clave de canal y no deben inventar un sustituto a nivel de paquete. La construcción de canales consciente de alias y la resolución de la configuración en tiempo de ejecución se incorporaron en zeroclaw#10146: un demonio construye una instancia de canal declarada explícitamente y resuelve su configuración tipada a partir de zpi1(package, channel, alias), tomando como clave el alias configurado real.
La visualización automática de la clave de plugin info y la precarga durante la instalación para las instancias de canal siguen siendo manuales hasta la ceremonia de concesión en zeroclaw#9584. Hasta que se complete esa ceremonia, los operadores precargan manualmente la clave del canal con zeroclaw config set, en lugar de que install o info la muestren y precarguen por ellos, por lo que un paquete exclusivo del canal que dependa de la ruta automática de claves de install e info aún no está completo.
Diagnóstico de un rechazo
| Mensaje | Causa |
|---|---|
solicita config_read, pero no declara ningún config_schema | paso 1 no completado |
declara config_schema sin solicitar config_read | elimina el esquema o añade el permiso |
config_schema debe establecer additionalProperties = false | el objeto raíz está abierto |
config_schema no debe declarar <keyword> en la raíz | La raíz usa una palabra clave de clave dinámica; indica en su lugar el nombre de cada clave en properties |
| la propiedad usa un tipo no compatible | una propiedad no tiene un tipo admitido explícito o un $ref local no resoluble |
config contiene una propiedad que no está presente en config_schema | una clave de operador no está declarada; a menudo, se trata de un error tipográfico |
| la propiedad de configuración debe ser un entero JSON | la cadena almacenada no se puede analizar como el tipo declarado |
la configuración no cumple config_schema en <path> | no se cumplió una restricción como minimum o required |
Paquetes propios
Cada paquete publicado en zeroclaw-labs/zeroclaw-plugins solicita config_read, y ninguno había declarado config_schema cuando esto se incorporó, por lo que todos necesitan el paso 1 y el paso 5. La migración se registra en ese repositorio en lugar de aquí, ya que los paquetes tienen versiones independientes del host. Los paquetes de herramientas pueden completar ahora el paso de la clave del operador. Los paquetes que solo contienen canales deben esperar a la ruta de claves compatible con alias descrita arriba antes de que el rastreador los marque o publique como migrados para este contrato.
Complementos de memoria
Los complementos de memoria aún no tienen una exportación de configuración y no deben solicitar config_read hasta que exista esa ABI.