From ffbbcf692a97ec8648af39353b49f32896367207 Mon Sep 17 00:00:00 2001 From: Adam Malczewski Date: Thu, 11 Jun 2026 13:08:38 +0900 Subject: feat(surfaces): NumberField + per-conversation surface scoping; cache-warming controls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend the surface framework so cache-warming exposes per-conversation controls: - ui-contract: add NumberField (settable free-value numeric) to SurfaceField; add optional conversationId to subscribe/unsubscribe/invoke + surface/update - surface-registry: SurfaceContext { conversationId? } on getSpec/invoke (backward-compatible) - transport-ws: thread conversationId; key subscriptions by (surfaceId, conversationId); tag surface/update replies with conversationId - cache-warming: per-conversation surface — Toggle(enabled) + Number(interval seconds, cache-warming/set-interval) + Stat(last cache %); drop the currentConversationId closure Global surfaces (surface-loaded-extensions) unchanged. 784 vitest + 109 bun = 893 tests; tsc -b EXIT 0; biome clean. --- packages/surface-registry/src/index.ts | 2 +- packages/surface-registry/src/registry.ts | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'packages/surface-registry/src') diff --git a/packages/surface-registry/src/index.ts b/packages/surface-registry/src/index.ts index cdfcf7e..da52c92 100644 --- a/packages/surface-registry/src/index.ts +++ b/packages/surface-registry/src/index.ts @@ -1,4 +1,4 @@ export { createSurfaceRegistryExtension, manifest } from "./extension.js"; -export type { SurfaceProvider, SurfaceRegistry } from "./registry.js"; +export type { SurfaceContext, SurfaceProvider, SurfaceRegistry } from "./registry.js"; export { createSurfaceRegistry } from "./registry.js"; export { surfaceRegistryHandle } from "./service.js"; diff --git a/packages/surface-registry/src/registry.ts b/packages/surface-registry/src/registry.ts index b1c8116..5780910 100644 --- a/packages/surface-registry/src/registry.ts +++ b/packages/surface-registry/src/registry.ts @@ -1,5 +1,14 @@ import type { SurfaceCatalog, SurfaceCatalogEntry, SurfaceSpec } from "@dispatch/ui-contract"; +/** + * Optional context threaded by the transport when calling a surface provider. + * Providers may use this to scope per-conversation state; omitting it yields + * the default/global behaviour. + */ +export interface SurfaceContext { + readonly conversationId?: string; +} + /** * What a surface-contributing extension registers with the surface registry. * Each provider owns one surface identified by its catalog entry id. @@ -9,10 +18,10 @@ export interface SurfaceProvider { readonly catalogEntry: SurfaceCatalogEntry; /** Build the current surface spec (may be async for dynamic surfaces). */ - getSpec(): SurfaceSpec | Promise; + getSpec(context?: SurfaceContext): SurfaceSpec | Promise; /** Run a backend action by id with an optional payload. */ - invoke(actionId: string, payload?: unknown): void | Promise; + invoke(actionId: string, payload?: unknown, context?: SurfaceContext): void | Promise; /** * Optional: subscribe to spec changes. Returns an unsubscribe disposer. -- cgit v1.2.3