Skip to content

Latest commit

 

History

History
126 lines (107 loc) · 6.64 KB

File metadata and controls

126 lines (107 loc) · 6.64 KB

Extension System

Extensions are statically compiled in-tree code. The server project includes Extensions\**\*.cs and the client project includes extension client assets; the host discovers parameterless IWorldSharpExtension implementations at startup. Adding a new extension folder is therefore enough to compile and register it, provided its server extension class has a parameterless constructor.

Each extension gets a generic lifecycle:

public interface IWorldSharpExtension
{
    ExtensionDescriptor Descriptor { get; }
    void Register(IExtensionRegistry registry);
    void ConfigureServices(IServiceCollection services, ExtensionHostContext context);
    void MapEndpoints(IEndpointRouteBuilder endpoints);
}

The default lifecycle methods are optional. Register contributes shared catalogue capabilities such as WorldAction and InterfaceModeDescriptor; ConfigureServices owns extension services and persistence drivers; and MapEndpoints owns the extension's HTTP surface. The host does not call feature-specific AddX or MapX methods.

Registered mode extensions

  • Convo registers worldsharp.convo.
  • Roleplay registers the shared worldsharp.roleplay workspace; its server code owns roleplay generation and the optional bounded-session lifecycle.
  • Social Feed registers singleton worldsharp.social-feed; the extension also registers its planner, drafter, reaction Drivers, and heartbeat contributor/action.
  • BuiltIn registers foundational actions.
  • PreviewModes registers the worldsharp.game preview descriptor. It is not a game implementation.
  • Presence owns conversation availability endpoints and the weekly schedule editor. Provider-generated plans are persisted as inactive drafts and only become active after an explicit accept action. Its reusable plan contracts and validation remain in Core.
  • Activities owns durable world event rules, planned activities, occurrence materialization, and the Universe calendar editor. Its reusable schedule and activity contracts remain in Core.

Summaries and World Tracker are also extensions even though they do not contribute an Interface mode.

Heartbeat contributions

Heartbeat is host orchestration rather than a feature-specific extension. It provides a bounded HeartbeatContext and asks registered extensions for typed HeartbeatProposal values. The host validates proposals against the Universe's opt-in maximum risk ceiling; the ceiling controls the worst allowed outcome, not how often an extension should act. Activity changes are delivered as an ActivityChange trigger with the changed WorldActivity, its previous status when available, and a change kind.

Extensions should return no proposal when there is nothing meaningful to do. They must not mutate canonical state from a contributor. Conversation messages, Social Feed posts, and world changes should be executed through extension-owned action handlers so the host can enforce rate limits, permissions, and duplicate suppression. Actions execute automatically by default after passing the risk ceiling; a Universe can opt into proposal-by-proposal approval with RequireApproval. Real-Time heartbeat scheduling is host-owned and actor-scoped, while the Social Feed and Convo actions remain extension-owned. World Tracker mutations still use its own review-first branch semantics.

Conversation Presence also governs autonomous eligibility. Convo heartbeats resolve the target conversation's current status and suppress replies while the character is DND or Offline. Social Feed uses the character's active one-character Persona Convo presence as its global availability signal, preferring the most available matching conversation when more than one exists; it likewise suppresses heartbeat interactions while the character is DND or Offline. Missing presence plans resolve to Online, preserving the default behavior for characters without a schedule.

Heartbeat runs and proposals carry an optional character actor. Autonomous Real-Time, Roleplay-turn, and Activity-change triggers populate that actor, and extension actions must scope generated work to it. A Convo heartbeat defaults to the active, non-frozen one-character conversation assigned to the selected Persona; an explicit proposal conversation source can target another conversation when a feature chooses to do so. Manual runs can target a character with the actorId query parameter; a manual run without an actor records the trigger but does not authorize a character action.

Heartbeat actions that generate feature content must start the target extension's ordinary request path. Convo generation receives the existing conversation history and Social Feed drafting receives the normal world, profile, and recent-post context. A proposal may include a Hint, but it is non-binding guidance and cannot replace feature-owned prompts, validation, or canonical state.

Social Feed exposes one heartbeat action, Browse or Post on Social Feed. Its internal Drivers may return posts, replies, quotes, likes, reposts, follows, or no actions. The extension currently provides both a scoped batch Driver and an individual Driver; both receive the same normal-route-shaped feed context, produce the same validated interaction plan, and use the same idempotent persistence path. Every proposal identifies one character actor, and validation rejects actions for any other character. The context includes newest posts, a bounded slice of older posts, profiles, world nodes, and the target character's follows and notifications. The active heartbeat Driver is persisted per Universe through the Social Feed Driver settings endpoint. Universes without an explicit selection fall back to WorldSharp:SocialFeed:ActiveHeartbeatDriver and then the scoped batch Driver default; changing the selection affects future heartbeats without changing the user-facing action.

Extension modes and ownership

An extension mode declares cardinality and routes, while the registry remains a catalogue rather than a generic mode-instance creation/enforcement service. Features own their mode-specific data and orchestration. Extensions are compiled into the host; this is source discovery, not runtime package loading.

Drivers remain feature-owned typed contracts. A Driver returns proposals; feature services validate and persist results. Drivers do not own canonical state or get raw database/DI access. Provider credentials remain host-managed.

Not implemented

The extension system has no package download/install flow, runtime DLL loading from external packages, dynamic reload/unload, permissions, sandboxing, independently-installed migrations, profile registry, or generic client-panel/topbar contribution contract.