oui-spec 0.2.0 → 0.3.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 (63) hide show
  1. package/README.md +94 -122
  2. package/dist/{chunk-CVUUSPF4.js → chunk-BMCL2K74.js} +2 -2
  3. package/dist/chunk-BMCL2K74.js.map +1 -0
  4. package/dist/{chunk-MTMEW6MM.cjs → chunk-DCVVTP3V.cjs} +72 -23
  5. package/dist/chunk-DCVVTP3V.cjs.map +1 -0
  6. package/dist/chunk-F3SKRAGU.cjs +98 -0
  7. package/dist/chunk-F3SKRAGU.cjs.map +1 -0
  8. package/dist/{chunk-YDMGV72W.js → chunk-F3WKIRAU.js} +72 -23
  9. package/dist/chunk-F3WKIRAU.js.map +1 -0
  10. package/dist/chunk-IIZ6HL2L.js +89 -0
  11. package/dist/chunk-IIZ6HL2L.js.map +1 -0
  12. package/dist/chunk-KNWGQRXL.cjs +567 -0
  13. package/dist/chunk-KNWGQRXL.cjs.map +1 -0
  14. package/dist/chunk-NYCJZQSP.js +92 -0
  15. package/dist/chunk-NYCJZQSP.js.map +1 -0
  16. package/dist/chunk-ROGKEMLL.cjs +91 -0
  17. package/dist/chunk-ROGKEMLL.cjs.map +1 -0
  18. package/dist/chunk-TRNVXAB5.js +563 -0
  19. package/dist/chunk-TRNVXAB5.js.map +1 -0
  20. package/dist/{chunk-3DCIL4FV.cjs → chunk-ZKM4XWAB.cjs} +2 -2
  21. package/dist/chunk-ZKM4XWAB.cjs.map +1 -0
  22. package/dist/core/index.cjs +10 -6
  23. package/dist/core/index.d.cts +15 -8
  24. package/dist/core/index.d.ts +15 -8
  25. package/dist/core/index.js +3 -3
  26. package/dist/index.cjs +28 -12
  27. package/dist/index.d.cts +5 -4
  28. package/dist/index.d.ts +5 -4
  29. package/dist/index.js +5 -5
  30. package/dist/react/index.cjs +15 -3
  31. package/dist/react/index.d.cts +33 -50
  32. package/dist/react/index.d.ts +33 -50
  33. package/dist/react/index.js +1 -1
  34. package/dist/spec/index.cjs +2 -2
  35. package/dist/spec/index.d.cts +35 -7
  36. package/dist/spec/index.d.ts +35 -7
  37. package/dist/spec/index.js +1 -1
  38. package/dist/{define-surface-D6XPtoqu.d.cts → surface-runtime--2lZGB7Z.d.cts} +92 -2
  39. package/dist/{define-surface-DXBop-uB.d.ts → surface-runtime-Dj_nhd7r.d.ts} +92 -2
  40. package/dist/transport/index.cjs +4 -4
  41. package/dist/transport/index.d.cts +2 -2
  42. package/dist/transport/index.d.ts +2 -2
  43. package/dist/transport/index.js +2 -2
  44. package/dist/{websocket-CrI0yRNo.d.cts → websocket-YfWILdZ4.d.cts} +36 -18
  45. package/dist/{websocket-CiWvkaz_.d.ts → websocket-c5tIUWY5.d.ts} +36 -18
  46. package/package.json +5 -1
  47. package/spec/OUI-SPEC-v0.1.md +229 -155
  48. package/dist/chunk-2ON5IEXB.cjs +0 -167
  49. package/dist/chunk-2ON5IEXB.cjs.map +0 -1
  50. package/dist/chunk-3DCIL4FV.cjs.map +0 -1
  51. package/dist/chunk-5TQ6AVQH.cjs +0 -108
  52. package/dist/chunk-5TQ6AVQH.cjs.map +0 -1
  53. package/dist/chunk-CVUUSPF4.js.map +0 -1
  54. package/dist/chunk-HK7OXB2W.cjs +0 -157
  55. package/dist/chunk-HK7OXB2W.cjs.map +0 -1
  56. package/dist/chunk-ILUTAHUJ.js +0 -154
  57. package/dist/chunk-ILUTAHUJ.js.map +0 -1
  58. package/dist/chunk-MTMEW6MM.cjs.map +0 -1
  59. package/dist/chunk-O6EI77LD.js +0 -106
  60. package/dist/chunk-O6EI77LD.js.map +0 -1
  61. package/dist/chunk-UIGRLZOX.js +0 -164
  62. package/dist/chunk-UIGRLZOX.js.map +0 -1
  63. package/dist/chunk-YDMGV72W.js.map +0 -1
@@ -1,167 +0,0 @@
1
- 'use strict';
2
-
3
- var react = require('react');
4
-
5
- // src/react/use-surface.ts
6
- function useSurface(options) {
7
- const { surface, context, send, active = true } = options;
8
- const contextRef = react.useRef(context);
9
- contextRef.current = context;
10
- const surfaceRef = react.useRef(surface);
11
- surfaceRef.current = surface;
12
- const sendRef = react.useRef(send);
13
- sendRef.current = send;
14
- const activePollers = react.useRef(/* @__PURE__ */ new Map());
15
- const pushObservation = react.useCallback((observationId, value) => {
16
- const update = {
17
- surfaceId: surfaceRef.current.id,
18
- observationId,
19
- value,
20
- timestamp: Date.now()
21
- };
22
- sendRef.current({ type: "observation:update", payload: update });
23
- }, []);
24
- const startPolling = react.useCallback((actionId, pollingConfig, dispatchResult) => {
25
- const observationId = `${surfaceRef.current.id}:${actionId}:status`;
26
- let attempts = 0;
27
- const maxAttempts = pollingConfig.maxAttempts ?? Infinity;
28
- const startTime = Date.now();
29
- const maxDuration = pollingConfig.maxDurationMs ?? Infinity;
30
- if (pollingConfig.subscribe) {
31
- pushObservation(observationId, { status: "dispatched", dispatchResult, interim: true });
32
- return;
33
- }
34
- if (!pollingConfig.resolve) {
35
- pushObservation(observationId, { status: "dispatched", dispatchResult, interim: false });
36
- return;
37
- }
38
- pushObservation(observationId, { status: "polling", dispatchResult, interim: true });
39
- const timer = setInterval(async () => {
40
- attempts++;
41
- const elapsed = Date.now() - startTime;
42
- if (attempts > maxAttempts || elapsed > maxDuration) {
43
- clearInterval(timer);
44
- activePollers.current.delete(actionId);
45
- pushObservation(observationId, { status: "timeout", dispatchResult, interim: false });
46
- return;
47
- }
48
- try {
49
- const action = surfaceRef.current.actions.find((a) => a.id === actionId);
50
- if (action?.polling?.resolve) {
51
- const result = await action.polling.resolve(dispatchResult, contextRef.current);
52
- pushObservation(observationId, { ...result.data, interim: !result.done });
53
- if (result.done) {
54
- clearInterval(timer);
55
- activePollers.current.delete(actionId);
56
- }
57
- }
58
- } catch (err) {
59
- pushObservation(observationId, { status: "poll_error", error: String(err), interim: true });
60
- }
61
- }, pollingConfig.intervalMs);
62
- activePollers.current.set(actionId, timer);
63
- }, [pushObservation]);
64
- const clearAllPollers = react.useCallback(() => {
65
- for (const [, timer] of activePollers.current) {
66
- clearInterval(timer);
67
- }
68
- activePollers.current.clear();
69
- }, []);
70
- react.useEffect(() => {
71
- if (!active) {
72
- send({
73
- type: "surface:deregister",
74
- payload: { surfaceId: surface.id, timestamp: Date.now() }
75
- });
76
- return;
77
- }
78
- send({
79
- type: "surface:register",
80
- payload: {
81
- surface: surface.toManifest(),
82
- timestamp: Date.now()
83
- }
84
- });
85
- return () => {
86
- clearAllPollers();
87
- send({
88
- type: "surface:deregister",
89
- payload: { surfaceId: surface.id, timestamp: Date.now() }
90
- });
91
- };
92
- }, [surface.id, active, send, clearAllPollers]);
93
- react.useEffect(() => {
94
- return () => {
95
- clearAllPollers();
96
- };
97
- }, [clearAllPollers]);
98
- const handleActionRequest = react.useCallback(async (request) => {
99
- if (request.surfaceId !== surfaceRef.current.id) return;
100
- const { actionId, params } = request;
101
- const observationId = `${surfaceRef.current.id}:${actionId}:status`;
102
- let result;
103
- try {
104
- result = await surfaceRef.current.executeAction(actionId, params, contextRef.current);
105
- } catch (err) {
106
- pushObservation(observationId, {
107
- status: "error",
108
- error: err instanceof Error ? err.message : String(err),
109
- interim: false
110
- });
111
- return;
112
- }
113
- pushObservation(observationId, {
114
- status: result.success ? "dispatched" : "error",
115
- data: result.data,
116
- error: result.error,
117
- interim: !!result.success
118
- });
119
- if (result.success) {
120
- const action = surfaceRef.current.actions.find((a) => a.id === actionId);
121
- if (action?.polling) {
122
- startPolling(actionId, action.polling, result.data ?? result.dispatchMeta);
123
- } else {
124
- pushObservation(observationId, {
125
- status: "complete",
126
- data: result.data,
127
- interim: false
128
- });
129
- }
130
- }
131
- }, [pushObservation, startPolling]);
132
- return react.useMemo(() => ({
133
- handleActionRequest,
134
- surfaceId: surface.id,
135
- manifest: surface.toManifest(),
136
- /** Manually stop polling for a specific action */
137
- stopPolling: (actionId) => {
138
- const timer = activePollers.current.get(actionId);
139
- if (timer) {
140
- clearInterval(timer);
141
- activePollers.current.delete(actionId);
142
- }
143
- },
144
- /** Stop all active pollers */
145
- stopAllPolling: clearAllPollers
146
- }), [handleActionRequest, surface, clearAllPollers]);
147
- }
148
- function useObservation(surfaceId, observationId, value, send) {
149
- const prevValueRef = react.useRef("");
150
- react.useEffect(() => {
151
- const serialized = JSON.stringify(value);
152
- if (serialized === prevValueRef.current) return;
153
- prevValueRef.current = serialized;
154
- const update = {
155
- surfaceId,
156
- observationId,
157
- value,
158
- timestamp: Date.now()
159
- };
160
- send({ type: "observation:update", payload: update });
161
- }, [surfaceId, observationId, value, send]);
162
- }
163
-
164
- exports.useObservation = useObservation;
165
- exports.useSurface = useSurface;
166
- //# sourceMappingURL=chunk-2ON5IEXB.cjs.map
167
- //# sourceMappingURL=chunk-2ON5IEXB.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/react/use-surface.ts"],"names":["useRef","useCallback","useEffect","useMemo"],"mappings":"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","file":"chunk-2ON5IEXB.cjs","sourcesContent":["import { useEffect, useRef, useCallback, useMemo } from 'react';\nimport type { DefinedSurface, ActionHandlerResult, ActionPollingConfig } from '../core/index.js';\nimport type { OUIActionRequest, OUIObservationUpdate } from '../spec/index.js';\n\n/**\n * Configuration for the useSurface hook.\n */\nexport interface UseSurfaceOptions<TContext> {\n /** The defined surface (from defineSurface()) */\n surface: DefinedSurface<TContext>;\n\n /** The context passed to action handlers (app state, utilities, etc.) */\n context: TContext;\n\n /** Transport send function — how to send protocol events to the agent runtime */\n send: (event: { type: string; payload: unknown }) => void;\n\n /** Whether the surface is currently active (respects activation conditions) */\n active?: boolean;\n}\n\n/**\n * useSurface — registers an OUI surface with the agent runtime and handles\n * incoming action requests by executing them locally and pushing observation\n * updates. Actions are dispatched one-way (no request/response correlation).\n *\n * After an action handler executes, if the action has a polling config, the\n * hook starts a polling loop that pushes observation updates until the\n * operation completes or times out.\n *\n * @example\n * ```tsx\n * function DataVizPage() {\n * const { state, updateState, goToStep } = useDataVizWizard();\n *\n * useSurface({\n * surface: datavizSurface,\n * context: { state, updateState, goToStep },\n * send: agentTransport.send,\n * active: true,\n * });\n *\n * return <DataVizWizard />;\n * }\n * ```\n */\nexport function useSurface<TContext>(options: UseSurfaceOptions<TContext>) {\n const { surface, context, send, active = true } = options;\n const contextRef = useRef(context);\n contextRef.current = context;\n\n const surfaceRef = useRef(surface);\n surfaceRef.current = surface;\n\n const sendRef = useRef(send);\n sendRef.current = send;\n\n // Track active polling intervals for cleanup\n const activePollers = useRef<Map<string, ReturnType<typeof setInterval>>>(new Map());\n\n // Push an observation update to the agent runtime\n const pushObservation = useCallback((observationId: string, value: unknown) => {\n const update: OUIObservationUpdate = {\n surfaceId: surfaceRef.current.id,\n observationId,\n value,\n timestamp: Date.now(),\n };\n sendRef.current({ type: 'observation:update', payload: update });\n }, []);\n\n // Start the polling runtime for an async action\n const startPolling = useCallback((\n actionId: string,\n pollingConfig: ActionPollingConfig<TContext>,\n dispatchResult: unknown,\n ) => {\n const observationId = `${surfaceRef.current.id}:${actionId}:status`;\n let attempts = 0;\n const maxAttempts = pollingConfig.maxAttempts ?? Infinity;\n const startTime = Date.now();\n const maxDuration = pollingConfig.maxDurationMs ?? Infinity;\n\n // Subscribe mode — transport layer handles events, just push initial state\n if (pollingConfig.subscribe) {\n pushObservation(observationId, { status: 'dispatched', dispatchResult, interim: true });\n return;\n }\n\n // Polling mode — requires a resolve function\n if (!pollingConfig.resolve) {\n pushObservation(observationId, { status: 'dispatched', dispatchResult, interim: false });\n return;\n }\n\n // Push initial dispatched state\n pushObservation(observationId, { status: 'polling', dispatchResult, interim: true });\n\n const timer = setInterval(async () => {\n attempts++;\n const elapsed = Date.now() - startTime;\n\n if (attempts > maxAttempts || elapsed > maxDuration) {\n clearInterval(timer);\n activePollers.current.delete(actionId);\n pushObservation(observationId, { status: 'timeout', dispatchResult, interim: false });\n return;\n }\n\n try {\n const action = surfaceRef.current.actions.find(a => a.id === actionId);\n if (action?.polling?.resolve) {\n const result = await action.polling.resolve(dispatchResult, contextRef.current);\n pushObservation(observationId, { ...result.data as Record<string, unknown>, interim: !result.done });\n if (result.done) {\n clearInterval(timer);\n activePollers.current.delete(actionId);\n }\n }\n } catch (err) {\n // Don't stop polling on transient errors — push error state and continue\n pushObservation(observationId, { status: 'poll_error', error: String(err), interim: true });\n }\n }, pollingConfig.intervalMs);\n\n activePollers.current.set(actionId, timer);\n }, [pushObservation]);\n\n // Clear all active pollers\n const clearAllPollers = useCallback(() => {\n for (const [, timer] of activePollers.current) {\n clearInterval(timer);\n }\n activePollers.current.clear();\n }, []);\n\n // Register surface when it becomes active\n useEffect(() => {\n if (!active) {\n send({\n type: 'surface:deregister',\n payload: { surfaceId: surface.id, timestamp: Date.now() },\n });\n return;\n }\n\n send({\n type: 'surface:register',\n payload: {\n surface: surface.toManifest(),\n timestamp: Date.now(),\n },\n });\n\n return () => {\n // Clean up all active pollers on deregister\n clearAllPollers();\n send({\n type: 'surface:deregister',\n payload: { surfaceId: surface.id, timestamp: Date.now() },\n });\n };\n }, [surface.id, active, send, clearAllPollers]);\n\n // Clean up pollers on unmount (safety net)\n useEffect(() => {\n return () => {\n clearAllPollers();\n };\n }, [clearAllPollers]);\n\n // Handler for incoming action requests — fully async, no response correlation\n const handleActionRequest = useCallback(async (request: OUIActionRequest) => {\n if (request.surfaceId !== surfaceRef.current.id) return;\n\n const { actionId, params } = request;\n const observationId = `${surfaceRef.current.id}:${actionId}:status`;\n\n // Execute the handler locally\n let result: ActionHandlerResult;\n try {\n result = await surfaceRef.current.executeAction(actionId, params, contextRef.current);\n } catch (err) {\n // Execution failed — push error observation\n pushObservation(observationId, {\n status: 'error',\n error: err instanceof Error ? err.message : String(err),\n interim: false,\n });\n return;\n }\n\n // Push observation with dispatch result immediately\n pushObservation(observationId, {\n status: result.success ? 'dispatched' : 'error',\n data: result.data,\n error: result.error,\n interim: !!result.success,\n });\n\n // If action has polling config and dispatch succeeded, start polling runtime\n if (result.success) {\n const action = surfaceRef.current.actions.find(a => a.id === actionId);\n if (action?.polling) {\n startPolling(actionId, action.polling, result.data ?? result.dispatchMeta);\n } else {\n // Non-async action — mark as complete (not interim)\n pushObservation(observationId, {\n status: 'complete',\n data: result.data,\n interim: false,\n });\n }\n }\n }, [pushObservation, startPolling]);\n\n // Expose the handler for the transport layer to call\n return useMemo(() => ({\n handleActionRequest,\n surfaceId: surface.id,\n manifest: surface.toManifest(),\n /** Manually stop polling for a specific action */\n stopPolling: (actionId: string) => {\n const timer = activePollers.current.get(actionId);\n if (timer) {\n clearInterval(timer);\n activePollers.current.delete(actionId);\n }\n },\n /** Stop all active pollers */\n stopAllPolling: clearAllPollers,\n }), [handleActionRequest, surface, clearAllPollers]);\n}\n\n/**\n * Helper to push an observation update to the agent runtime.\n */\nexport function useObservation(\n surfaceId: string,\n observationId: string,\n value: unknown,\n send: (event: { type: string; payload: unknown }) => void,\n) {\n const prevValueRef = useRef<string>('');\n\n useEffect(() => {\n const serialized = JSON.stringify(value);\n if (serialized === prevValueRef.current) return;\n prevValueRef.current = serialized;\n\n const update: OUIObservationUpdate = {\n surfaceId,\n observationId,\n value,\n timestamp: Date.now(),\n };\n\n send({ type: 'observation:update', payload: update });\n }, [surfaceId, observationId, value, send]);\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/spec/types.ts"],"names":[],"mappings":";;;AAgSO,IAAM,mBAAA,GAAsB;AAAA,EACjC,gBAAA,EAAkB,kBAAA;AAAA,EAClB,kBAAA,EAAoB,oBAAA;AAAA,EACpB,cAAA,EAAgB,gBAAA;AAAA,EAChB,aAAA,EAAe,eAAA;AAAA,EACf,kBAAA,EAAoB;AACtB","file":"chunk-3DCIL4FV.cjs","sourcesContent":["/**\n * OUI — Open UI Specification\n *\n * The machine-readable contract for agent-controllable user interfaces.\n * Any UI application that implements this interface can be controlled by\n * any OUI-compatible agent runtime.\n */\n\n/** JSON Schema type (subset used by OUI) */\nexport type JSONSchema = {\n type?: string | string[];\n properties?: Record<string, JSONSchema>;\n items?: JSONSchema;\n required?: string[];\n enum?: (string | number | boolean)[];\n description?: string;\n default?: unknown;\n oneOf?: JSONSchema[];\n anyOf?: JSONSchema[];\n allOf?: JSONSchema[];\n const?: unknown;\n minimum?: number;\n maximum?: number;\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n format?: string;\n additionalProperties?: boolean | JSONSchema;\n};\n\n/**\n * A Surface is a controllable boundary within an application.\n * It declares what an agent can do (actions), what it can observe (state),\n * and when it's available (activation conditions).\n *\n * Think of it as \"one page\" or \"one feature\" of an application, described\n * in a way that an agent can understand and operate.\n */\nexport interface OUISurface {\n /** Unique identifier for this surface (e.g., 'dataviz-wizard', 'document-editor') */\n id: string;\n\n /** Human-readable name */\n name: string;\n\n /** Description of what this surface does — included in agent context */\n description: string;\n\n /** Version of this surface's contract (semver) */\n version?: string;\n\n /** Actions the agent can invoke on this surface */\n actions: OUIAction[];\n\n /** Observable state the agent can read */\n observations?: OUIObservation[];\n\n /** When this surface is active/available */\n activation?: OUIActivation;\n\n /** Additional metadata for agent context */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Declarative polling configuration for async actions.\n * The OUI runtime in the browser manages the polling lifecycle automatically\n * after the action handler returns its dispatch result.\n */\nexport interface OUIActionPolling {\n /** How often to check (milliseconds) */\n intervalMs: number;\n\n /** Max poll attempts before giving up (optional) */\n maxAttempts?: number;\n\n /** Max total duration before giving up in ms (alternative to maxAttempts) */\n maxDurationMs?: number;\n\n /**\n * Subscribe to a realtime event instead of polling.\n * If provided, the runtime listens for this event instead of using setInterval.\n * More efficient when realtime infrastructure exists.\n */\n subscribe?: {\n /** Event name to listen for */\n event: string;\n /**\n * Filter to match the event. Values prefixed with '$dispatchResult.'\n * are resolved from the handler's return value.\n * Example: { jobId: '$dispatchResult.jobId' }\n */\n filter?: Record<string, unknown>;\n };\n}\n\n/**\n * An Action is a single operation an agent can perform on a surface.\n * Each action becomes a \"tool\" that the LLM can call.\n *\n * The action's handler executes in the UI (or API) and returns a result\n * that the agent sees as the tool's output.\n */\nexport interface OUIAction {\n /** Unique action identifier (becomes the tool name) */\n id: string;\n\n /** Human-readable description — this is what the LLM reads to decide when to use it */\n description: string;\n\n /** JSON Schema for the action's input parameters */\n input: JSONSchema;\n\n /** JSON Schema for the action's return value (optional — agent still gets the result) */\n output?: JSONSchema;\n\n /** If true, the agent runtime should confirm with the user before executing */\n confirm?: boolean;\n\n /** If true, the action is async — returns immediately with a job/tracking ID */\n async?: boolean;\n\n /** Declarative polling configuration — runtime manages the polling lifecycle after dispatch */\n polling?: OUIActionPolling;\n\n /** Human-readable hint about when this action is appropriate to use */\n usage?: string;\n\n /**\n * Preconditions that should be met before this action is called.\n * Expressed as a description (for the LLM) not as executable logic.\n */\n preconditions?: string;\n\n /** Estimated duration hint (e.g., \"instant\", \"2-5s\", \"30-120s\") */\n estimatedDuration?: string;\n\n /** Tags for categorization */\n tags?: string[];\n}\n\n/**\n * An Observation is a piece of application state that the agent can read.\n * Observations are pushed to the agent in real-time as the app state changes,\n * giving it situational awareness without needing screenshots.\n */\nexport interface OUIObservation {\n /** Unique identifier for this observation */\n id: string;\n\n /** Description of what this observation represents */\n description: string;\n\n /** JSON Schema for the observation's value */\n schema: JSONSchema;\n\n /** How frequently this observation updates */\n updateFrequency?: 'realtime' | 'on-change' | 'polling';\n}\n\n/**\n * Activation conditions — when a surface is available to the agent.\n * A surface might only be active on a specific page, when certain\n * entities are loaded, or under specific application states.\n */\nexport interface OUIActivation {\n /** URL path(s) where this surface is active */\n routes?: string | string[];\n\n /** Entity type/ID that must be present for this surface to activate */\n entity?: {\n type: string;\n id?: string;\n };\n\n /** Custom predicate description (for documentation, not execution) */\n condition?: string;\n}\n\n// ─── Protocol Types ──────────────────────────────────────────────────────────\n\n/**\n * A request from the agent runtime to execute an action on a surface.\n */\nexport interface OUIActionRequest {\n /** Unique request ID for correlation */\n requestId: string;\n\n /** Which surface this request targets */\n surfaceId: string;\n\n /** Which action to invoke */\n actionId: string;\n\n /** The action's input parameters (validated against the action's input schema) */\n params: Record<string, unknown>;\n\n /** Timestamp of the request */\n timestamp: number;\n}\n\n/**\n * The result of an action execution, returned from the surface to the agent.\n */\nexport interface OUIActionResult {\n /** Correlates to the request */\n requestId: string;\n\n /** Whether the action succeeded */\n success: boolean;\n\n /** The action's return data (if successful) */\n data?: unknown;\n\n /** Error information (if failed) */\n error?: {\n code: string;\n message: string;\n details?: unknown;\n };\n\n /** Progress indicator for interim polling results (0-100) */\n progress?: number;\n\n /** Whether this is an interim update (polling still in progress) or final */\n interim?: boolean;\n\n /** Duration of execution in milliseconds */\n durationMs?: number;\n\n /** Timestamp of the result */\n timestamp: number;\n}\n\n/**\n * An observation update pushed from the surface to the agent.\n */\nexport interface OUIObservationUpdate {\n /** Which surface this observation belongs to */\n surfaceId: string;\n\n /** Which observation updated */\n observationId: string;\n\n /** The new value */\n value: unknown;\n\n /** Timestamp of the update */\n timestamp: number;\n}\n\n/**\n * Surface registration event — sent when a surface becomes active.\n */\nexport interface OUISurfaceRegistration {\n /** The full surface manifest */\n surface: OUISurface;\n\n /** Timestamp of registration */\n timestamp: number;\n}\n\n/**\n * Surface deregistration event — sent when a surface becomes inactive.\n */\nexport interface OUISurfaceDeregistration {\n /** Which surface is being deregistered */\n surfaceId: string;\n\n /** Timestamp */\n timestamp: number;\n}\n\n// ─── Transport Protocol Events ───────────────────────────────────────────────\n\n/**\n * All protocol events exchanged between agent runtime and surfaces.\n */\nexport type OUIProtocolEvent =\n | { type: 'surface:register'; payload: OUISurfaceRegistration }\n | { type: 'surface:deregister'; payload: OUISurfaceDeregistration }\n | { type: 'action:request'; payload: OUIActionRequest }\n | { type: 'action:result'; payload: OUIActionResult }\n | { type: 'observation:update'; payload: OUIObservationUpdate };\n\n/**\n * Protocol event type strings (for type guards and routing).\n */\nexport const OUI_PROTOCOL_EVENTS = {\n SURFACE_REGISTER: 'surface:register',\n SURFACE_DEREGISTER: 'surface:deregister',\n ACTION_REQUEST: 'action:request',\n ACTION_RESULT: 'action:result',\n OBSERVATION_UPDATE: 'observation:update',\n} as const;\n"]}
@@ -1,108 +0,0 @@
1
- 'use strict';
2
-
3
- // src/transport/direct.ts
4
- function createDirectTransportPair() {
5
- const actionHandlers = [];
6
- const observationHandlers = [];
7
- const surfaceRegisterHandlers = [];
8
- const surfaceDeregisterHandlers = [];
9
- const server = {
10
- dispatch(surfaceId, actionId, params) {
11
- actionHandlers.forEach((h) => h(surfaceId, actionId, params));
12
- },
13
- onAction() {
14
- return () => {
15
- };
16
- },
17
- // Server doesn't receive dispatches
18
- pushObservation() {
19
- },
20
- // Server doesn't push observations
21
- onObservation(handler) {
22
- observationHandlers.push(handler);
23
- return () => {
24
- const i = observationHandlers.indexOf(handler);
25
- if (i >= 0) observationHandlers.splice(i, 1);
26
- };
27
- },
28
- registerSurface() {
29
- },
30
- deregisterSurface() {
31
- },
32
- onSurfaceRegister(handler) {
33
- surfaceRegisterHandlers.push(handler);
34
- return () => {
35
- const i = surfaceRegisterHandlers.indexOf(handler);
36
- if (i >= 0) surfaceRegisterHandlers.splice(i, 1);
37
- };
38
- },
39
- onSurfaceDeregister(handler) {
40
- surfaceDeregisterHandlers.push(handler);
41
- return () => {
42
- const i = surfaceDeregisterHandlers.indexOf(handler);
43
- if (i >= 0) surfaceDeregisterHandlers.splice(i, 1);
44
- };
45
- },
46
- get connected() {
47
- return true;
48
- },
49
- async connect() {
50
- },
51
- disconnect() {
52
- },
53
- onConnectionChange() {
54
- return () => {
55
- };
56
- }
57
- };
58
- const client = {
59
- dispatch() {
60
- },
61
- // Client doesn't dispatch
62
- onAction(handler) {
63
- actionHandlers.push(handler);
64
- return () => {
65
- const i = actionHandlers.indexOf(handler);
66
- if (i >= 0) actionHandlers.splice(i, 1);
67
- };
68
- },
69
- pushObservation(update) {
70
- observationHandlers.forEach((h) => h(update));
71
- },
72
- onObservation() {
73
- return () => {
74
- };
75
- },
76
- // Client doesn't receive observations
77
- registerSurface(surface) {
78
- surfaceRegisterHandlers.forEach((h) => h(surface));
79
- },
80
- deregisterSurface(surfaceId) {
81
- surfaceDeregisterHandlers.forEach((h) => h(surfaceId));
82
- },
83
- onSurfaceRegister() {
84
- return () => {
85
- };
86
- },
87
- onSurfaceDeregister() {
88
- return () => {
89
- };
90
- },
91
- get connected() {
92
- return true;
93
- },
94
- async connect() {
95
- },
96
- disconnect() {
97
- },
98
- onConnectionChange() {
99
- return () => {
100
- };
101
- }
102
- };
103
- return { server, client };
104
- }
105
-
106
- exports.createDirectTransportPair = createDirectTransportPair;
107
- //# sourceMappingURL=chunk-5TQ6AVQH.cjs.map
108
- //# sourceMappingURL=chunk-5TQ6AVQH.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/transport/direct.ts"],"names":[],"mappings":"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","file":"chunk-5TQ6AVQH.cjs","sourcesContent":["import type { OUITransport, OUIActionHandler, OUIObservationHandler } from './types.js';\nimport type { OUISurface, OUIObservationUpdate } from '../spec/index.js';\n\n/**\n * Direct transport — for same-process communication.\n * Used for API surfaces (where the agent runtime and surface are in the same Lambda)\n * and for testing (where you want synchronous, in-memory communication).\n *\n * Creates a paired (server, client) transport where messages sent on one\n * side are immediately received on the other.\n */\nexport function createDirectTransportPair(): { server: OUITransport; client: OUITransport } {\n const actionHandlers: OUIActionHandler[] = [];\n const observationHandlers: OUIObservationHandler[] = [];\n const surfaceRegisterHandlers: Array<(s: OUISurface) => void> = [];\n const surfaceDeregisterHandlers: Array<(id: string) => void> = [];\n\n const server: OUITransport = {\n dispatch(surfaceId, actionId, params) {\n // Server dispatches → client receives\n actionHandlers.forEach(h => h(surfaceId, actionId, params));\n },\n onAction() { return () => {}; }, // Server doesn't receive dispatches\n pushObservation() {}, // Server doesn't push observations\n onObservation(handler) {\n observationHandlers.push(handler);\n return () => { const i = observationHandlers.indexOf(handler); if (i >= 0) observationHandlers.splice(i, 1); };\n },\n registerSurface() {},\n deregisterSurface() {},\n onSurfaceRegister(handler) {\n surfaceRegisterHandlers.push(handler);\n return () => { const i = surfaceRegisterHandlers.indexOf(handler); if (i >= 0) surfaceRegisterHandlers.splice(i, 1); };\n },\n onSurfaceDeregister(handler) {\n surfaceDeregisterHandlers.push(handler);\n return () => { const i = surfaceDeregisterHandlers.indexOf(handler); if (i >= 0) surfaceDeregisterHandlers.splice(i, 1); };\n },\n get connected() { return true; },\n async connect() {},\n disconnect() {},\n onConnectionChange() { return () => {}; },\n };\n\n const client: OUITransport = {\n dispatch() {}, // Client doesn't dispatch\n onAction(handler) {\n actionHandlers.push(handler);\n return () => { const i = actionHandlers.indexOf(handler); if (i >= 0) actionHandlers.splice(i, 1); };\n },\n pushObservation(update: OUIObservationUpdate) {\n // Client pushes → server receives\n observationHandlers.forEach(h => h(update));\n },\n onObservation() { return () => {}; }, // Client doesn't receive observations\n registerSurface(surface) {\n surfaceRegisterHandlers.forEach(h => h(surface));\n },\n deregisterSurface(surfaceId) {\n surfaceDeregisterHandlers.forEach(h => h(surfaceId));\n },\n onSurfaceRegister() { return () => {}; },\n onSurfaceDeregister() { return () => {}; },\n get connected() { return true; },\n async connect() {},\n disconnect() {},\n onConnectionChange() { return () => {}; },\n };\n\n return { server, client };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/spec/types.ts"],"names":[],"mappings":";AAgSO,IAAM,mBAAA,GAAsB;AAAA,EACjC,gBAAA,EAAkB,kBAAA;AAAA,EAClB,kBAAA,EAAoB,oBAAA;AAAA,EACpB,cAAA,EAAgB,gBAAA;AAAA,EAChB,aAAA,EAAe,eAAA;AAAA,EACf,kBAAA,EAAoB;AACtB","file":"chunk-CVUUSPF4.js","sourcesContent":["/**\n * OUI — Open UI Specification\n *\n * The machine-readable contract for agent-controllable user interfaces.\n * Any UI application that implements this interface can be controlled by\n * any OUI-compatible agent runtime.\n */\n\n/** JSON Schema type (subset used by OUI) */\nexport type JSONSchema = {\n type?: string | string[];\n properties?: Record<string, JSONSchema>;\n items?: JSONSchema;\n required?: string[];\n enum?: (string | number | boolean)[];\n description?: string;\n default?: unknown;\n oneOf?: JSONSchema[];\n anyOf?: JSONSchema[];\n allOf?: JSONSchema[];\n const?: unknown;\n minimum?: number;\n maximum?: number;\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n format?: string;\n additionalProperties?: boolean | JSONSchema;\n};\n\n/**\n * A Surface is a controllable boundary within an application.\n * It declares what an agent can do (actions), what it can observe (state),\n * and when it's available (activation conditions).\n *\n * Think of it as \"one page\" or \"one feature\" of an application, described\n * in a way that an agent can understand and operate.\n */\nexport interface OUISurface {\n /** Unique identifier for this surface (e.g., 'dataviz-wizard', 'document-editor') */\n id: string;\n\n /** Human-readable name */\n name: string;\n\n /** Description of what this surface does — included in agent context */\n description: string;\n\n /** Version of this surface's contract (semver) */\n version?: string;\n\n /** Actions the agent can invoke on this surface */\n actions: OUIAction[];\n\n /** Observable state the agent can read */\n observations?: OUIObservation[];\n\n /** When this surface is active/available */\n activation?: OUIActivation;\n\n /** Additional metadata for agent context */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Declarative polling configuration for async actions.\n * The OUI runtime in the browser manages the polling lifecycle automatically\n * after the action handler returns its dispatch result.\n */\nexport interface OUIActionPolling {\n /** How often to check (milliseconds) */\n intervalMs: number;\n\n /** Max poll attempts before giving up (optional) */\n maxAttempts?: number;\n\n /** Max total duration before giving up in ms (alternative to maxAttempts) */\n maxDurationMs?: number;\n\n /**\n * Subscribe to a realtime event instead of polling.\n * If provided, the runtime listens for this event instead of using setInterval.\n * More efficient when realtime infrastructure exists.\n */\n subscribe?: {\n /** Event name to listen for */\n event: string;\n /**\n * Filter to match the event. Values prefixed with '$dispatchResult.'\n * are resolved from the handler's return value.\n * Example: { jobId: '$dispatchResult.jobId' }\n */\n filter?: Record<string, unknown>;\n };\n}\n\n/**\n * An Action is a single operation an agent can perform on a surface.\n * Each action becomes a \"tool\" that the LLM can call.\n *\n * The action's handler executes in the UI (or API) and returns a result\n * that the agent sees as the tool's output.\n */\nexport interface OUIAction {\n /** Unique action identifier (becomes the tool name) */\n id: string;\n\n /** Human-readable description — this is what the LLM reads to decide when to use it */\n description: string;\n\n /** JSON Schema for the action's input parameters */\n input: JSONSchema;\n\n /** JSON Schema for the action's return value (optional — agent still gets the result) */\n output?: JSONSchema;\n\n /** If true, the agent runtime should confirm with the user before executing */\n confirm?: boolean;\n\n /** If true, the action is async — returns immediately with a job/tracking ID */\n async?: boolean;\n\n /** Declarative polling configuration — runtime manages the polling lifecycle after dispatch */\n polling?: OUIActionPolling;\n\n /** Human-readable hint about when this action is appropriate to use */\n usage?: string;\n\n /**\n * Preconditions that should be met before this action is called.\n * Expressed as a description (for the LLM) not as executable logic.\n */\n preconditions?: string;\n\n /** Estimated duration hint (e.g., \"instant\", \"2-5s\", \"30-120s\") */\n estimatedDuration?: string;\n\n /** Tags for categorization */\n tags?: string[];\n}\n\n/**\n * An Observation is a piece of application state that the agent can read.\n * Observations are pushed to the agent in real-time as the app state changes,\n * giving it situational awareness without needing screenshots.\n */\nexport interface OUIObservation {\n /** Unique identifier for this observation */\n id: string;\n\n /** Description of what this observation represents */\n description: string;\n\n /** JSON Schema for the observation's value */\n schema: JSONSchema;\n\n /** How frequently this observation updates */\n updateFrequency?: 'realtime' | 'on-change' | 'polling';\n}\n\n/**\n * Activation conditions — when a surface is available to the agent.\n * A surface might only be active on a specific page, when certain\n * entities are loaded, or under specific application states.\n */\nexport interface OUIActivation {\n /** URL path(s) where this surface is active */\n routes?: string | string[];\n\n /** Entity type/ID that must be present for this surface to activate */\n entity?: {\n type: string;\n id?: string;\n };\n\n /** Custom predicate description (for documentation, not execution) */\n condition?: string;\n}\n\n// ─── Protocol Types ──────────────────────────────────────────────────────────\n\n/**\n * A request from the agent runtime to execute an action on a surface.\n */\nexport interface OUIActionRequest {\n /** Unique request ID for correlation */\n requestId: string;\n\n /** Which surface this request targets */\n surfaceId: string;\n\n /** Which action to invoke */\n actionId: string;\n\n /** The action's input parameters (validated against the action's input schema) */\n params: Record<string, unknown>;\n\n /** Timestamp of the request */\n timestamp: number;\n}\n\n/**\n * The result of an action execution, returned from the surface to the agent.\n */\nexport interface OUIActionResult {\n /** Correlates to the request */\n requestId: string;\n\n /** Whether the action succeeded */\n success: boolean;\n\n /** The action's return data (if successful) */\n data?: unknown;\n\n /** Error information (if failed) */\n error?: {\n code: string;\n message: string;\n details?: unknown;\n };\n\n /** Progress indicator for interim polling results (0-100) */\n progress?: number;\n\n /** Whether this is an interim update (polling still in progress) or final */\n interim?: boolean;\n\n /** Duration of execution in milliseconds */\n durationMs?: number;\n\n /** Timestamp of the result */\n timestamp: number;\n}\n\n/**\n * An observation update pushed from the surface to the agent.\n */\nexport interface OUIObservationUpdate {\n /** Which surface this observation belongs to */\n surfaceId: string;\n\n /** Which observation updated */\n observationId: string;\n\n /** The new value */\n value: unknown;\n\n /** Timestamp of the update */\n timestamp: number;\n}\n\n/**\n * Surface registration event — sent when a surface becomes active.\n */\nexport interface OUISurfaceRegistration {\n /** The full surface manifest */\n surface: OUISurface;\n\n /** Timestamp of registration */\n timestamp: number;\n}\n\n/**\n * Surface deregistration event — sent when a surface becomes inactive.\n */\nexport interface OUISurfaceDeregistration {\n /** Which surface is being deregistered */\n surfaceId: string;\n\n /** Timestamp */\n timestamp: number;\n}\n\n// ─── Transport Protocol Events ───────────────────────────────────────────────\n\n/**\n * All protocol events exchanged between agent runtime and surfaces.\n */\nexport type OUIProtocolEvent =\n | { type: 'surface:register'; payload: OUISurfaceRegistration }\n | { type: 'surface:deregister'; payload: OUISurfaceDeregistration }\n | { type: 'action:request'; payload: OUIActionRequest }\n | { type: 'action:result'; payload: OUIActionResult }\n | { type: 'observation:update'; payload: OUIObservationUpdate };\n\n/**\n * Protocol event type strings (for type guards and routing).\n */\nexport const OUI_PROTOCOL_EVENTS = {\n SURFACE_REGISTER: 'surface:register',\n SURFACE_DEREGISTER: 'surface:deregister',\n ACTION_REQUEST: 'action:request',\n ACTION_RESULT: 'action:result',\n OBSERVATION_UPDATE: 'observation:update',\n} as const;\n"]}
@@ -1,157 +0,0 @@
1
- 'use strict';
2
-
3
- var chunkMTMEW6MM_cjs = require('./chunk-MTMEW6MM.cjs');
4
-
5
- // src/core/brand.ts
6
- function brand(value) {
7
- return value;
8
- }
9
-
10
- // src/core/define-surface.ts
11
- function defineSurface(definition) {
12
- const actionIds = /* @__PURE__ */ new Set();
13
- for (const action of definition.actions) {
14
- if (actionIds.has(action.id)) {
15
- throw new Error(
16
- `[OUI] Duplicate action ID "${action.id}" in surface "${definition.id}"`
17
- );
18
- }
19
- actionIds.add(action.id);
20
- }
21
- if (definition.observations) {
22
- const obsIds = /* @__PURE__ */ new Set();
23
- for (const obs of definition.observations) {
24
- if (obsIds.has(obs.id)) {
25
- throw new Error(
26
- `[OUI] Duplicate observation ID "${obs.id}" in surface "${definition.id}"`
27
- );
28
- }
29
- obsIds.add(obs.id);
30
- }
31
- }
32
- return brand({
33
- ...definition,
34
- /** Extract the manifest (schema only, no handlers) for transmission to the agent runtime */
35
- toManifest() {
36
- return {
37
- id: definition.id,
38
- name: definition.name,
39
- description: definition.description,
40
- version: definition.version,
41
- activation: definition.activation,
42
- actions: definition.actions.map(actionToManifest),
43
- observations: definition.observations?.map(obsToManifest),
44
- metadata: definition.metadata
45
- };
46
- },
47
- /** Execute an action by ID with the given params and context */
48
- async executeAction(actionId, params, context) {
49
- const action = definition.actions.find((a) => a.id === actionId);
50
- if (!action) {
51
- return {
52
- success: false,
53
- error: {
54
- code: "ACTION_NOT_FOUND",
55
- message: `Action "${actionId}" not found on surface "${definition.id}"`
56
- }
57
- };
58
- }
59
- try {
60
- return await action.handler(params, context);
61
- } catch (err) {
62
- return {
63
- success: false,
64
- error: {
65
- code: "ACTION_EXECUTION_ERROR",
66
- message: err instanceof Error ? err.message : String(err)
67
- }
68
- };
69
- }
70
- },
71
- /** Get all action IDs */
72
- getActionIds() {
73
- return definition.actions.map((a) => a.id);
74
- },
75
- /** Get the polling config for an action (if async) */
76
- getPollingConfig(actionId) {
77
- const action = definition.actions.find((a) => a.id === actionId);
78
- return action?.polling;
79
- }
80
- });
81
- }
82
- function actionToManifest(action) {
83
- return {
84
- id: action.id,
85
- description: action.description,
86
- input: action.input,
87
- output: action.output,
88
- confirm: action.confirm,
89
- async: action.async,
90
- polling: action.polling,
91
- usage: action.usage,
92
- preconditions: action.preconditions,
93
- estimatedDuration: action.estimatedDuration,
94
- tags: action.tags
95
- };
96
- }
97
- function obsToManifest(obs) {
98
- return {
99
- id: obs.id,
100
- description: obs.description,
101
- schema: obs.schema
102
- };
103
- }
104
-
105
- // src/core/create-oui.ts
106
- function createOUI(config) {
107
- const {
108
- socket,
109
- surfaces,
110
- transport: transportConfig
111
- } = config;
112
- if (!socket) {
113
- throw new Error(
114
- "[OUI] createOUI requires a socket. OUI owns the wire; the integrator owns the connection."
115
- );
116
- }
117
- if (!Array.isArray(surfaces) || surfaces.length === 0) {
118
- throw new Error("[OUI] createOUI requires at least one surface.");
119
- }
120
- const seen = /* @__PURE__ */ new Set();
121
- for (const surface of surfaces) {
122
- if (seen.has(surface.id)) {
123
- throw new Error(
124
- `[OUI] Duplicate surface id "${surface.id}". Registration is keyed by id, so the second would replace the first.`
125
- );
126
- }
127
- seen.add(surface.id);
128
- }
129
- const transport = brand(
130
- chunkMTMEW6MM_cjs.createWebSocketTransport(socket, transportConfig)
131
- );
132
- const byId = new Map(surfaces.map((s) => [s.id, s]));
133
- return {
134
- transport,
135
- manifests: surfaces.map((s) => s.toManifest()),
136
- async start() {
137
- await transport.connect();
138
- for (const surface of surfaces) {
139
- transport.registerSurface(surface.toManifest());
140
- }
141
- },
142
- stop() {
143
- for (const surface of surfaces) {
144
- transport.deregisterSurface(surface.id);
145
- }
146
- transport.disconnect();
147
- },
148
- getSurface(id) {
149
- return byId.get(id);
150
- }
151
- };
152
- }
153
-
154
- exports.createOUI = createOUI;
155
- exports.defineSurface = defineSurface;
156
- //# sourceMappingURL=chunk-HK7OXB2W.cjs.map
157
- //# sourceMappingURL=chunk-HK7OXB2W.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/brand.ts","../src/core/define-surface.ts","../src/core/create-oui.ts"],"names":["createWebSocketTransport"],"mappings":"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","file":"chunk-HK7OXB2W.cjs","sourcesContent":["/**\n * Nominal branding for values OUI must construct itself.\n *\n * Structural typing means any object with the right shape satisfies an\n * interface. That is how Closure Studio ended up hand-rolling OUI's transport:\n * `SocketLike` was importable, `OUITransport` was a plain interface, so an\n * integrator could satisfy every type without ever calling OUI. The result was\n * a second implementation of the wire — hardcoded namespace, re-declared\n * payload types on the server, and a dead `action:result` mapping alongside the\n * observation channel that already carried results.\n *\n * A unique symbol cannot be produced outside this module. Branding the types\n * OUI owns turns \"you should use our constructor\" into \"you cannot compile\n * without it\".\n */\n\ndeclare const OUI_BRAND: unique symbol;\n\n/** Marks a value as constructed by OUI itself. */\nexport interface OUIBranded<TKind extends string> {\n readonly [OUI_BRAND]: TKind;\n}\n\n/**\n * Attach the brand at runtime. The property does not exist at runtime — the\n * symbol is declare-only — so this is a type-level assertion with no cost.\n */\nexport function brand<TKind extends string, T>(\n value: T,\n): T & OUIBranded<TKind> {\n return value as T & OUIBranded<TKind>;\n}\n","import type {\n OUISurface,\n OUIAction,\n OUIObservation,\n OUIActivation,\n OUIActionPolling,\n JSONSchema,\n} from \"../spec/index.js\";\nimport { brand, type OUIBranded } from \"./brand.js\";\n\n/**\n * Configuration for defining an OUI surface with handlers.\n * This is the \"integration file\" an app provides — it declares both\n * the schema (what the agent sees) and the implementation (what executes).\n */\nexport interface SurfaceDefinition<TContext = unknown> {\n id: string;\n name: string;\n description: string;\n version?: string;\n activation?: OUIActivation;\n actions: ActionDefinition<TContext>[];\n observations?: ObservationDefinition[];\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Polling config with an optional resolve handler.\n * The spec's OUIActionPolling is the manifest shape (no functions).\n * The core extends it with the resolve implementation for the runtime.\n */\nexport interface ActionPollingConfig<\n TContext = unknown,\n> extends OUIActionPolling {\n /**\n * Called on each poll interval. Receives the dispatch result from the handler\n * plus the current context. Return { done: true, data } to stop polling,\n * or { done: false, data } to continue.\n */\n resolve?: (\n dispatchResult: unknown,\n context: TContext,\n ) => Promise<{ done: boolean; data: unknown }>;\n}\n\n/**\n * An action definition includes both the schema (for the agent) and\n * the handler (for execution). This is the single source of truth —\n * no separate YAML, no separate listener, no drift possible.\n */\nexport interface ActionDefinition<TContext = unknown> {\n id: string;\n description: string;\n input: JSONSchema;\n output?: JSONSchema;\n confirm?: boolean;\n async?: boolean;\n\n /**\n * Polling/subscription config for async actions.\n * After the handler returns, the OUI runtime starts polling or subscribing\n * and pushes observation updates until the operation completes.\n * Extends the spec's OUIActionPolling with an optional resolve handler.\n */\n polling?: ActionPollingConfig<TContext>;\n\n usage?: string;\n preconditions?: string;\n estimatedDuration?: string;\n tags?: string[];\n\n /**\n * The handler that executes when the agent invokes this action.\n * Receives typed params and a context object (app-specific state/utilities).\n * Returns a result that the agent sees as the tool output.\n */\n handler: (\n params: Record<string, unknown>,\n context: TContext,\n ) => Promise<ActionHandlerResult>;\n}\n\nexport interface ActionHandlerResult {\n success: boolean;\n data?: unknown;\n error?: { code: string; message: string; details?: unknown };\n /** For async actions: metadata passed to the polling resolver */\n dispatchMeta?: Record<string, unknown>;\n}\n\nexport interface ObservationDefinition {\n id: string;\n description: string;\n schema: JSONSchema;\n /** Function that returns the current observation value */\n getValue?: () => unknown;\n}\n\n/**\n * Define an OUI surface — the single entry point for integrating\n * an application feature with the OUI protocol.\n *\n * This function validates the definition and returns a typed surface\n * object that can be registered with an agent runtime or transport layer.\n *\n * @example\n * ```typescript\n * const mySurface = defineSurface({\n * id: 'my-feature',\n * name: 'My Feature',\n * description: 'Does something cool',\n * actions: [\n * {\n * id: 'do_thing',\n * description: 'Does the thing',\n * input: { type: 'object', properties: { name: { type: 'string' } }, required: ['name'] },\n * handler: async (params) => {\n * const result = await doTheThing(params.name);\n * return { success: true, data: result };\n * },\n * },\n * ],\n * });\n * ```\n */\nexport function defineSurface<\n TContext = unknown,\n const TId extends string = string,\n>(\n definition: SurfaceDefinition<TContext> & { id: TId },\n): DefinedSurface<TContext> & { id: TId } {\n // Validate: no duplicate action IDs\n const actionIds = new Set<string>();\n for (const action of definition.actions) {\n if (actionIds.has(action.id)) {\n throw new Error(\n `[OUI] Duplicate action ID \"${action.id}\" in surface \"${definition.id}\"`,\n );\n }\n actionIds.add(action.id);\n }\n\n // Validate: no duplicate observation IDs\n if (definition.observations) {\n const obsIds = new Set<string>();\n for (const obs of definition.observations) {\n if (obsIds.has(obs.id)) {\n throw new Error(\n `[OUI] Duplicate observation ID \"${obs.id}\" in surface \"${definition.id}\"`,\n );\n }\n obsIds.add(obs.id);\n }\n }\n\n return brand<\"surface\", unknown>({\n ...definition,\n\n /** Extract the manifest (schema only, no handlers) for transmission to the agent runtime */\n toManifest(): OUISurface {\n return {\n id: definition.id,\n name: definition.name,\n description: definition.description,\n version: definition.version,\n activation: definition.activation,\n actions: definition.actions.map(actionToManifest),\n observations: definition.observations?.map(obsToManifest),\n metadata: definition.metadata,\n };\n },\n\n /** Execute an action by ID with the given params and context */\n async executeAction(\n actionId: string,\n params: Record<string, unknown>,\n context: TContext,\n ): Promise<ActionHandlerResult> {\n const action = definition.actions.find((a) => a.id === actionId);\n if (!action) {\n return {\n success: false,\n error: {\n code: \"ACTION_NOT_FOUND\",\n message: `Action \"${actionId}\" not found on surface \"${definition.id}\"`,\n },\n };\n }\n try {\n return await action.handler(params, context);\n } catch (err) {\n return {\n success: false,\n error: {\n code: \"ACTION_EXECUTION_ERROR\",\n message: err instanceof Error ? err.message : String(err),\n },\n };\n }\n },\n\n /** Get all action IDs */\n getActionIds(): string[] {\n return definition.actions.map((a) => a.id);\n },\n\n /** Get the polling config for an action (if async) */\n getPollingConfig(actionId: string): OUIActionPolling | undefined {\n const action = definition.actions.find((a) => a.id === actionId);\n return action?.polling;\n },\n }) as DefinedSurface<TContext> & { id: TId };\n}\n\n/** A fully defined surface with both manifest extraction and execution capabilities */\n/**\n * Branded so it can only come from `defineSurface`.\n *\n * Without the brand a plain object literal satisfies this interface\n * structurally, which is how an integrator can assemble a surface that never\n * ran defineSurface's duplicate-id checks and never produced a real manifest.\n */\nexport interface DefinedSurface<TContext = unknown>\n extends SurfaceDefinition<TContext>, OUIBranded<\"surface\"> {\n toManifest(): OUISurface;\n executeAction(\n actionId: string,\n params: Record<string, unknown>,\n context: TContext,\n ): Promise<ActionHandlerResult>;\n getActionIds(): string[];\n /** Get the polling config for an action (if async) */\n getPollingConfig(actionId: string): OUIActionPolling | undefined;\n}\n\n// ─── Internal helpers ────────────────────────────────────────────────────────\n\nfunction actionToManifest<T>(action: ActionDefinition<T>): OUIAction {\n return {\n id: action.id,\n description: action.description,\n input: action.input,\n output: action.output,\n confirm: action.confirm,\n async: action.async,\n polling: action.polling,\n usage: action.usage,\n preconditions: action.preconditions,\n estimatedDuration: action.estimatedDuration,\n tags: action.tags,\n };\n}\n\nfunction obsToManifest(obs: ObservationDefinition): OUIObservation {\n return {\n id: obs.id,\n description: obs.description,\n schema: obs.schema,\n };\n}\n","/**\n * createOUI — the only supported way to instantiate OUI.\n *\n * WHY THIS EXISTS\n *\n * OUI shipped a correct protocol and a correct transport, and its first\n * integrator used neither. studio-ui imported only the `SocketLike` TYPE from\n * oui-spec and rebuilt the wire by hand: a literal map of protocol types to\n * socket names, `oui:` hardcoded so the configurable namespace was unreachable,\n * payload interfaces re-declared on the server, and an `action:result` channel\n * mapped but never sent — duplicating the observation channel that already\n * carries results.\n *\n * Nothing was wrong with the spec. Nothing enforced it. Structural typing meant\n * every hand-rolled piece type-checked, and both ends agreed only by the\n * coincidence of matching string literals. Rename one and the other keeps\n * compiling and silently stops receiving.\n *\n * So the requirements are gated here:\n *\n * OUI owns the wire. The integrator provides a socket; it cannot provide a\n * transport, because `OUITransport` values are branded and only this module\n * brands them.\n *\n * OUI owns the result path. Results return through the observation channel,\n * as `use-surface` already implements. An integrator cannot add a parallel\n * channel because it cannot construct a transport to add one to.\n *\n * The integrator owns content. Surfaces, action schemas, observation schemas\n * and handlers all arrive through `defineSurface`, whose output is branded —\n * so a plain object shaped like a surface will not compile.\n *\n * Violations fail at compile time with a message naming the offending id.\n */\nimport type { OUITransport, OUITransportConfig } from \"../transport/types.js\";\nimport type { SocketLike } from \"../transport/websocket.js\";\nimport { createWebSocketTransport } from \"../transport/websocket.js\";\nimport type { DefinedSurface } from \"./define-surface.js\";\nimport { brand, type OUIBranded } from \"./brand.js\";\nimport type { OUIConfigError, ValidateSurfaceIds } from \"./validate.js\";\nimport type { OUISurface } from \"../spec/index.js\";\n\n/** A transport OUI constructed. Integrators cannot produce one. */\nexport type OwnedTransport = OUITransport & OUIBranded<\"transport\">;\n\n/** Surface ids as literal types, for the duplicate check. */\ntype SurfaceIds<T extends readonly DefinedSurface<never>[]> = {\n [K in keyof T]: T[K][\"id\"];\n};\n\nexport interface OUIConfig<TSurfaces extends readonly DefinedSurface<never>[]> {\n /**\n * The socket OUI will speak over. The integrator owns the connection —\n * auth, reconnection, lifecycle — and OUI owns what travels on it.\n */\n socket: SocketLike;\n\n /**\n * Surfaces produced by `defineSurface`. A plain object with the same shape\n * will not compile: DefinedSurface is branded.\n */\n surfaces: TSurfaces;\n\n /**\n * Wire configuration. `namespace` defaults to 'oui' and is the supported way\n * to change the event prefix — hardcoding it at the call site is what made\n * this option unreachable in the first integration.\n */\n transport?: Omit<OUITransportConfig, \"namespace\"> & { namespace?: string };\n}\n\n/** A live OUI instance. */\nexport interface OUIInstance {\n /** The transport OUI owns. Exposed for wiring, not for reimplementation. */\n readonly transport: OwnedTransport;\n\n /** Manifests for every registered surface, as the agent sees them. */\n readonly manifests: readonly OUISurface[];\n\n /** Register every surface and connect. */\n start(): Promise<void>;\n\n /** Deregister every surface and disconnect. */\n stop(): void;\n\n /** Look up a registered surface by id. */\n getSurface(id: string): DefinedSurface<never> | undefined;\n}\n\n/**\n * Instantiate OUI.\n *\n * `const` on the type parameter captures surface ids as literal types, which is\n * what allows duplicate detection to name the offending id rather than failing\n * with an unassignable-to-never error.\n */\nexport function createOUI<\n const TSurfaces extends readonly DefinedSurface<never>[],\n>(\n config: OUIConfig<TSurfaces> & ValidateSurfaceIds<SurfaceIds<TSurfaces>>,\n): OUIInstance {\n const {\n socket,\n surfaces,\n transport: transportConfig,\n } = config as OUIConfig<TSurfaces>;\n\n // Defensive, not decorative: the compile-time checks only bind when a caller\n // passes literals. A surface list assembled at runtime, or JS with no types\n // at all, reaches here unchecked.\n if (!socket) {\n throw new Error(\n \"[OUI] createOUI requires a socket. OUI owns the wire; the integrator owns the connection.\",\n );\n }\n if (!Array.isArray(surfaces) || surfaces.length === 0) {\n throw new Error(\"[OUI] createOUI requires at least one surface.\");\n }\n\n const seen = new Set<string>();\n for (const surface of surfaces) {\n if (seen.has(surface.id)) {\n throw new Error(\n `[OUI] Duplicate surface id \"${surface.id}\". Registration is keyed by id, so the second would replace the first.`,\n );\n }\n seen.add(surface.id);\n }\n\n const transport = brand<\"transport\", OUITransport>(\n createWebSocketTransport(socket, transportConfig),\n );\n\n const byId = new Map(surfaces.map((s) => [s.id, s] as const));\n\n return {\n transport,\n manifests: surfaces.map((s) => s.toManifest()),\n\n async start() {\n await transport.connect();\n for (const surface of surfaces) {\n transport.registerSurface(surface.toManifest());\n }\n },\n\n stop() {\n for (const surface of surfaces) {\n transport.deregisterSurface(surface.id);\n }\n transport.disconnect();\n },\n\n getSurface(id) {\n return byId.get(id);\n },\n };\n}\n\n/** Re-exported so integrators can name the error type in tests. */\nexport type { OUIConfigError };\n"]}