feat(server-shared): events

This commit is contained in:
Neko Ayaka
2026-02-07 03:31:42 +08:00
parent 9e5034fffc
commit 892c1a2d4a
9 changed files with 815 additions and 128 deletions
+1 -1
View File
@@ -67,7 +67,7 @@
"smol-toml": "^1.6.0",
"taze": "^19.9.2",
"tinyexec": "^1.0.2",
"tsdown": "^0.17.4",
"tsdown": "catalog:",
"tsx": "^4.21.0",
"turbo": "^2.7.5",
"typescript": "~5.9.3",
+3
View File
@@ -0,0 +1,3 @@
# @proj-airi/plugin-sdk
Runtime-agnostic SDK for AIRI plugins.
+3
View File
@@ -31,5 +31,8 @@
"dev": "pnpm run build",
"build": "tsdown",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@moeru/eventa": "catalog:"
}
}
+9
View File
@@ -0,0 +1,9 @@
import { defineConfig } from 'tsdown'
export default defineConfig({
entry: [
'src/index.ts',
],
dts: true,
format: 'esm',
})
+1 -1
View File
@@ -33,7 +33,7 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@xsai/shared": "catalog:",
"@moeru/eventa": "catalog:",
"@xsai/shared-chat": "catalog:"
}
}
@@ -1,5 +1,7 @@
import type { AssistantMessage, CommonContentPart, Message, ToolMessage, UserMessage } from '@xsai/shared-chat'
import { defineEventa } from '@moeru/eventa'
export interface DiscordGuildMember {
nickname: string
displayName: string
@@ -13,22 +15,38 @@ export interface Discord {
channelId?: string
}
export interface MetadataEventSource {
export interface PluginIdentity {
/**
* Stable module/plugin identifier (shared across instances).
* Stable plugin identifier (shared across instances).
* Example: "telegram-bot", "stage-tamagotchi".
*/
plugin: string
id: string
/**
* Unique instance id for this module run (per process/deployment).
* Example: "telegram-01", "stage-ui-2f7c9".
*/
instanceId: string
/**
* Optional semantic version for the module/plugin.
* Optional semantic version for the plugin.
* Example: "0.8.1-beta.7".
*/
version?: string
/**
* Optional labels attached to the plugin manifest.
* Example: { env: "prod", app: "telegram", devtools: "true" }.
*/
labels?: Record<string, string>
}
export interface ModuleIdentity {
/**
* Unique module instance id for this module run (per process/deployment).
* Example: "telegram-01", "stage-ui-2f7c9".
*/
id: string
/**
* Module identity kind. For now only plugin-backed modules are supported.
*/
kind: 'plugin'
/**
* Plugin identity associated with this module instance.
*/
plugin: PluginIdentity
/**
* K8s-style labels for routing and policy selectors.
* Example: { env: "prod", app: "telegram", devtools: "true" }.
@@ -36,6 +54,295 @@ export interface MetadataEventSource {
labels?: Record<string, string>
}
export type MetadataEventSource = ModuleIdentity
/**
* Static schema metadata for module configuration.
* This is transport-friendly and can be paired with a JSON Schema-like object.
*
* Example:
* {
* id: "airi.config.stage-ui",
* version: 2,
* schema: { type: "object", properties: { model: { type: "string" } }, required: ["model"] },
* }
*/
export interface ModuleConfigSchema {
id: string
version: number
/**
* Optional JSON Schema-like descriptor for tooling/validation.
* Keep it JSON-serializable and avoid runtime-only values.
*/
schema?: Record<string, unknown>
}
/**
* Module dependency declaration.
*
* Use this during prepare/probe to describe what a module needs before
* it can decide its dynamic contributions. Dependencies can change at
* runtime if peers go offline.
*
* Example:
* { role: "llm:orchestrator", min: "v1", optional: true }
*/
export interface ModuleDependency {
/**
* Logical dependency role (preferred over hard-coded plugin ids).
* Example: "llm:orchestrator"
*/
role: string
/**
* Optional dependency flag.
*/
optional?: boolean
/**
* Version constraint hints.
*/
version?: string
min?: string
max?: string
/**
* Additional constraint metadata (JSON-serializable).
*/
constraints?: Record<string, unknown>
}
/**
* Dynamic contributions emitted by a module after configuration.
*
* Unlike static manifests, contributions can be updated or revoked at
* runtime. This is where capabilities, provider registrations, and UI
* extensions should be declared.
*
* Example:
* {
* capabilities: ["context.aggregate"],
* providers: [{ id: "vscode-context", type: "context-source" }],
* ui: { widgets: ["context-summary-panel"] }
* }
*/
export interface ModuleContribution {
/**
* Dynamic capabilities exposed by the module.
*/
capabilities?: string[]
/**
* Provider registry contributions (shape defined by the host).
*/
providers?: Array<Record<string, unknown>>
/**
* UI contribution descriptors (widgets, toolbar items, etc).
*/
ui?: Record<string, unknown>
/**
* Hook registrations (event handlers, interceptors, etc).
*/
hooks?: Array<Record<string, unknown>>
/**
* Additional resources or metadata.
*/
resources?: Record<string, unknown>
}
/**
* Lifecycle phases for module orchestration and UX.
*/
export type ModulePhase
= | 'announced'
| 'preparing'
| 'prepared'
| 'configuration-needed'
| 'configured'
| 'ready'
| 'failed'
export type Localizable
= | string
| {
/**
* Localization key owned by the module.
* Example: "config.deprecated.model_driver.legacy"
*/
key: string
/**
* Fallback display string when translation is unavailable.
*/
fallback?: string
/**
* Params for string interpolation.
*/
params?: Record<string, string | number | boolean>
}
export interface ModuleConfigNotice {
/**
* Machine-friendly key for analytics or client-side mapping.
*/
code?: string
/**
* Human readable message or localization key.
*/
message?: Localizable
/**
* JSON pointer or dotted path in config.
* Example: "driver.legacyModelPath"
*/
path?: string
/**
* Suggested replacement path or alternative.
*/
replacedBy?: string
/**
* Version since the notice applies.
*/
since?: number
/**
* Link to docs or migration guide.
*/
link?: string
}
export interface ModuleConfigStep {
/**
* Suggested action to complete configuration.
* Use code for UI rendering or message for fallback.
*/
code?: string
message?: Localizable
/**
* Optional targeted field(s).
*/
paths?: string[]
}
export interface ModuleConfigPlan {
/**
* Schema that this plan targets.
*/
schema: ModuleConfigSchema
/**
* Missing required paths for current schema/version.
*/
missing?: string[]
/**
* Invalid fields with reasons (runtime validation result).
*/
invalid?: Array<{ path: string, reason: string }>
/**
* Recommended defaults computed at runtime (may be environment-specific).
*/
defaults?: Record<string, unknown>
/**
* Deprecated fields/behaviors detected in current config.
*/
deprecated?: Array<string | ModuleConfigNotice>
/**
* Suggested migration steps between schema versions.
*/
migrations?: Array<{
from: number
to: number
steps?: Array<string | ModuleConfigStep>
notes?: Array<string | ModuleConfigNotice>
}>
/**
* Human- or UI-friendly next actions to resolve partial config.
*/
nextSteps?: Array<string | ModuleConfigStep>
/**
* Non-blocking issues that should be shown to the user/operator.
*/
warnings?: Array<string | ModuleConfigNotice>
}
export interface ModuleConfigValidation {
/**
* Overall validation status.
*
* - valid: all required fields present and valid.
* - partial: config is structurally OK but missing required fields; can be fixed by patches.
* - invalid: one or more fields are present but invalid (type/range/format); requires correction.
*/
status: 'partial' | 'valid' | 'invalid'
/**
* Missing required fields (only for partial/invalid).
*/
missing?: string[]
/**
* Invalid fields with reasons (only for invalid).
*/
invalid?: Array<{ path: string, reason: Localizable }>
/**
* Non-blocking issues (e.g., deprecations, best-practice notices).
*/
warnings?: Array<string | ModuleConfigNotice>
}
/**
* Config payload envelope for plan/apply/validate/commit.
*
* Example:
* {
* configId: "stage-ui-live2d",
* revision: 12,
* schemaVersion: 2,
* full: { model: "Hiyori", driver: { type: "live2d" } },
* }
*/
export interface ModuleConfigEnvelope<C = Record<string, unknown>> {
configId: string
/**
* Monotonic revision number for this configId.
*/
revision: number
/**
* Schema version this config targets.
*/
schemaVersion: number
/**
* Optional source identity (who produced this config).
*/
source?: ModuleIdentity
/**
* Full config payload (use when first applying or rehydrating).
*/
full?: C
/**
* Partial patch payload (use when updating or filling missing fields).
*/
patch?: Partial<C>
/**
* If patch is used, baseRevision should be set for optimistic concurrency.
*/
baseRevision?: number
}
export interface ModuleCapability {
/**
* Stable capability id within a module.
* Example: "memory.write", "vision.ocr".
*/
id: string
/**
* Human-friendly name.
*/
name?: string
/**
* Optional localized description.
*/
description?: Localizable
/**
* Capability-specific config schema (if needed).
*/
configSchema?: ModuleConfigSchema
/**
* Additional metadata for tooling/UI.
*/
metadata?: Record<string, unknown>
}
export type RouteTargetExpression
= | { type: 'and', all: RouteTargetExpression[] }
| { type: 'or', any: RouteTargetExpression[] }
@@ -162,7 +469,7 @@ export type WebSocketEventDataInputs = WebSocketEventInputText | WebSocketEventI
export type WebSocketEventInputs = WebSocketEventOf<'input:text'> | WebSocketEventOf<'input:text:voice'> | WebSocketEventOf<'input:voice'>
export interface WebSocketEventBaseMetadata {
source?: MetadataEventSource
source?: ModuleIdentity
event?: {
id?: string
parentId?: string
@@ -177,7 +484,7 @@ export interface WebSocketBaseEvent<T, D, S extends string = string> {
*/
source?: WebSocketEventSource | S
metadata: {
source: MetadataEventSource
source: ModuleIdentity
event: {
id: string
parentId?: string
@@ -194,56 +501,468 @@ export type WithOutputSource<Source extends keyof OutputSource> = {
[S in Source]: OutputSource[S]
}
// Module orchestration (local or remote transport):
//
// 1) module:authenticate → module:authenticated
// 2) registry:modules:sync (host → module bootstrap)
// 3) module:announce (identity, deps, config schema)
// 4) module:prepared
// 5) module:configuration:* (validate/plan/commit flow)
// 6) module:configuration:configured
// 7) module:contribute:capability:offer (repeat per capability)
// 8) module:contribute:capability:configuration:* (optional)
// 9) module:contribute:capability:activated
// 10) module:status (ready)
// 11) module:status:change (to re-run phases)
interface ModuleAuthenticateEvent {
token: string
}
interface ModuleAuthenticatedEvent {
authenticated: boolean
}
interface RegistryModulesSyncEvent {
modules: Array<{
name: string
index?: number
identity: ModuleIdentity
}>
}
interface ErrorEvent {
message: string
}
interface ModuleAnnounceEvent<C = undefined> {
name: string
identity: ModuleIdentity
possibleEvents: Array<(keyof WebSocketEvents<C>)>
configSchema?: ModuleConfigSchema
dependencies?: ModuleDependency[]
}
interface ModulePreparedEvent {
identity: ModuleIdentity
missingDependencies?: ModuleDependency[]
}
interface ModuleConfigurationNeededEvent<C = undefined> {
identity: ModuleIdentity
schema?: ModuleConfigSchema
current?: ModuleConfigEnvelope<C>
reason?: string
}
interface ModuleStatusEvent {
identity: ModuleIdentity
phase: ModulePhase
reason?: string
details?: Record<string, unknown>
}
interface ModuleConfigurationValidateRequestEvent<C = undefined> {
identity: ModuleIdentity
current?: ModuleConfigEnvelope<C>
}
interface ModuleConfigurationValidateResponseEvent<C = undefined> {
identity: ModuleIdentity
validation: ModuleConfigValidation
plan?: ModuleConfigPlan
current?: ModuleConfigEnvelope<C>
}
interface ModuleConfigurationValidateStatusEvent {
identity: ModuleIdentity
state: 'queued' | 'working' | 'done' | 'failed'
note?: string
progress?: number
}
interface ModuleConfigurationPlanRequestEvent<C = undefined> {
identity: ModuleIdentity
plan?: ModuleConfigPlan
current?: ModuleConfigEnvelope<C>
}
interface ModuleConfigurationPlanResponseEvent<C = undefined> {
identity: ModuleIdentity
plan: ModuleConfigPlan
current?: ModuleConfigEnvelope<C>
}
interface ModuleConfigurationPlanStatusEvent {
identity: ModuleIdentity
state: 'queued' | 'working' | 'done' | 'failed'
note?: string
progress?: number
}
interface ModuleConfigurationCommitEvent<C = undefined> {
identity: ModuleIdentity
config: ModuleConfigEnvelope<C>
}
interface ModuleConfigurationCommitStatusEvent {
identity: ModuleIdentity
state: 'queued' | 'working' | 'done' | 'failed'
note?: string
progress?: number
}
interface ModuleConfigurationConfiguredEvent<C = undefined> {
identity: ModuleIdentity
config: ModuleConfigEnvelope<C>
}
interface ModuleContributeCapabilityOfferEvent {
identity: ModuleIdentity
capability: ModuleCapability
}
interface ModuleContributeCapabilityConfigurationNeededEvent<C = undefined> {
identity: ModuleIdentity
capabilityId: string
schema?: ModuleConfigSchema
current?: ModuleConfigEnvelope<C>
reason?: string
}
interface ModuleContributeCapabilityConfigurationValidateRequestEvent<C = undefined> {
identity: ModuleIdentity
capabilityId: string
current?: ModuleConfigEnvelope<C>
}
interface ModuleContributeCapabilityConfigurationValidateResponseEvent<C = undefined> {
identity: ModuleIdentity
capabilityId: string
validation: ModuleConfigValidation
plan?: ModuleConfigPlan
current?: ModuleConfigEnvelope<C>
}
interface ModuleContributeCapabilityConfigurationValidateStatusEvent {
identity: ModuleIdentity
capabilityId: string
state: 'queued' | 'working' | 'done' | 'failed'
note?: string
progress?: number
}
interface ModuleContributeCapabilityConfigurationPlanRequestEvent<C = undefined> {
identity: ModuleIdentity
capabilityId: string
plan?: ModuleConfigPlan
current?: ModuleConfigEnvelope<C>
}
interface ModuleContributeCapabilityConfigurationPlanResponseEvent<C = undefined> {
identity: ModuleIdentity
capabilityId: string
plan: ModuleConfigPlan
current?: ModuleConfigEnvelope<C>
}
interface ModuleContributeCapabilityConfigurationPlanStatusEvent {
identity: ModuleIdentity
capabilityId: string
state: 'queued' | 'working' | 'done' | 'failed'
note?: string
progress?: number
}
interface ModuleContributeCapabilityConfigurationCommitEvent<C = undefined> {
identity: ModuleIdentity
capabilityId: string
config: ModuleConfigEnvelope<C>
}
interface ModuleContributeCapabilityConfigurationCommitStatusEvent {
identity: ModuleIdentity
capabilityId: string
state: 'queued' | 'working' | 'done' | 'failed'
note?: string
progress?: number
}
interface ModuleContributeCapabilityConfigurationConfiguredEvent<C = undefined> {
identity: ModuleIdentity
capabilityId: string
config: ModuleConfigEnvelope<C>
}
interface ModuleContributeCapabilityActivatedEvent {
identity: ModuleIdentity
capabilityId: string
active: boolean
reason?: string
}
interface ModuleStatusChangeEvent {
identity: ModuleIdentity
phase: ModulePhase
reason?: string
details?: Record<string, unknown>
}
interface UiConfigureEvent<C = undefined> {
moduleName: string
moduleIndex?: number
config: C | Record<string, unknown>
}
type OutputGenAiChatToolCallEvent = {
toolCalls: ToolMessage[]
} & Partial<WithInputSource<'stage-web' | 'stage-tamagotchi' | 'discord'>> & Partial<WithOutputSource<'gen-ai:chat'>>
type OutputGenAiChatMessageEvent = {
message: AssistantMessage
} & Partial<WithInputSource<'stage-web' | 'stage-tamagotchi' | 'discord'>> & Partial<WithOutputSource<'gen-ai:chat'>>
interface OutputGenAiChatUsage {
promptTokens: number
completionTokens: number
totalTokens: number
source: 'provider-based' | 'estimate-based'
}
type OutputGenAiChatCompleteEvent = {
message: AssistantMessage
toolCalls: ToolMessage[]
usage: OutputGenAiChatUsage
} & Partial<WithInputSource<'stage-web' | 'stage-tamagotchi' | 'discord'>> & Partial<WithOutputSource<'gen-ai:chat'>>
interface SparkNotifyEvent {
id: string
eventId: string
lane?: string
kind: 'alarm' | 'ping' | 'reminder'
urgency: 'immediate' | 'soon' | 'later'
headline: string
note?: string
payload?: Record<string, unknown>
ttlMs?: number
requiresAck?: boolean
destinations: Array<string>
metadata?: Record<string, unknown>
}
interface SparkEmitEvent {
id: string
eventId?: string
state: 'queued' | 'working' | 'done' | 'dropped' | 'blocked' | 'expired'
note?: string
destinations: Array<string>
metadata?: Record<string, unknown>
}
interface SparkCommandGuidanceOption {
label: string
steps: Array<string>
rationale?: string
possibleOutcome?: Array<string>
risk?: 'high' | 'medium' | 'low' | 'none'
fallback?: Array<string>
triggers?: Array<string>
}
interface SparkCommandGuidance {
type: 'proposal' | 'instruction' | 'memory-recall'
/**
* Personas can be used to adjust the behavior of sub-agents.
* For example, when using as NPC in games, or player in Minecraft,
* the persona can help define the character's traits and decision-making style.
*
* Example:
* persona: {
* "bravery": "high",
* "cautiousness": "low",
* "friendliness": "medium"
* }
*/
persona?: Record<string, 'very-high' | 'high' | 'medium' | 'low' | 'very-low'>
options: Array<SparkCommandGuidanceOption>
}
interface SparkCommandEvent {
id: string
eventId?: string
parentEventId?: string
commandId: string
interrupt: 'force' | 'soft' | false
priority: 'critical' | 'high' | 'normal' | 'low'
intent: 'plan' | 'proposal' | 'action' | 'pause' | 'resume' | 'reroute' | 'context'
ack?: string
guidance?: SparkCommandGuidance
contexts?: Array<ContextUpdate>
destinations: Array<string>
}
interface TransportConnectionHeartbeatEvent {
kind: MessageHeartbeatKind
message: MessageHeartbeat | string
at?: number
}
type ContextUpdateEvent = ContextUpdate
export const moduleAuthenticate = defineEventa<ModuleAuthenticateEvent>('module:authenticate')
export const moduleAuthenticated = defineEventa<ModuleAuthenticatedEvent>('module:authenticated')
export const registryModulesSync = defineEventa<RegistryModulesSyncEvent>('registry:modules:sync')
export const error = defineEventa<ErrorEvent>('error')
export const moduleAnnounce = defineEventa<ModuleAnnounceEvent>('module:announce')
export const modulePrepared = defineEventa<ModulePreparedEvent>('module:prepared')
export const moduleConfigurationNeeded = defineEventa<ModuleConfigurationNeededEvent>('module:configuration:needed')
export const moduleStatus = defineEventa<ModuleStatusEvent>('module:status')
export const moduleConfigurationValidateRequest = defineEventa<ModuleConfigurationValidateRequestEvent>('module:configuration:validate:request')
export const moduleConfigurationValidateResponse = defineEventa<ModuleConfigurationValidateResponseEvent>('module:configuration:validate:response')
export const moduleConfigurationValidateStatus = defineEventa<ModuleConfigurationValidateStatusEvent>('module:configuration:validate:status')
export const moduleConfigurationPlanRequest = defineEventa<ModuleConfigurationPlanRequestEvent>('module:configuration:plan:request')
export const moduleConfigurationPlanResponse = defineEventa<ModuleConfigurationPlanResponseEvent>('module:configuration:plan:response')
export const moduleConfigurationPlanStatus = defineEventa<ModuleConfigurationPlanStatusEvent>('module:configuration:plan:status')
export const moduleConfigurationCommit = defineEventa<ModuleConfigurationCommitEvent>('module:configuration:commit')
export const moduleConfigurationCommitStatus = defineEventa<ModuleConfigurationCommitStatusEvent>('module:configuration:commit:status')
export const moduleConfigurationConfigured = defineEventa<ModuleConfigurationConfiguredEvent>('module:configuration:configured')
export const moduleContributeCapabilityOffer = defineEventa<ModuleContributeCapabilityOfferEvent>('module:contribute:capability:offer')
export const moduleContributeCapabilityConfigurationNeeded = defineEventa<ModuleContributeCapabilityConfigurationNeededEvent>('module:contribute:capability:configuration:needed')
export const moduleContributeCapabilityConfigurationValidateRequest = defineEventa<ModuleContributeCapabilityConfigurationValidateRequestEvent>('module:contribute:capability:configuration:validate:request')
export const moduleContributeCapabilityConfigurationValidateResponse = defineEventa<ModuleContributeCapabilityConfigurationValidateResponseEvent>('module:contribute:capability:configuration:validate:response')
export const moduleContributeCapabilityConfigurationValidateStatus = defineEventa<ModuleContributeCapabilityConfigurationValidateStatusEvent>('module:contribute:capability:configuration:validate:status')
export const moduleContributeCapabilityConfigurationPlanRequest = defineEventa<ModuleContributeCapabilityConfigurationPlanRequestEvent>('module:contribute:capability:configuration:plan:request')
export const moduleContributeCapabilityConfigurationPlanResponse = defineEventa<ModuleContributeCapabilityConfigurationPlanResponseEvent>('module:contribute:capability:configuration:plan:response')
export const moduleContributeCapabilityConfigurationPlanStatus = defineEventa<ModuleContributeCapabilityConfigurationPlanStatusEvent>('module:contribute:capability:configuration:plan:status')
export const moduleContributeCapabilityConfigurationCommit = defineEventa<ModuleContributeCapabilityConfigurationCommitEvent>('module:contribute:capability:configuration:commit')
export const moduleContributeCapabilityConfigurationCommitStatus = defineEventa<ModuleContributeCapabilityConfigurationCommitStatusEvent>('module:contribute:capability:configuration:commit:status')
export const moduleContributeCapabilityConfigurationConfigured = defineEventa<ModuleContributeCapabilityConfigurationConfiguredEvent>('module:contribute:capability:configuration:configured')
export const moduleContributeCapabilityActivated = defineEventa<ModuleContributeCapabilityActivatedEvent>('module:contribute:capability:activated')
export const moduleStatusChange = defineEventa<ModuleStatusChangeEvent>('module:status:change')
export const uiConfigure = defineEventa<UiConfigureEvent>('ui:configure')
export const inputText = defineEventa<WebSocketEventInputText>('input:text')
export const inputTextVoice = defineEventa<WebSocketEventInputTextVoice>('input:text:voice')
export const inputVoice = defineEventa<WebSocketEventInputVoice>('input:voice')
export const outputGenAiChatToolCall = defineEventa<OutputGenAiChatToolCallEvent>('output:gen-ai:chat:tool-call')
export const outputGenAiChatMessage = defineEventa<OutputGenAiChatMessageEvent>('output:gen-ai:chat:message')
export const outputGenAiChatComplete = defineEventa<OutputGenAiChatCompleteEvent>('output:gen-ai:chat:complete')
export const sparkNotify = defineEventa<SparkNotifyEvent>('spark:notify')
export const sparkEmit = defineEventa<SparkEmitEvent>('spark:emit')
export const sparkCommand = defineEventa<SparkCommandEvent>('spark:command')
export const transportConnectionHeartbeat = defineEventa<TransportConnectionHeartbeatEvent>('transport:connection:heartbeat')
export const contextUpdate = defineEventa<ContextUpdateEvent>('context:update')
// Thanks to:
//
// A little hack for creating extensible discriminated unions : r/typescript
// https://www.reddit.com/r/typescript/comments/1064ibt/a_little_hack_for_creating_extensible/
export interface WebSocketEvents<C = undefined> {
'error': {
message: string
}
'error': ErrorEvent
'module:authenticate': {
token: string
}
'module:authenticated': {
authenticated: boolean
}
'module:announce': {
name: string
identity?: MetadataEventSource
possibleEvents: Array<(keyof WebSocketEvents<C>)>
}
'module:configure': {
config: C
}
'module:authenticate': ModuleAuthenticateEvent
'module:authenticated': ModuleAuthenticatedEvent
/**
* Server-side registry sync for known online modules.
* Sent to newly authenticated peers to bootstrap module discovery.
*/
'registry:modules:sync': RegistryModulesSyncEvent
'module:announce': ModuleAnnounceEvent<C>
/**
* Prepare completed. Host can move into config apply/validate.
*
* Example:
* module:prepared { missingDependencies: [] }
*/
'module:prepared': ModulePreparedEvent
/**
* Module needs configuration to proceed to prepared/configured.
*/
'module:configuration:needed': ModuleConfigurationNeededEvent<C>
/**
* Lifecycle status updates for orchestration/UX.
*
* Example:
* module:status { phase: "ready" }
*/
'module:status': ModuleStatusEvent
/**
* Ask the module to validate current config (host → module).
*/
'module:configuration:validate:request': ModuleConfigurationValidateRequestEvent<C>
/**
* Validation response (module → host), with optional plan suggestions.
*/
'module:configuration:validate:response': ModuleConfigurationValidateResponseEvent<C>
/**
* Status updates for validation (module → host).
*/
'module:configuration:validate:status': ModuleConfigurationValidateStatusEvent
/**
* Configuration planning request (host → module).
*/
'module:configuration:plan:request': ModuleConfigurationPlanRequestEvent<C>
/**
* Configuration planning response (module → host).
*/
'module:configuration:plan:response': ModuleConfigurationPlanResponseEvent<C>
/**
* Status updates for planning (module → host).
*/
'module:configuration:plan:status': ModuleConfigurationPlanStatusEvent
/**
* Commit a config as "active" (host → module).
*/
'module:configuration:commit': ModuleConfigurationCommitEvent<C>
/**
* Status updates for commit (module → host).
*/
'module:configuration:commit:status': ModuleConfigurationCommitStatusEvent
/**
* Configuration fully applied and active (module → host).
*/
'module:configuration:configured': ModuleConfigurationConfiguredEvent<C>
/**
* Capability offer emitted after module configuration.
*/
'module:contribute:capability:offer': ModuleContributeCapabilityOfferEvent
/**
* Capability needs configuration before activation.
*/
'module:contribute:capability:configuration:needed': ModuleContributeCapabilityConfigurationNeededEvent<C>
'module:contribute:capability:configuration:validate:request': ModuleContributeCapabilityConfigurationValidateRequestEvent<C>
'module:contribute:capability:configuration:validate:response': ModuleContributeCapabilityConfigurationValidateResponseEvent<C>
'module:contribute:capability:configuration:validate:status': ModuleContributeCapabilityConfigurationValidateStatusEvent
'module:contribute:capability:configuration:plan:request': ModuleContributeCapabilityConfigurationPlanRequestEvent<C>
'module:contribute:capability:configuration:plan:response': ModuleContributeCapabilityConfigurationPlanResponseEvent<C>
'module:contribute:capability:configuration:plan:status': ModuleContributeCapabilityConfigurationPlanStatusEvent
'module:contribute:capability:configuration:commit': ModuleContributeCapabilityConfigurationCommitEvent<C>
'module:contribute:capability:configuration:commit:status': ModuleContributeCapabilityConfigurationCommitStatusEvent
'module:contribute:capability:configuration:configured': ModuleContributeCapabilityConfigurationConfiguredEvent<C>
'module:contribute:capability:activated': ModuleContributeCapabilityActivatedEvent
/**
* Request a phase transition (module → host).
*/
'module:status:change': ModuleStatusChangeEvent
'ui:configure': {
moduleName: string
moduleIndex?: number
config: C | Record<string, unknown>
}
'ui:configure': UiConfigureEvent<C>
'input:text': WebSocketEventInputText
'input:text:voice': WebSocketEventInputTextVoice
'input:voice': WebSocketEventInputVoice
'output:gen-ai:chat:tool-call': {
toolCalls: ToolMessage[]
} & Partial<WithInputSource<'stage-web' | 'stage-tamagotchi' | 'discord'>> & Partial<WithOutputSource<'gen-ai:chat'>>
'output:gen-ai:chat:message': {
message: AssistantMessage
} & Partial<WithInputSource<'stage-web' | 'stage-tamagotchi' | 'discord'>> & Partial<WithOutputSource<'gen-ai:chat'>>
'output:gen-ai:chat:complete': {
message: AssistantMessage
toolCalls: ToolMessage[]
usage: {
promptTokens: number
completionTokens: number
totalTokens: number
source: 'provider-based' | 'estimate-based'
}
} & Partial<WithInputSource<'stage-web' | 'stage-tamagotchi' | 'discord'>> & Partial<WithOutputSource<'gen-ai:chat'>>
'output:gen-ai:chat:tool-call': OutputGenAiChatToolCallEvent
'output:gen-ai:chat:message': OutputGenAiChatMessageEvent
'output:gen-ai:chat:complete': OutputGenAiChatCompleteEvent
/**
* Spark used for allowing agents in a network to raise an event toward the other destinations (e.g. character).
@@ -270,20 +989,7 @@ export interface WebSocketEvents<C = undefined> {
*
* destinations controls routing (e.g. ['character'], ['character','minecraft-agent']).
*/
'spark:notify': {
id: string
eventId: string
lane?: string
kind: 'alarm' | 'ping' | 'reminder'
urgency: 'immediate' | 'soon' | 'later'
headline: string
note?: string
payload?: Record<string, unknown>
ttlMs?: number
requiresAck?: boolean
destinations: Array<string>
metadata?: Record<string, unknown>
}
'spark:notify': SparkNotifyEvent
/**
* Acknowledgement/progress/state for a spark or command (bidirectional).
@@ -293,14 +999,7 @@ export interface WebSocketEvents<C = undefined> {
* - Sub-agent: state=blocked/dropped with note when it cannot comply.
* - Minecraft: state=working, note="Pillared up; healing" in reply to a command.
*/
'spark:emit': {
id: string
eventId?: string
state: 'queued' | 'working' | 'done' | 'dropped' | 'blocked' | 'expired'
note?: string
destinations: Array<string>
metadata?: Record<string, unknown>
}
'spark:emit': SparkEmitEvent
/**
* Character issues instructions or context to a sub-agent.
@@ -311,51 +1010,11 @@ export interface WebSocketEvents<C = undefined> {
* - Prep plan: interrupt=soft, priority=high, intent=plan with steps/fallbacks.
* - Contextual hints: intent=context with contextPatch ideas/hints.
*/
'spark:command': {
id: string
eventId?: string
parentEventId?: string
commandId: string
interrupt: 'force' | 'soft' | false
priority: 'critical' | 'high' | 'normal' | 'low'
intent: 'plan' | 'proposal' | 'action' | 'pause' | 'resume' | 'reroute' | 'context'
ack?: string
guidance?: {
type: 'proposal' | 'instruction' | 'memory-recall'
/**
* Personas can be used to adjust the behavior of sub-agents.
* For example, when using as NPC in games, or player in Minecraft,
* the persona can help define the character's traits and decision-making style.
*
* Example:
* persona: {
* "bravery": "high",
* "cautiousness": "low",
* "friendliness": "medium"
* }
*/
persona?: Record<string, 'very-high' | 'high' | 'medium' | 'low' | 'very-low'>
options: Array<{
label: string
steps: Array<string>
rationale?: string
possibleOutcome?: Array<string>
risk?: 'high' | 'medium' | 'low' | 'none'
fallback?: Array<string>
triggers?: Array<string>
}>
}
contexts?: Array<ContextUpdate>
destinations: Array<string>
}
'spark:command': SparkCommandEvent
'transport:connection:heartbeat': {
kind: MessageHeartbeatKind
message: MessageHeartbeat | string
at?: number
}
'transport:connection:heartbeat': TransportConnectionHeartbeatEvent
'context:update': ContextUpdate
'context:update': ContextUpdateEvent
}
export type WebSocketEvent<C = undefined> = {
+22 -11
View File
@@ -40,7 +40,7 @@ catalogs:
specifier: 0.1.0-beta.15
version: 0.1.0-beta.15
'@moeru/eventa':
specifier: 1.0.0-alpha.10
specifier: 'catalog:'
version: 1.0.0-alpha.10
'@moeru/std':
specifier: 0.1.0-beta.14
@@ -171,6 +171,9 @@ catalogs:
superjson:
specifier: ^2.2.6
version: 2.2.6
tsdown:
specifier: ^0.17.4
version: 0.17.4
tsx:
specifier: ^4.21.0
version: 4.21.0
@@ -315,7 +318,7 @@ importers:
specifier: ^1.0.2
version: 1.0.2
tsdown:
specifier: ^0.17.4
specifier: 'catalog:'
version: 0.17.4(@arethetypeswrong/core@0.18.2)(oxc-resolver@11.16.2)(publint@0.3.16)(synckit@0.11.12)(typescript@5.9.3)(unplugin-lightningcss@0.4.4)(unplugin-unused@0.5.6)
tsx:
specifier: ^4.21.0
@@ -1967,7 +1970,11 @@ importers:
specifier: ^1.0.2
version: 1.0.2
packages/plugin-sdk: {}
packages/plugin-sdk:
dependencies:
'@moeru/eventa':
specifier: 'catalog:'
version: 1.0.0-alpha.10(electron@40.0.0)
packages/server-runtime:
dependencies:
@@ -2001,9 +2008,6 @@ importers:
crossws:
specifier: ^0.4.3
version: 0.4.3(srvx@0.10.1)
defu:
specifier: ^6.1.4
version: 6.1.4
superjson:
specifier: 'catalog:'
version: 2.2.6
@@ -2014,9 +2018,9 @@ importers:
packages/server-shared:
dependencies:
'@xsai/shared':
'@moeru/eventa':
specifier: 'catalog:'
version: 0.4.0-beta.13
version: 1.0.0-alpha.10(electron@40.0.0)
'@xsai/shared-chat':
specifier: 'catalog:'
version: 0.4.0-beta.13
@@ -3020,7 +3024,7 @@ importers:
version: 14.1.0(vue@3.5.26(typescript@5.9.3))
'@wxt-dev/module-vue':
specifier: ^1.0.3
version: 1.0.3(vite@7.3.1(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))(wxt@0.20.13(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)(lightningcss@1.30.2)(rollup@4.55.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
version: 1.0.3(vite@8.0.0-beta.9(@types/node@24.10.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))(wxt@0.20.13(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)(lightningcss@1.30.2)(rollup@4.55.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
nanoid:
specifier: ^5.1.6
version: 5.1.6
@@ -19698,6 +19702,13 @@ snapshots:
optionalDependencies:
electron: 39.2.7
'@moeru/eventa@1.0.0-alpha.10(electron@40.0.0)':
dependencies:
nanoid: 5.1.6
picomatch: 4.0.3
optionalDependencies:
electron: 40.0.0
'@moeru/eventa@1.0.0-alpha.11(electron@40.0.0)(h3@2.0.1-rc.5(crossws@0.4.3(srvx@0.10.1)))':
dependencies:
nanoid: 5.1.6
@@ -23283,9 +23294,9 @@ snapshots:
'@types/filesystem': 0.0.36
'@types/har-format': 1.2.16
'@wxt-dev/module-vue@1.0.3(vite@7.3.1(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))(wxt@0.20.13(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)(lightningcss@1.30.2)(rollup@4.55.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
'@wxt-dev/module-vue@1.0.3(vite@8.0.0-beta.9(@types/node@24.10.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))(wxt@0.20.13(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)(lightningcss@1.30.2)(rollup@4.55.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@vitejs/plugin-vue': 6.0.3(vite@7.3.1(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))
'@vitejs/plugin-vue': 6.0.3(vite@8.0.0-beta.9(@types/node@24.10.9)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))
wxt: 0.20.13(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)(lightningcss@1.30.2)(rollup@4.55.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
transitivePeerDependencies:
- vite
+2 -1
View File
@@ -36,7 +36,7 @@ catalog:
'@iconify-json/logos': ^1.2.10
'@iconify-json/tabler': ^1.2.26
'@moeru/eslint-config': 0.1.0-beta.15
'@moeru/eventa': 1.0.0-alpha.10
'@moeru/eventa': 'catalog:'
'@moeru/std': 0.1.0-beta.14
'@nekopaw/tempora': 0.4.0-alpha.1
'@pinia/testing': ^1.0.3
@@ -80,6 +80,7 @@ catalog:
splitpanes: ^4.0.4
std-env: ^3.10.0
superjson: ^2.2.6
tsdown: ^0.17.4
tsx: ^4.21.0
uncrypto: ^0.1.3
unplugin-info: ^1.2.4
+1
View File
@@ -5,6 +5,7 @@ export default defineConfig({
projects: [
'apps/server',
'packages/stage-ui',
'packages/plugin-sdk',
'packages/vite-plugin-warpdrive',
'packages/audio-pipelines-transcribe',
'packages/server-runtime',