oui-spec 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +95 -10
  2. package/dist/chunk-5TQ6AVQH.cjs +108 -0
  3. package/dist/chunk-5TQ6AVQH.cjs.map +1 -0
  4. package/dist/{chunk-LEXIU2MH.cjs → chunk-HK7OXB2W.cjs} +74 -7
  5. package/dist/chunk-HK7OXB2W.cjs.map +1 -0
  6. package/dist/{chunk-JO5LGOB6.js → chunk-ILUTAHUJ.js} +74 -8
  7. package/dist/chunk-ILUTAHUJ.js.map +1 -0
  8. package/dist/{chunk-WZXUKJ7E.cjs → chunk-MTMEW6MM.cjs} +2 -106
  9. package/dist/chunk-MTMEW6MM.cjs.map +1 -0
  10. package/dist/chunk-O6EI77LD.js +106 -0
  11. package/dist/chunk-O6EI77LD.js.map +1 -0
  12. package/dist/{chunk-7EXSMPGR.js → chunk-YDMGV72W.js} +3 -106
  13. package/dist/chunk-YDMGV72W.js.map +1 -0
  14. package/dist/core/index.cjs +7 -2
  15. package/dist/core/index.d.cts +116 -102
  16. package/dist/core/index.d.ts +116 -102
  17. package/dist/core/index.js +2 -1
  18. package/dist/define-surface-D6XPtoqu.d.cts +151 -0
  19. package/dist/define-surface-DXBop-uB.d.ts +151 -0
  20. package/dist/index.cjs +10 -5
  21. package/dist/index.d.cts +4 -2
  22. package/dist/index.d.ts +4 -2
  23. package/dist/index.js +3 -2
  24. package/dist/react/index.d.cts +1 -1
  25. package/dist/react/index.d.ts +1 -1
  26. package/dist/transport/index.cjs +4 -3
  27. package/dist/transport/index.d.cts +4 -77
  28. package/dist/transport/index.d.ts +4 -77
  29. package/dist/transport/index.js +2 -1
  30. package/dist/websocket-CiWvkaz_.d.ts +78 -0
  31. package/dist/websocket-CrI0yRNo.d.cts +78 -0
  32. package/package.json +4 -3
  33. package/dist/chunk-7EXSMPGR.js.map +0 -1
  34. package/dist/chunk-JO5LGOB6.js.map +0 -1
  35. package/dist/chunk-LEXIU2MH.cjs.map +0 -1
  36. package/dist/chunk-WZXUKJ7E.cjs.map +0 -1
@@ -1,120 +1,134 @@
1
- import { JSONSchema, OUIActionPolling, OUIActivation, OUISurface } from '../spec/index.js';
2
- export { OUIAction, OUIActionRequest, OUIActionResult, OUIObservation, OUIObservationUpdate, OUIProtocolEvent, OUISurfaceDeregistration, OUISurfaceRegistration, OUI_PROTOCOL_EVENTS } from '../spec/index.js';
1
+ import { OUISurface } from '../spec/index.js';
2
+ export { JSONSchema, OUIAction, OUIActionPolling, OUIActionRequest, OUIActionResult, OUIActivation, OUIObservation, OUIObservationUpdate, OUIProtocolEvent, OUISurfaceDeregistration, OUISurfaceRegistration, OUI_PROTOCOL_EVENTS } from '../spec/index.js';
3
+ import { D as DefinedSurface, O as OUIBranded } from '../define-surface-DXBop-uB.js';
4
+ export { A as ActionDefinition, a as ActionHandlerResult, b as ActionPollingConfig, c as ObservationDefinition, S as SurfaceDefinition, d as defineSurface } from '../define-surface-DXBop-uB.js';
5
+ import { S as SocketLike, c as OUITransportConfig, b as OUITransport } from '../websocket-CiWvkaz_.js';
3
6
 
4
7
  /**
5
- * Configuration for defining an OUI surface with handlers.
6
- * This is the "integration file" an app provides — it declares both
7
- * the schema (what the agent sees) and the implementation (what executes).
8
+ * Compile-time validation for a createOUI configuration.
9
+ *
10
+ * These types resolve to a descriptive error type when a rule is broken, so the
11
+ * failure surfaces at the call site with a message naming the offending id —
12
+ * not as `Type 'X' is not assignable to type 'never'`.
13
+ *
14
+ * Everything here was previously a runtime `throw` inside defineSurface, or
15
+ * nothing at all. A duplicate action id threw when the surface was constructed,
16
+ * which in a React app means at render, in a browser, after a deploy. The same
17
+ * mistake is now a red squiggle.
8
18
  */
9
- interface SurfaceDefinition<TContext = unknown> {
10
- id: string;
11
- name: string;
12
- description: string;
13
- version?: string;
14
- activation?: OUIActivation;
15
- actions: ActionDefinition<TContext>[];
16
- observations?: ObservationDefinition[];
17
- metadata?: Record<string, unknown>;
18
- }
19
+ /** A readable compile error. The message lands in the tooltip. */
20
+ type OUIConfigError<TMessage extends string> = {
21
+ readonly __ouiError: TMessage;
22
+ };
23
+ /** Ids appearing more than once in a tuple of string literals. */
24
+ type Duplicates<T extends readonly string[], Seen extends string = never> = T extends readonly [
25
+ infer Head extends string,
26
+ ...infer Rest extends readonly string[]
27
+ ] ? Head extends Seen ? Head | Duplicates<Rest, Seen | Head> : Duplicates<Rest, Seen | Head> : never;
19
28
  /**
20
- * Polling config with an optional resolve handler.
21
- * The spec's OUIActionPolling is the manifest shape (no functions).
22
- * The core extends it with the resolve implementation for the runtime.
29
+ * `never` when every id is unique, otherwise the duplicated ids.
30
+ * Exported for tests — a validation type nobody can assert against is a
31
+ * validation type nobody can trust.
23
32
  */
24
- interface ActionPollingConfig<TContext = unknown> extends OUIActionPolling {
25
- /**
26
- * Called on each poll interval. Receives the dispatch result from the handler
27
- * plus the current context. Return { done: true, data } to stop polling,
28
- * or { done: false, data } to continue.
29
- */
30
- resolve?: (dispatchResult: unknown, context: TContext) => Promise<{
31
- done: boolean;
32
- data: unknown;
33
- }>;
34
- }
33
+ type DuplicateIds<T extends readonly string[]> = Duplicates<T>;
34
+ type IsEmpty<T extends readonly unknown[]> = T extends readonly [] ? true : false;
35
35
  /**
36
- * An action definition includes both the schema (for the agent) and
37
- * the handler (for execution). This is the single source of truth —
38
- * no separate YAML, no separate listener, no drift possible.
36
+ * Validate the surface list, returning the config type when it passes and an
37
+ * OUIConfigError when it does not.
38
+ *
39
+ * The rules, and why each exists:
40
+ *
41
+ * Non-empty — an OUI instance with no surfaces registers nothing and
42
+ * dispatches nowhere. It looks connected and does nothing, which is the
43
+ * failure mode this whole design is trying to eliminate.
44
+ *
45
+ * Unique surface ids — registration is keyed by surface id, so a duplicate
46
+ * silently replaces the first surface's manifest. The agent then sees one
47
+ * surface's actions attributed to the other.
48
+ */
49
+ type ValidateSurfaceIds<TIds extends readonly string[]> = IsEmpty<TIds> extends true ? OUIConfigError<"createOUI requires at least one surface. An instance with no surfaces registers nothing and dispatches nowhere."> : [DuplicateIds<TIds>] extends [never] ? unknown : OUIConfigError<`Duplicate surface id: "${DuplicateIds<TIds>}". Surface registration is keyed by id, so the second would silently replace the first.`>;
50
+
51
+ /**
52
+ * createOUI — the only supported way to instantiate OUI.
53
+ *
54
+ * WHY THIS EXISTS
55
+ *
56
+ * OUI shipped a correct protocol and a correct transport, and its first
57
+ * integrator used neither. studio-ui imported only the `SocketLike` TYPE from
58
+ * oui-spec and rebuilt the wire by hand: a literal map of protocol types to
59
+ * socket names, `oui:` hardcoded so the configurable namespace was unreachable,
60
+ * payload interfaces re-declared on the server, and an `action:result` channel
61
+ * mapped but never sent — duplicating the observation channel that already
62
+ * carries results.
63
+ *
64
+ * Nothing was wrong with the spec. Nothing enforced it. Structural typing meant
65
+ * every hand-rolled piece type-checked, and both ends agreed only by the
66
+ * coincidence of matching string literals. Rename one and the other keeps
67
+ * compiling and silently stops receiving.
68
+ *
69
+ * So the requirements are gated here:
70
+ *
71
+ * OUI owns the wire. The integrator provides a socket; it cannot provide a
72
+ * transport, because `OUITransport` values are branded and only this module
73
+ * brands them.
74
+ *
75
+ * OUI owns the result path. Results return through the observation channel,
76
+ * as `use-surface` already implements. An integrator cannot add a parallel
77
+ * channel because it cannot construct a transport to add one to.
78
+ *
79
+ * The integrator owns content. Surfaces, action schemas, observation schemas
80
+ * and handlers all arrive through `defineSurface`, whose output is branded —
81
+ * so a plain object shaped like a surface will not compile.
82
+ *
83
+ * Violations fail at compile time with a message naming the offending id.
39
84
  */
40
- interface ActionDefinition<TContext = unknown> {
41
- id: string;
42
- description: string;
43
- input: JSONSchema;
44
- output?: JSONSchema;
45
- confirm?: boolean;
46
- async?: boolean;
85
+
86
+ /** A transport OUI constructed. Integrators cannot produce one. */
87
+ type OwnedTransport = OUITransport & OUIBranded<"transport">;
88
+ /** Surface ids as literal types, for the duplicate check. */
89
+ type SurfaceIds<T extends readonly DefinedSurface<never>[]> = {
90
+ [K in keyof T]: T[K]["id"];
91
+ };
92
+ interface OUIConfig<TSurfaces extends readonly DefinedSurface<never>[]> {
47
93
  /**
48
- * Polling/subscription config for async actions.
49
- * After the handler returns, the OUI runtime starts polling or subscribing
50
- * and pushes observation updates until the operation completes.
51
- * Extends the spec's OUIActionPolling with an optional resolve handler.
94
+ * The socket OUI will speak over. The integrator owns the connection —
95
+ * auth, reconnection, lifecycle — and OUI owns what travels on it.
52
96
  */
53
- polling?: ActionPollingConfig<TContext>;
54
- usage?: string;
55
- preconditions?: string;
56
- estimatedDuration?: string;
57
- tags?: string[];
97
+ socket: SocketLike;
58
98
  /**
59
- * The handler that executes when the agent invokes this action.
60
- * Receives typed params and a context object (app-specific state/utilities).
61
- * Returns a result that the agent sees as the tool output.
99
+ * Surfaces produced by `defineSurface`. A plain object with the same shape
100
+ * will not compile: DefinedSurface is branded.
62
101
  */
63
- handler: (params: Record<string, unknown>, context: TContext) => Promise<ActionHandlerResult>;
64
- }
65
- interface ActionHandlerResult {
66
- success: boolean;
67
- data?: unknown;
68
- error?: {
69
- code: string;
70
- message: string;
71
- details?: unknown;
102
+ surfaces: TSurfaces;
103
+ /**
104
+ * Wire configuration. `namespace` defaults to 'oui' and is the supported way
105
+ * to change the event prefix — hardcoding it at the call site is what made
106
+ * this option unreachable in the first integration.
107
+ */
108
+ transport?: Omit<OUITransportConfig, "namespace"> & {
109
+ namespace?: string;
72
110
  };
73
- /** For async actions: metadata passed to the polling resolver */
74
- dispatchMeta?: Record<string, unknown>;
75
111
  }
76
- interface ObservationDefinition {
77
- id: string;
78
- description: string;
79
- schema: JSONSchema;
80
- /** Function that returns the current observation value */
81
- getValue?: () => unknown;
112
+ /** A live OUI instance. */
113
+ interface OUIInstance {
114
+ /** The transport OUI owns. Exposed for wiring, not for reimplementation. */
115
+ readonly transport: OwnedTransport;
116
+ /** Manifests for every registered surface, as the agent sees them. */
117
+ readonly manifests: readonly OUISurface[];
118
+ /** Register every surface and connect. */
119
+ start(): Promise<void>;
120
+ /** Deregister every surface and disconnect. */
121
+ stop(): void;
122
+ /** Look up a registered surface by id. */
123
+ getSurface(id: string): DefinedSurface<never> | undefined;
82
124
  }
83
125
  /**
84
- * Define an OUI surface — the single entry point for integrating
85
- * an application feature with the OUI protocol.
86
- *
87
- * This function validates the definition and returns a typed surface
88
- * object that can be registered with an agent runtime or transport layer.
126
+ * Instantiate OUI.
89
127
  *
90
- * @example
91
- * ```typescript
92
- * const mySurface = defineSurface({
93
- * id: 'my-feature',
94
- * name: 'My Feature',
95
- * description: 'Does something cool',
96
- * actions: [
97
- * {
98
- * id: 'do_thing',
99
- * description: 'Does the thing',
100
- * input: { type: 'object', properties: { name: { type: 'string' } }, required: ['name'] },
101
- * handler: async (params) => {
102
- * const result = await doTheThing(params.name);
103
- * return { success: true, data: result };
104
- * },
105
- * },
106
- * ],
107
- * });
108
- * ```
128
+ * `const` on the type parameter captures surface ids as literal types, which is
129
+ * what allows duplicate detection to name the offending id rather than failing
130
+ * with an unassignable-to-never error.
109
131
  */
110
- declare function defineSurface<TContext = unknown>(definition: SurfaceDefinition<TContext>): DefinedSurface<TContext>;
111
- /** A fully defined surface with both manifest extraction and execution capabilities */
112
- interface DefinedSurface<TContext = unknown> extends SurfaceDefinition<TContext> {
113
- toManifest(): OUISurface;
114
- executeAction(actionId: string, params: Record<string, unknown>, context: TContext): Promise<ActionHandlerResult>;
115
- getActionIds(): string[];
116
- /** Get the polling config for an action (if async) */
117
- getPollingConfig(actionId: string): OUIActionPolling | undefined;
118
- }
132
+ declare function createOUI<const TSurfaces extends readonly DefinedSurface<never>[]>(config: OUIConfig<TSurfaces> & ValidateSurfaceIds<SurfaceIds<TSurfaces>>): OUIInstance;
119
133
 
120
- export { type ActionDefinition, type ActionHandlerResult, type ActionPollingConfig, type DefinedSurface, JSONSchema, OUIActivation, OUISurface, type ObservationDefinition, type SurfaceDefinition, defineSurface };
134
+ export { DefinedSurface, type DuplicateIds, OUIBranded, type OUIConfig, type OUIConfigError, type OUIInstance, OUISurface, type OwnedTransport, type ValidateSurfaceIds, createOUI };
@@ -1,4 +1,5 @@
1
- export { defineSurface } from '../chunk-JO5LGOB6.js';
1
+ export { createOUI, defineSurface } from '../chunk-ILUTAHUJ.js';
2
2
  export { OUI_PROTOCOL_EVENTS } from '../chunk-CVUUSPF4.js';
3
+ import '../chunk-YDMGV72W.js';
3
4
  //# sourceMappingURL=index.js.map
4
5
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,151 @@
1
+ import { JSONSchema, OUIActionPolling, OUIActivation, OUISurface } from './spec/index.cjs';
2
+
3
+ /**
4
+ * Nominal branding for values OUI must construct itself.
5
+ *
6
+ * Structural typing means any object with the right shape satisfies an
7
+ * interface. That is how Closure Studio ended up hand-rolling OUI's transport:
8
+ * `SocketLike` was importable, `OUITransport` was a plain interface, so an
9
+ * integrator could satisfy every type without ever calling OUI. The result was
10
+ * a second implementation of the wire — hardcoded namespace, re-declared
11
+ * payload types on the server, and a dead `action:result` mapping alongside the
12
+ * observation channel that already carried results.
13
+ *
14
+ * A unique symbol cannot be produced outside this module. Branding the types
15
+ * OUI owns turns "you should use our constructor" into "you cannot compile
16
+ * without it".
17
+ */
18
+ declare const OUI_BRAND: unique symbol;
19
+ /** Marks a value as constructed by OUI itself. */
20
+ interface OUIBranded<TKind extends string> {
21
+ readonly [OUI_BRAND]: TKind;
22
+ }
23
+
24
+ /**
25
+ * Configuration for defining an OUI surface with handlers.
26
+ * This is the "integration file" an app provides — it declares both
27
+ * the schema (what the agent sees) and the implementation (what executes).
28
+ */
29
+ interface SurfaceDefinition<TContext = unknown> {
30
+ id: string;
31
+ name: string;
32
+ description: string;
33
+ version?: string;
34
+ activation?: OUIActivation;
35
+ actions: ActionDefinition<TContext>[];
36
+ observations?: ObservationDefinition[];
37
+ metadata?: Record<string, unknown>;
38
+ }
39
+ /**
40
+ * Polling config with an optional resolve handler.
41
+ * The spec's OUIActionPolling is the manifest shape (no functions).
42
+ * The core extends it with the resolve implementation for the runtime.
43
+ */
44
+ interface ActionPollingConfig<TContext = unknown> extends OUIActionPolling {
45
+ /**
46
+ * Called on each poll interval. Receives the dispatch result from the handler
47
+ * plus the current context. Return { done: true, data } to stop polling,
48
+ * or { done: false, data } to continue.
49
+ */
50
+ resolve?: (dispatchResult: unknown, context: TContext) => Promise<{
51
+ done: boolean;
52
+ data: unknown;
53
+ }>;
54
+ }
55
+ /**
56
+ * An action definition includes both the schema (for the agent) and
57
+ * the handler (for execution). This is the single source of truth —
58
+ * no separate YAML, no separate listener, no drift possible.
59
+ */
60
+ interface ActionDefinition<TContext = unknown> {
61
+ id: string;
62
+ description: string;
63
+ input: JSONSchema;
64
+ output?: JSONSchema;
65
+ confirm?: boolean;
66
+ async?: boolean;
67
+ /**
68
+ * Polling/subscription config for async actions.
69
+ * After the handler returns, the OUI runtime starts polling or subscribing
70
+ * and pushes observation updates until the operation completes.
71
+ * Extends the spec's OUIActionPolling with an optional resolve handler.
72
+ */
73
+ polling?: ActionPollingConfig<TContext>;
74
+ usage?: string;
75
+ preconditions?: string;
76
+ estimatedDuration?: string;
77
+ tags?: string[];
78
+ /**
79
+ * The handler that executes when the agent invokes this action.
80
+ * Receives typed params and a context object (app-specific state/utilities).
81
+ * Returns a result that the agent sees as the tool output.
82
+ */
83
+ handler: (params: Record<string, unknown>, context: TContext) => Promise<ActionHandlerResult>;
84
+ }
85
+ interface ActionHandlerResult {
86
+ success: boolean;
87
+ data?: unknown;
88
+ error?: {
89
+ code: string;
90
+ message: string;
91
+ details?: unknown;
92
+ };
93
+ /** For async actions: metadata passed to the polling resolver */
94
+ dispatchMeta?: Record<string, unknown>;
95
+ }
96
+ interface ObservationDefinition {
97
+ id: string;
98
+ description: string;
99
+ schema: JSONSchema;
100
+ /** Function that returns the current observation value */
101
+ getValue?: () => unknown;
102
+ }
103
+ /**
104
+ * Define an OUI surface — the single entry point for integrating
105
+ * an application feature with the OUI protocol.
106
+ *
107
+ * This function validates the definition and returns a typed surface
108
+ * object that can be registered with an agent runtime or transport layer.
109
+ *
110
+ * @example
111
+ * ```typescript
112
+ * const mySurface = defineSurface({
113
+ * id: 'my-feature',
114
+ * name: 'My Feature',
115
+ * description: 'Does something cool',
116
+ * actions: [
117
+ * {
118
+ * id: 'do_thing',
119
+ * description: 'Does the thing',
120
+ * input: { type: 'object', properties: { name: { type: 'string' } }, required: ['name'] },
121
+ * handler: async (params) => {
122
+ * const result = await doTheThing(params.name);
123
+ * return { success: true, data: result };
124
+ * },
125
+ * },
126
+ * ],
127
+ * });
128
+ * ```
129
+ */
130
+ declare function defineSurface<TContext = unknown, const TId extends string = string>(definition: SurfaceDefinition<TContext> & {
131
+ id: TId;
132
+ }): DefinedSurface<TContext> & {
133
+ id: TId;
134
+ };
135
+ /** A fully defined surface with both manifest extraction and execution capabilities */
136
+ /**
137
+ * Branded so it can only come from `defineSurface`.
138
+ *
139
+ * Without the brand a plain object literal satisfies this interface
140
+ * structurally, which is how an integrator can assemble a surface that never
141
+ * ran defineSurface's duplicate-id checks and never produced a real manifest.
142
+ */
143
+ interface DefinedSurface<TContext = unknown> extends SurfaceDefinition<TContext>, OUIBranded<"surface"> {
144
+ toManifest(): OUISurface;
145
+ executeAction(actionId: string, params: Record<string, unknown>, context: TContext): Promise<ActionHandlerResult>;
146
+ getActionIds(): string[];
147
+ /** Get the polling config for an action (if async) */
148
+ getPollingConfig(actionId: string): OUIActionPolling | undefined;
149
+ }
150
+
151
+ export { type ActionDefinition as A, type DefinedSurface as D, type OUIBranded as O, type SurfaceDefinition as S, type ActionHandlerResult as a, type ActionPollingConfig as b, type ObservationDefinition as c, defineSurface as d };
@@ -0,0 +1,151 @@
1
+ import { JSONSchema, OUIActionPolling, OUIActivation, OUISurface } from './spec/index.js';
2
+
3
+ /**
4
+ * Nominal branding for values OUI must construct itself.
5
+ *
6
+ * Structural typing means any object with the right shape satisfies an
7
+ * interface. That is how Closure Studio ended up hand-rolling OUI's transport:
8
+ * `SocketLike` was importable, `OUITransport` was a plain interface, so an
9
+ * integrator could satisfy every type without ever calling OUI. The result was
10
+ * a second implementation of the wire — hardcoded namespace, re-declared
11
+ * payload types on the server, and a dead `action:result` mapping alongside the
12
+ * observation channel that already carried results.
13
+ *
14
+ * A unique symbol cannot be produced outside this module. Branding the types
15
+ * OUI owns turns "you should use our constructor" into "you cannot compile
16
+ * without it".
17
+ */
18
+ declare const OUI_BRAND: unique symbol;
19
+ /** Marks a value as constructed by OUI itself. */
20
+ interface OUIBranded<TKind extends string> {
21
+ readonly [OUI_BRAND]: TKind;
22
+ }
23
+
24
+ /**
25
+ * Configuration for defining an OUI surface with handlers.
26
+ * This is the "integration file" an app provides — it declares both
27
+ * the schema (what the agent sees) and the implementation (what executes).
28
+ */
29
+ interface SurfaceDefinition<TContext = unknown> {
30
+ id: string;
31
+ name: string;
32
+ description: string;
33
+ version?: string;
34
+ activation?: OUIActivation;
35
+ actions: ActionDefinition<TContext>[];
36
+ observations?: ObservationDefinition[];
37
+ metadata?: Record<string, unknown>;
38
+ }
39
+ /**
40
+ * Polling config with an optional resolve handler.
41
+ * The spec's OUIActionPolling is the manifest shape (no functions).
42
+ * The core extends it with the resolve implementation for the runtime.
43
+ */
44
+ interface ActionPollingConfig<TContext = unknown> extends OUIActionPolling {
45
+ /**
46
+ * Called on each poll interval. Receives the dispatch result from the handler
47
+ * plus the current context. Return { done: true, data } to stop polling,
48
+ * or { done: false, data } to continue.
49
+ */
50
+ resolve?: (dispatchResult: unknown, context: TContext) => Promise<{
51
+ done: boolean;
52
+ data: unknown;
53
+ }>;
54
+ }
55
+ /**
56
+ * An action definition includes both the schema (for the agent) and
57
+ * the handler (for execution). This is the single source of truth —
58
+ * no separate YAML, no separate listener, no drift possible.
59
+ */
60
+ interface ActionDefinition<TContext = unknown> {
61
+ id: string;
62
+ description: string;
63
+ input: JSONSchema;
64
+ output?: JSONSchema;
65
+ confirm?: boolean;
66
+ async?: boolean;
67
+ /**
68
+ * Polling/subscription config for async actions.
69
+ * After the handler returns, the OUI runtime starts polling or subscribing
70
+ * and pushes observation updates until the operation completes.
71
+ * Extends the spec's OUIActionPolling with an optional resolve handler.
72
+ */
73
+ polling?: ActionPollingConfig<TContext>;
74
+ usage?: string;
75
+ preconditions?: string;
76
+ estimatedDuration?: string;
77
+ tags?: string[];
78
+ /**
79
+ * The handler that executes when the agent invokes this action.
80
+ * Receives typed params and a context object (app-specific state/utilities).
81
+ * Returns a result that the agent sees as the tool output.
82
+ */
83
+ handler: (params: Record<string, unknown>, context: TContext) => Promise<ActionHandlerResult>;
84
+ }
85
+ interface ActionHandlerResult {
86
+ success: boolean;
87
+ data?: unknown;
88
+ error?: {
89
+ code: string;
90
+ message: string;
91
+ details?: unknown;
92
+ };
93
+ /** For async actions: metadata passed to the polling resolver */
94
+ dispatchMeta?: Record<string, unknown>;
95
+ }
96
+ interface ObservationDefinition {
97
+ id: string;
98
+ description: string;
99
+ schema: JSONSchema;
100
+ /** Function that returns the current observation value */
101
+ getValue?: () => unknown;
102
+ }
103
+ /**
104
+ * Define an OUI surface — the single entry point for integrating
105
+ * an application feature with the OUI protocol.
106
+ *
107
+ * This function validates the definition and returns a typed surface
108
+ * object that can be registered with an agent runtime or transport layer.
109
+ *
110
+ * @example
111
+ * ```typescript
112
+ * const mySurface = defineSurface({
113
+ * id: 'my-feature',
114
+ * name: 'My Feature',
115
+ * description: 'Does something cool',
116
+ * actions: [
117
+ * {
118
+ * id: 'do_thing',
119
+ * description: 'Does the thing',
120
+ * input: { type: 'object', properties: { name: { type: 'string' } }, required: ['name'] },
121
+ * handler: async (params) => {
122
+ * const result = await doTheThing(params.name);
123
+ * return { success: true, data: result };
124
+ * },
125
+ * },
126
+ * ],
127
+ * });
128
+ * ```
129
+ */
130
+ declare function defineSurface<TContext = unknown, const TId extends string = string>(definition: SurfaceDefinition<TContext> & {
131
+ id: TId;
132
+ }): DefinedSurface<TContext> & {
133
+ id: TId;
134
+ };
135
+ /** A fully defined surface with both manifest extraction and execution capabilities */
136
+ /**
137
+ * Branded so it can only come from `defineSurface`.
138
+ *
139
+ * Without the brand a plain object literal satisfies this interface
140
+ * structurally, which is how an integrator can assemble a surface that never
141
+ * ran defineSurface's duplicate-id checks and never produced a real manifest.
142
+ */
143
+ interface DefinedSurface<TContext = unknown> extends SurfaceDefinition<TContext>, OUIBranded<"surface"> {
144
+ toManifest(): OUISurface;
145
+ executeAction(actionId: string, params: Record<string, unknown>, context: TContext): Promise<ActionHandlerResult>;
146
+ getActionIds(): string[];
147
+ /** Get the polling config for an action (if async) */
148
+ getPollingConfig(actionId: string): OUIActionPolling | undefined;
149
+ }
150
+
151
+ export { type ActionDefinition as A, type DefinedSurface as D, type OUIBranded as O, type SurfaceDefinition as S, type ActionHandlerResult as a, type ActionPollingConfig as b, type ObservationDefinition as c, defineSurface as d };
package/dist/index.cjs CHANGED
@@ -1,15 +1,20 @@
1
1
  'use strict';
2
2
 
3
- var chunkLEXIU2MH_cjs = require('./chunk-LEXIU2MH.cjs');
3
+ var chunkHK7OXB2W_cjs = require('./chunk-HK7OXB2W.cjs');
4
4
  var chunk3DCIL4FV_cjs = require('./chunk-3DCIL4FV.cjs');
5
5
  var chunk2ON5IEXB_cjs = require('./chunk-2ON5IEXB.cjs');
6
- var chunkWZXUKJ7E_cjs = require('./chunk-WZXUKJ7E.cjs');
6
+ var chunk5TQ6AVQH_cjs = require('./chunk-5TQ6AVQH.cjs');
7
+ var chunkMTMEW6MM_cjs = require('./chunk-MTMEW6MM.cjs');
7
8
 
8
9
 
9
10
 
11
+ Object.defineProperty(exports, "createOUI", {
12
+ enumerable: true,
13
+ get: function () { return chunkHK7OXB2W_cjs.createOUI; }
14
+ });
10
15
  Object.defineProperty(exports, "defineSurface", {
11
16
  enumerable: true,
12
- get: function () { return chunkLEXIU2MH_cjs.defineSurface; }
17
+ get: function () { return chunkHK7OXB2W_cjs.defineSurface; }
13
18
  });
14
19
  Object.defineProperty(exports, "OUI_PROTOCOL_EVENTS", {
15
20
  enumerable: true,
@@ -25,11 +30,11 @@ Object.defineProperty(exports, "useSurface", {
25
30
  });
26
31
  Object.defineProperty(exports, "createDirectTransportPair", {
27
32
  enumerable: true,
28
- get: function () { return chunkWZXUKJ7E_cjs.createDirectTransportPair; }
33
+ get: function () { return chunk5TQ6AVQH_cjs.createDirectTransportPair; }
29
34
  });
30
35
  Object.defineProperty(exports, "createWebSocketTransport", {
31
36
  enumerable: true,
32
- get: function () { return chunkWZXUKJ7E_cjs.createWebSocketTransport; }
37
+ get: function () { return chunkMTMEW6MM_cjs.createWebSocketTransport; }
33
38
  });
34
39
  //# sourceMappingURL=index.cjs.map
35
40
  //# sourceMappingURL=index.cjs.map
package/dist/index.d.cts CHANGED
@@ -1,4 +1,6 @@
1
1
  export { JSONSchema, OUIAction, OUIActionPolling, OUIActionRequest, OUIActionResult, OUIActivation, OUIObservation, OUIObservationUpdate, OUIProtocolEvent, OUISurface, OUISurfaceDeregistration, OUISurfaceRegistration, OUI_PROTOCOL_EVENTS } from './spec/index.cjs';
2
- export { ActionDefinition, ActionHandlerResult, ActionPollingConfig, DefinedSurface, ObservationDefinition, SurfaceDefinition, defineSurface } from './core/index.cjs';
2
+ export { A as ActionDefinition, a as ActionHandlerResult, b as ActionPollingConfig, D as DefinedSurface, O as OUIBranded, c as ObservationDefinition, S as SurfaceDefinition, d as defineSurface } from './define-surface-D6XPtoqu.cjs';
3
+ export { DuplicateIds, OUIConfig, OUIConfigError, OUIInstance, OwnedTransport, ValidateSurfaceIds, createOUI } from './core/index.cjs';
3
4
  export { UseSurfaceOptions, useObservation, useSurface } from './react/index.cjs';
4
- export { OUIActionHandler, OUIObservationHandler, OUITransport, OUITransportConfig, SocketLike, createDirectTransportPair, createWebSocketTransport } from './transport/index.cjs';
5
+ export { O as OUIActionHandler, a as OUIObservationHandler, b as OUITransport, c as OUITransportConfig, S as SocketLike, d as createWebSocketTransport } from './websocket-CrI0yRNo.cjs';
6
+ export { createDirectTransportPair } from './transport/index.cjs';
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export { JSONSchema, OUIAction, OUIActionPolling, OUIActionRequest, OUIActionResult, OUIActivation, OUIObservation, OUIObservationUpdate, OUIProtocolEvent, OUISurface, OUISurfaceDeregistration, OUISurfaceRegistration, OUI_PROTOCOL_EVENTS } from './spec/index.js';
2
- export { ActionDefinition, ActionHandlerResult, ActionPollingConfig, DefinedSurface, ObservationDefinition, SurfaceDefinition, defineSurface } from './core/index.js';
2
+ export { A as ActionDefinition, a as ActionHandlerResult, b as ActionPollingConfig, D as DefinedSurface, O as OUIBranded, c as ObservationDefinition, S as SurfaceDefinition, d as defineSurface } from './define-surface-DXBop-uB.js';
3
+ export { DuplicateIds, OUIConfig, OUIConfigError, OUIInstance, OwnedTransport, ValidateSurfaceIds, createOUI } from './core/index.js';
3
4
  export { UseSurfaceOptions, useObservation, useSurface } from './react/index.js';
4
- export { OUIActionHandler, OUIObservationHandler, OUITransport, OUITransportConfig, SocketLike, createDirectTransportPair, createWebSocketTransport } from './transport/index.js';
5
+ export { O as OUIActionHandler, a as OUIObservationHandler, b as OUITransport, c as OUITransportConfig, S as SocketLike, d as createWebSocketTransport } from './websocket-CiWvkaz_.js';
6
+ export { createDirectTransportPair } from './transport/index.js';
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
- export { defineSurface } from './chunk-JO5LGOB6.js';
1
+ export { createOUI, defineSurface } from './chunk-ILUTAHUJ.js';
2
2
  export { OUI_PROTOCOL_EVENTS } from './chunk-CVUUSPF4.js';
3
3
  export { useObservation, useSurface } from './chunk-UIGRLZOX.js';
4
- export { createDirectTransportPair, createWebSocketTransport } from './chunk-7EXSMPGR.js';
4
+ export { createDirectTransportPair } from './chunk-O6EI77LD.js';
5
+ export { createWebSocketTransport } from './chunk-YDMGV72W.js';
5
6
  //# sourceMappingURL=index.js.map
6
7
  //# sourceMappingURL=index.js.map
@@ -1,5 +1,5 @@
1
1
  import { OUIActionRequest, OUISurface } from '../spec/index.cjs';
2
- import { DefinedSurface } from '../core/index.cjs';
2
+ import { D as DefinedSurface } from '../define-surface-D6XPtoqu.cjs';
3
3
 
4
4
  /**
5
5
  * Configuration for the useSurface hook.
@@ -1,5 +1,5 @@
1
1
  import { OUIActionRequest, OUISurface } from '../spec/index.js';
2
- import { DefinedSurface } from '../core/index.js';
2
+ import { D as DefinedSurface } from '../define-surface-DXBop-uB.js';
3
3
 
4
4
  /**
5
5
  * Configuration for the useSurface hook.
@@ -1,16 +1,17 @@
1
1
  'use strict';
2
2
 
3
- var chunkWZXUKJ7E_cjs = require('../chunk-WZXUKJ7E.cjs');
3
+ var chunk5TQ6AVQH_cjs = require('../chunk-5TQ6AVQH.cjs');
4
+ var chunkMTMEW6MM_cjs = require('../chunk-MTMEW6MM.cjs');
4
5
 
5
6
 
6
7
 
7
8
  Object.defineProperty(exports, "createDirectTransportPair", {
8
9
  enumerable: true,
9
- get: function () { return chunkWZXUKJ7E_cjs.createDirectTransportPair; }
10
+ get: function () { return chunk5TQ6AVQH_cjs.createDirectTransportPair; }
10
11
  });
11
12
  Object.defineProperty(exports, "createWebSocketTransport", {
12
13
  enumerable: true,
13
- get: function () { return chunkWZXUKJ7E_cjs.createWebSocketTransport; }
14
+ get: function () { return chunkMTMEW6MM_cjs.createWebSocketTransport; }
14
15
  });
15
16
  //# sourceMappingURL=index.cjs.map
16
17
  //# sourceMappingURL=index.cjs.map