oui-spec 0.8.0 → 0.11.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 (45) hide show
  1. package/README.md +29 -1
  2. package/dist/{chunk-5UUJ3F7C.cjs → chunk-2FFUDX2L.cjs} +5 -3
  3. package/dist/chunk-2FFUDX2L.cjs.map +1 -0
  4. package/dist/{chunk-JRXQLNUL.js → chunk-G4HLDVAI.js} +110 -4
  5. package/dist/chunk-G4HLDVAI.js.map +1 -0
  6. package/dist/{chunk-DLO56KLG.cjs → chunk-LCH3H5ZH.cjs} +158 -34
  7. package/dist/chunk-LCH3H5ZH.cjs.map +1 -0
  8. package/dist/{chunk-63T6SSPP.cjs → chunk-MZ25RAQX.cjs} +117 -3
  9. package/dist/chunk-MZ25RAQX.cjs.map +1 -0
  10. package/dist/{chunk-R3SGP2UY.js → chunk-NXDPC3KW.js} +5 -3
  11. package/dist/chunk-NXDPC3KW.js.map +1 -0
  12. package/dist/{chunk-3MISAULT.js → chunk-XJ34LTWV.js} +132 -10
  13. package/dist/chunk-XJ34LTWV.js.map +1 -0
  14. package/dist/core/index.cjs +15 -7
  15. package/dist/core/index.d.cts +24 -6
  16. package/dist/core/index.d.ts +24 -6
  17. package/dist/core/index.js +3 -3
  18. package/dist/index.cjs +80 -40
  19. package/dist/index.d.cts +5 -5
  20. package/dist/index.d.ts +5 -5
  21. package/dist/index.js +3 -3
  22. package/dist/react/index.d.cts +3 -3
  23. package/dist/react/index.d.ts +3 -3
  24. package/dist/spec/index.cjs +66 -34
  25. package/dist/spec/index.d.cts +61 -3
  26. package/dist/spec/index.d.ts +61 -3
  27. package/dist/spec/index.js +1 -1
  28. package/dist/{surface-runtime-bXSSONF4.d.cts → surface-runtime-C3883XHJ.d.cts} +44 -6
  29. package/dist/{surface-runtime-BsRS0EV1.d.ts → surface-runtime-Da1FSjNF.d.ts} +44 -6
  30. package/dist/transport/index.cjs +2 -2
  31. package/dist/transport/index.d.cts +3 -3
  32. package/dist/transport/index.d.ts +3 -3
  33. package/dist/transport/index.js +1 -1
  34. package/dist/{types-D4czecOw.d.ts → types-DLOa7CWj.d.cts} +9 -0
  35. package/dist/{types-D4czecOw.d.cts → types-DLOa7CWj.d.ts} +9 -0
  36. package/dist/{websocket-BcWDNt_V.d.ts → websocket-Bf7xMzs1.d.ts} +1 -1
  37. package/dist/{websocket-EzQq1mxO.d.cts → websocket-CoSpb5nB.d.cts} +1 -1
  38. package/package.json +1 -1
  39. package/spec/OUI-SPEC-v0.1.md +32 -0
  40. package/dist/chunk-3MISAULT.js.map +0 -1
  41. package/dist/chunk-5UUJ3F7C.cjs.map +0 -1
  42. package/dist/chunk-63T6SSPP.cjs.map +0 -1
  43. package/dist/chunk-DLO56KLG.cjs.map +0 -1
  44. package/dist/chunk-JRXQLNUL.js.map +0 -1
  45. package/dist/chunk-R3SGP2UY.js.map +0 -1
package/README.md CHANGED
@@ -352,7 +352,7 @@ Many UI operations are not instant. A DataViz chart generation might take 30 sec
352
352
  2. Handler fires, calls the API, returns `{ jobId: 'xyz' }` immediately
353
353
  3. OUI runtime starts polling every 2 seconds using the `resolve` function
354
354
  4. Each poll pushes an observation: `{ status: 'processing', progress: 45, interim: true }`
355
- 5. When `resolve` returns `{ done: true }`, polling stops and a final observation is pushed
355
+ 5. When `resolve` returns `{ done: true }`, polling stops and a final observation is pushed. Work that failed returns `{ done: true, data, error: { code, message } }`, and the final result is a failure
356
356
  6. The agent sees the final `{ status: 'complete', chartUrl: '...' }` observation on its next invocation
357
357
 
358
358
  ### Subscribe Mode (Alternative to Polling)
@@ -373,6 +373,33 @@ The `$dispatchResult.` prefix tells the runtime to resolve the filter value from
373
373
 
374
374
  ---
375
375
 
376
+ ## Inputs That Take an Attached File
377
+
378
+ An action can take a file the user attached to their conversation with the agent (spec §7.3.11). Declare the input as a string with the format `oui-attachment` and what the handler takes:
379
+
380
+ ```typescript
381
+ input: {
382
+ type: 'object',
383
+ properties: {
384
+ picture: { type: 'string', format: 'oui-attachment', 'x-oui-attachment': { as: 'file', mediaTypes: ['image/*'] } },
385
+ },
386
+ required: ['picture'],
387
+ },
388
+ handler: async ({ picture }) => useAsTexture(picture as File),
389
+ ```
390
+
391
+ The agent sends the attachment's id. Give the runtime your host's way to open one, and it hands the handler the `File` (or the file's text, with `as: 'text'`) before the handler runs, refusing an id it cannot resolve or a file of a type the input does not take:
392
+
393
+ ```typescript
394
+ createSurfaceRuntime({
395
+ attachments: { resolve: (id, as) => openAttachment(id, as) },
396
+ });
397
+ ```
398
+
399
+ For `as: 'text'`, resolve to the `File` or to `{ name, mediaType, text }`: the runtime checks the type against `mediaTypes` either way, so an `.html` file never reaches an input that takes SVG. A list input takes at most 20 files, resolved a few at a time, and a file input anywhere below the input's own properties (or a list property's items) is refused, since it can be neither checked nor resolved.
400
+
401
+ The index describes the input as `file(image/*)`, and an approval binds the file by its id.
402
+
376
403
  ## Real-World Example: DataViz Surface
377
404
 
378
405
  A complete DataViz wizard surface — the kind of thing you'd build for an AI-assisted analytics tool:
@@ -508,6 +535,7 @@ export const datavizSurface = defineSurface<DataVizContext>({
508
535
  return {
509
536
  done: true,
510
537
  data: { status: "failed", error: status.error },
538
+ error: { code: "RENDER_FAILED", message: status.error },
511
539
  };
512
540
  }
513
541
  return {
@@ -77,7 +77,9 @@ function createWebSocketTransport(socket, config) {
77
77
  }
78
78
  } : {},
79
79
  // The surfaces the agent runtime holds, so the answer need not repeat them (§7.3.4).
80
- ...typeof data.knownSurfaces === "string" && data.knownSurfaces ? { knownSurfaces: data.knownSurfaces } : {}
80
+ ...typeof data.knownSurfaces === "string" && data.knownSurfaces ? { knownSurfaces: data.knownSurfaces } : {},
81
+ // The turn the request belongs to, for a client that accepts per turn (§7.3.1).
82
+ ...typeof data.turnId === "string" && data.turnId ? { turnId: data.turnId } : {}
81
83
  },
82
84
  receipt
83
85
  );
@@ -188,5 +190,5 @@ function acknowledgmentOf(response) {
188
190
  }
189
191
 
190
192
  exports.createWebSocketTransport = createWebSocketTransport;
191
- //# sourceMappingURL=chunk-5UUJ3F7C.cjs.map
192
- //# sourceMappingURL=chunk-5UUJ3F7C.cjs.map
193
+ //# sourceMappingURL=chunk-2FFUDX2L.cjs.map
194
+ //# sourceMappingURL=chunk-2FFUDX2L.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/transport/websocket.ts"],"names":[],"mappings":";;;AA2BO,SAAS,wBAAA,CACd,QACA,MAAA,EACc;AACd,EAAA,MAAM,EAAA,GAAK,QAAQ,SAAA,IAAa,KAAA;AAChC,EAAA,MAAM,SAA6D,EAAC;AACpE,EAAA,MAAM,SAAA,GAAY,QAAQ,aAAA,IAAiB,GAAA;AAC3C,EAAA,MAAM,YAAA,GAAe,QAAQ,uBAAA,IAA2B,IAAA;AAExD,EAAA,IAAI,SAAA,GAAY,OAAO,SAAA,IAAa,KAAA;AACpC,EAAA,MAAM,qBAAkD,EAAC;AAIzD,EAAA,MAAM,WACJ,EAAC;AACH,EAAA,SAAS,MAAA,CACP,OACA,OAAA,EACY;AACZ,IAAA,MAAA,CAAO,EAAA,CAAG,OAAO,OAAO,CAAA;AACxB,IAAA,MAAM,KAAA,GAAQ,EAAE,KAAA,EAAO,OAAA,EAAQ;AAC/B,IAAA,QAAA,CAAS,KAAK,KAAK,CAAA;AACnB,IAAA,OAAO,MAAM;AACX,MAAA,MAAA,CAAO,GAAA,CAAI,OAAO,OAAO,CAAA;AACzB,MAAA,MAAM,CAAA,GAAI,QAAA,CAAS,OAAA,CAAQ,KAAK,CAAA;AAChC,MAAA,IAAI,CAAA,IAAK,CAAA,EAAG,QAAA,CAAS,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,IAClC,CAAA;AAAA,EACF;AAEA,EAAA,MAAA,CAAO,WAAW,MAAM;AACtB,IAAA,SAAA,GAAY,IAAA;AAGZ,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,OAAO,MAAA,CAAO,SAAS,CAAA,EAAG;AACxB,QAAA,MAAM,GAAA,GAAM,OAAO,KAAA,EAAM;AACzB,QAAA,IAAI,GAAA,CAAI,KAAK,MAAA,CAAO,IAAA,CAAK,IAAI,KAAA,EAAO,GAAA,CAAI,IAAA,EAAM,GAAA,CAAI,GAAG,CAAA;AAAA,aAChD,MAAA,CAAO,IAAA,CAAK,GAAA,CAAI,KAAA,EAAO,IAAI,IAAI,CAAA;AAAA,MACtC;AAAA,IACF;AACA,IAAA,kBAAA,CAAmB,OAAA,CAAQ,CAAC,CAAA,KAAM,CAAA,CAAE,IAAI,CAAC,CAAA;AAAA,EAC3C,CAAC,CAAA;AAED,EAAA,MAAA,CAAO,cAAc,MAAM;AACzB,IAAA,SAAA,GAAY,KAAA;AACZ,IAAA,kBAAA,CAAmB,OAAA,CAAQ,CAAC,CAAA,KAAM,CAAA,CAAE,KAAK,CAAC,CAAA;AAAA,EAC5C,CAAC,CAAA;AAED,EAAA,SAAS,IAAA,CAAK,KAAA,EAAe,IAAA,EAAe,GAAA,EAAW;AACrD,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,IAAI,GAAA,EAAK,MAAA,CAAO,IAAA,CAAK,KAAA,EAAO,MAAM,GAAG,CAAA;AAAA,WAChC,MAAA,CAAO,IAAA,CAAK,KAAA,EAAO,IAAI,CAAA;AAAA,IAC9B,CAAA,MAAA,IAAW,YAAA,IAAgB,MAAA,CAAO,MAAA,GAAS,SAAA,EAAW;AACpD,MAAA,MAAA,CAAO,IAAA,CAAK,EAAE,KAAA,EAAO,IAAA,EAAM,GAAI,GAAA,GAAM,EAAE,GAAA,EAAI,GAAI,EAAC,EAAI,CAAA;AAAA,IACtD;AAAA,EACF;AAEA,EAAA,OAAO;AAAA;AAAA,IAEL,SAAS,OAAA,EAA2B;AAClC,MAAA,IAAA,CAAK,CAAA,EAAG,EAAE,CAAA,SAAA,CAAA,EAAa,OAAO,CAAA;AAAA,IAChC,CAAA;AAAA,IAEA,SAAS,OAAA,EAA2B;AAClC,MAAA,OAAO,MAAA;AAAA,QACL,GAAG,EAAE,CAAA,SAAA,CAAA;AAAA,QACL,CAAC,MAA6C,GAAA,KAAkB;AAE9D,UAAA,MAAM,OAAA,GACJ,OAAO,GAAA,KAAQ,UAAA,GACX,CAAC,CAAA,KAA0B,GAAA,CAA6B,CAAC,CAAA,GACzD,MAAA;AAIN,UAAA,IACE,CAAC,IAAA,IACD,OAAO,IAAA,CAAK,SAAA,KAAc,YAC1B,CAAC,IAAA,CAAK,SAAA,IACN,OAAO,KAAK,SAAA,KAAc,QAAA,IAC1B,OAAO,IAAA,CAAK,aAAa,QAAA,EACzB;AACA,YAAA,OAAA,CAAQ,IAAA;AAAA,cACN,+DAAA;AAAA,cACA;AAAA,aACF;AACA,YAAA,OAAA,GAAU;AAAA,cACR,EAAA,EAAI,KAAA;AAAA,cACJ,MAAA,EAAQ;AAAA,aACT,CAAA;AACD,YAAA;AAAA,UACF;AACA,UAAA,OAAA;AAAA,YACE;AAAA,cACE,WAAW,IAAA,CAAK,SAAA;AAAA,cAChB,WAAW,IAAA,CAAK,SAAA;AAAA,cAChB,UAAU,IAAA,CAAK,QAAA;AAAA,cACf,MAAA,EAAQ,IAAA,CAAK,MAAA,IAAU,EAAC;AAAA,cACxB,SAAA,EAAW,IAAA,CAAK,SAAA,IAAa,IAAA,CAAK,GAAA,EAAI;AAAA,cACtC,GAAI,UAAA,CAAW,IAAA,CAAK,QAAQ,CAAA,GACxB;AAAA,gBACE,QAAA,EAAU;AAAA,kBACR,UAAA,EAAY,KAAK,QAAA,CAAS,UAAA;AAAA,kBAC1B,QAAA,EAAU,KAAK,QAAA,CAAS;AAAA;AAC1B,kBAEF,EAAC;AAAA;AAAA,cAEL,GAAI,OAAO,IAAA,CAAK,aAAA,KAAkB,QAAA,IAAY,IAAA,CAAK,aAAA,GAC/C,EAAE,aAAA,EAAe,IAAA,CAAK,aAAA,EAAc,GACpC,EAAC;AAAA;AAAA,cAEL,GAAI,OAAO,IAAA,CAAK,MAAA,KAAW,QAAA,IAAY,IAAA,CAAK,MAAA,GACxC,EAAE,MAAA,EAAQ,IAAA,CAAK,MAAA,EAAO,GACtB;AAAC,aACP;AAAA,YACA;AAAA,WACF;AAAA,QACF;AAAA,OACF;AAAA,IACF,CAAA;AAAA;AAAA,IAGA,UAAA,CACE,QACA,cAAA,EACA;AAEA,MAAA,IAAA;AAAA,QACE,GAAG,EAAE,CAAA,cAAA,CAAA;AAAA,QACL,MAAA;AAAA,QACA,cAAA,GACI,CAAC,QAAA,KAAsB;AACrB,UAAA,MAAM,GAAA,GAAM,iBAAiB,QAAQ,CAAA;AACrC,UAAA,IAAI,GAAA,iBAAoB,GAAG,CAAA;AAAA,QAC7B,CAAA,GACA;AAAA,OACN;AAAA,IACF,CAAA;AAAA,IAEA,SAAS,OAAA,EAA2B;AAClC,MAAA,OAAO,MAAA;AAAA,QAAO,GAAG,EAAE,CAAA,cAAA,CAAA;AAAA,QAAkB,CAAC,IAAA,KACpC,OAAA,CAAQ,IAAI;AAAA,OACd;AAAA,IACF,CAAA;AAAA;AAAA,IAGA,gBAAgB,MAAA,EAA8B;AAC5C,MAAA,IAAA,CAAK,CAAA,EAAG,EAAE,CAAA,YAAA,CAAA,EAAgB,MAAM,CAAA;AAAA,IAClC,CAAA;AAAA,IAEA,cAAc,OAAA,EAAgC;AAC5C,MAAA,OAAO,MAAA;AAAA,QAAO,GAAG,EAAE,CAAA,YAAA,CAAA;AAAA,QAAgB,CAAC,IAAA,KAClC,OAAA,CAAQ,IAAI;AAAA,OACd;AAAA,IACF,CAAA;AAAA;AAAA,IAGA,gBAAgB,OAAA,EAAqB;AACnC,MAAA,IAAA,CAAK,CAAA,EAAG,EAAE,CAAA,iBAAA,CAAA,EAAqB,EAAE,SAAS,SAAA,EAAW,IAAA,CAAK,GAAA,EAAI,EAAG,CAAA;AAAA,IACnE,CAAA;AAAA,IAEA,kBAAkB,SAAA,EAAmB;AACnC,MAAA,IAAA,CAAK,CAAA,EAAG,EAAE,CAAA,mBAAA,CAAA,EAAuB,EAAE,WAAW,SAAA,EAAW,IAAA,CAAK,GAAA,EAAI,EAAG,CAAA;AAAA,IACvE,CAAA;AAAA,IAEA,kBAAkB,OAAA,EAAwC;AACxD,MAAA,OAAO,MAAA;AAAA,QAAO,GAAG,EAAE,CAAA,iBAAA,CAAA;AAAA,QAAqB,CAAC,IAAA,KACvC,OAAA,CAAQ,IAAA,CAAK,OAAO;AAAA,OACtB;AAAA,IACF,CAAA;AAAA,IAEA,oBAAoB,OAAA,EAAsC;AACxD,MAAA,OAAO,MAAA;AAAA,QAAO,GAAG,EAAE,CAAA,mBAAA,CAAA;AAAA,QAAuB,CAAC,IAAA,KACzC,OAAA,CAAQ,IAAA,CAAK,SAAS;AAAA,OACxB;AAAA,IACF,CAAA;AAAA;AAAA,IAGA,IAAI,SAAA,GAAY;AACd,MAAA,OAAO,SAAA;AAAA,IACT,CAAA;AAAA,IAEA,MAAM,OAAA,GAAU;AACd,MAAA,IAAI,SAAA,EAAW;AACf,MAAA,OAAO,IAAI,OAAA,CAAc,CAAC,OAAA,EAAS,MAAA,KAAW;AAC5C,QAAA,MAAM,OAAA,GAAU,WAAW,MAAM;AAC/B,UAAA,MAAA;AAAA,YACE,IAAI,KAAA;AAAA,cACF,CAAA,+BAAA,EAAkC,MAAA,EAAQ,gBAAA,IAAoB,GAAK,CAAA,GAAA;AAAA;AACrE,WACF;AAAA,QACF,CAAA,EAAG,MAAA,EAAQ,gBAAA,IAAoB,GAAK,CAAA;AAEpC,QAAA,MAAA,CAAO,IAAA,CAAK,WAAW,MAAM;AAC3B,UAAA,YAAA,CAAa,OAAO,CAAA;AACpB,UAAA,OAAA,EAAQ;AAAA,QACV,CAAC,CAAA;AAED,QAAA,IAAI,OAAO,MAAA,CAAO,OAAA,KAAY,UAAA,EAAY;AACxC,UAAA,MAAA,CAAO,OAAA,EAAQ;AAAA,QACjB;AAAA,MACF,CAAC,CAAA;AAAA,IACH,CAAA;AAAA,IAEA,UAAA,GAAa;AACX,MAAA,IAAI,OAAO,MAAA,CAAO,UAAA,KAAe,UAAA,EAAY;AAC3C,QAAA,MAAA,CAAO,UAAA,EAAW;AAAA,MACpB;AAAA,IACF,CAAA;AAAA,IAEA,mBAAmB,OAAA,EAA+B;AAChD,MAAA,kBAAA,CAAmB,KAAK,OAAO,CAAA;AAC/B,MAAA,OAAO,MAAM;AACX,QAAA,MAAM,GAAA,GAAM,kBAAA,CAAmB,OAAA,CAAQ,OAAO,CAAA;AAC9C,QAAA,IAAI,GAAA,IAAO,CAAA,EAAG,kBAAA,CAAmB,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,MAChD,CAAA;AAAA,IACF,CAAA;AAAA,IAEA,OAAA,GAAU;AACR,MAAA,KAAA,MAAW,EAAE,KAAA,EAAO,OAAA,MAAa,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA,EAAG;AACnD,QAAA,MAAA,CAAO,GAAA,CAAI,OAAO,OAAO,CAAA;AAAA,MAC3B;AACA,MAAA,kBAAA,CAAmB,MAAA,GAAS,CAAA;AAC5B,MAAA,MAAA,CAAO,MAAA,GAAS,CAAA;AAAA,IAClB;AAAA,GACF;AACF;AAkBA,SAAS,WAAW,KAAA,EAA4C;AAC9D,EAAA,MAAM,CAAA,GAAI,KAAA;AACV,EAAA,OACE,CAAC,CAAC,CAAA,IACF,OAAO,CAAA,CAAE,UAAA,KAAe,QAAA,IACxB,CAAC,CAAC,CAAA,CAAE,UAAA,IACJ,OAAO,EAAE,QAAA,KAAa,QAAA;AAE1B;AASA,SAAS,iBAAiB,QAAA,EAA6C;AACrE,EAAA,MAAM,CAAA,GAAI,QAAA;AAEV,EAAA,IAAI,CAAC,CAAA,IAAK,OAAO,CAAA,KAAM,UAAU,OAAO,IAAA;AACxC,EAAA,IAAI,EAAE,EAAA,KAAO,IAAA,EAAM,OAAO,EAAE,IAAI,IAAA,EAAK;AACrC,EAAA,IAAI,CAAA,CAAE,EAAA,KAAO,KAAA,EAAO,OAAO,IAAA;AAC3B,EAAA,MAAM,GAAA,GACJ,OAAO,CAAA,CAAE,KAAA,KAAU,QAAA,GACf,CAAA,CAAE,KAAA,GACF,OAAO,CAAA,CAAE,MAAA,KAAW,QAAA,GAClB,CAAA,CAAE,MAAA,GACF,EAAA;AACR,EAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,MAAA,EAAQ,OAAO,SAAA,EAAU;AAC/C","file":"chunk-2FFUDX2L.cjs","sourcesContent":["import type {\n OUIAcknowledgment,\n OUITransport,\n OUITransportConfig,\n OUIActionHandler,\n OUIObservationHandler,\n OUIResultHandler,\n} from \"./types.js\";\nimport type {\n OUISurface,\n OUIObservationUpdate,\n OUIActionRequest,\n OUIActionResult,\n OUIActionApproval,\n} from \"../spec/index.js\";\n\n/**\n * WebSocket transport using Socket.IO.\n * Maps OUI protocol events to socket events with a configurable namespace prefix.\n *\n * Events:\n * {ns}:dispatch — action request (runtime → client)\n * {ns}:action:result — action result (client → runtime)\n * {ns}:observation — observation (client → runtime)\n * {ns}:surface:register — registration (client → runtime)\n * {ns}:surface:deregister — deregistration (client → runtime)\n */\nexport function createWebSocketTransport(\n socket: SocketLike,\n config?: OUITransportConfig,\n): OUITransport {\n const ns = config?.namespace ?? \"oui\";\n const buffer: Array<{ event: string; data: unknown; ack?: Ack }> = [];\n const maxBuffer = config?.maxBufferSize ?? 100;\n const shouldBuffer = config?.bufferWhileDisconnected ?? true;\n\n let connected = socket.connected ?? false;\n const connectionHandlers: Array<(c: boolean) => void> = [];\n\n // Every listener this transport attaches, so dispose() can remove exactly\n // these and nothing the integrator attached to the same socket.\n const attached: Array<{ event: string; handler: (...args: any[]) => void }> =\n [];\n function listen(\n event: string,\n handler: (...args: any[]) => void,\n ): () => void {\n socket.on(event, handler);\n const entry = { event, handler };\n attached.push(entry);\n return () => {\n socket.off(event, handler);\n const i = attached.indexOf(entry);\n if (i >= 0) attached.splice(i, 1);\n };\n }\n\n listen(\"connect\", () => {\n connected = true;\n // Flush before announcing: anything queued while offline was sent earlier\n // than whatever a connection handler is about to send.\n if (shouldBuffer) {\n while (buffer.length > 0) {\n const msg = buffer.shift()!;\n if (msg.ack) socket.emit(msg.event, msg.data, msg.ack);\n else socket.emit(msg.event, msg.data);\n }\n }\n connectionHandlers.forEach((h) => h(true));\n });\n\n listen(\"disconnect\", () => {\n connected = false;\n connectionHandlers.forEach((h) => h(false));\n });\n\n function emit(event: string, data: unknown, ack?: Ack) {\n if (connected) {\n if (ack) socket.emit(event, data, ack);\n else socket.emit(event, data);\n } else if (shouldBuffer && buffer.length < maxBuffer) {\n buffer.push({ event, data, ...(ack ? { ack } : {}) });\n }\n }\n\n return {\n // ─── Dispatch ───────────────────────────────────────────────\n dispatch(request: OUIActionRequest) {\n emit(`${ns}:dispatch`, request);\n },\n\n onAction(handler: OUIActionHandler) {\n return listen(\n `${ns}:dispatch`,\n (data: Partial<OUIActionRequest> | undefined, ack?: unknown) => {\n // The sender's receipt, when it asked for one (§7.3.7).\n const receipt =\n typeof ack === \"function\"\n ? (a: OUIAcknowledgment) => (ack as (r: unknown) => void)(a)\n : undefined;\n // A request without a requestId cannot be answered, and answering is\n // the contract. Refuse it loudly rather than run an action whose\n // result has nowhere to go.\n if (\n !data ||\n typeof data.requestId !== \"string\" ||\n !data.requestId ||\n typeof data.surfaceId !== \"string\" ||\n typeof data.actionId !== \"string\"\n ) {\n console.warn(\n \"[OUI] Dropped a dispatch without requestId/surfaceId/actionId\",\n data,\n );\n receipt?.({\n ok: false,\n reason: \"a request needs requestId, surfaceId and actionId\",\n });\n return;\n }\n handler(\n {\n requestId: data.requestId,\n surfaceId: data.surfaceId,\n actionId: data.actionId,\n params: data.params ?? {},\n timestamp: data.timestamp ?? Date.now(),\n ...(isApproval(data.approval)\n ? {\n approval: {\n approvalId: data.approval.approvalId,\n argsHash: data.approval.argsHash,\n },\n }\n : {}),\n // The surfaces the agent runtime holds, so the answer need not repeat them (§7.3.4).\n ...(typeof data.knownSurfaces === \"string\" && data.knownSurfaces\n ? { knownSurfaces: data.knownSurfaces }\n : {}),\n // The turn the request belongs to, for a client that accepts per turn (§7.3.1).\n ...(typeof data.turnId === \"string\" && data.turnId\n ? { turnId: data.turnId }\n : {}),\n },\n receipt,\n );\n },\n );\n },\n\n // ─── Result ─────────────────────────────────────────────────\n sendResult(\n result: OUIActionResult,\n onAcknowledged?: (ack: OUIAcknowledgment) => void,\n ) {\n // Acknowledged, so a refusal is heard rather than silent (§7.3.6).\n emit(\n `${ns}:action:result`,\n result,\n onAcknowledged\n ? (response: unknown) => {\n const ack = acknowledgmentOf(response);\n if (ack) onAcknowledged(ack);\n }\n : undefined,\n );\n },\n\n onResult(handler: OUIResultHandler) {\n return listen(`${ns}:action:result`, (data: OUIActionResult) =>\n handler(data),\n );\n },\n\n // ─── Observation Channel ────────────────────────────────────\n pushObservation(update: OUIObservationUpdate) {\n emit(`${ns}:observation`, update);\n },\n\n onObservation(handler: OUIObservationHandler) {\n return listen(`${ns}:observation`, (data: OUIObservationUpdate) =>\n handler(data),\n );\n },\n\n // ─── Surface Lifecycle ──────────────────────────────────────\n registerSurface(surface: OUISurface) {\n emit(`${ns}:surface:register`, { surface, timestamp: Date.now() });\n },\n\n deregisterSurface(surfaceId: string) {\n emit(`${ns}:surface:deregister`, { surfaceId, timestamp: Date.now() });\n },\n\n onSurfaceRegister(handler: (surface: OUISurface) => void) {\n return listen(`${ns}:surface:register`, (data: { surface: OUISurface }) =>\n handler(data.surface),\n );\n },\n\n onSurfaceDeregister(handler: (surfaceId: string) => void) {\n return listen(`${ns}:surface:deregister`, (data: { surfaceId: string }) =>\n handler(data.surfaceId),\n );\n },\n\n // ─── Connection ─────────────────────────────────────────────\n get connected() {\n return connected;\n },\n\n async connect() {\n if (connected) return;\n return new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(\n new Error(\n `OUI transport connect timeout (${config?.connectTimeoutMs ?? 10000}ms)`,\n ),\n );\n }, config?.connectTimeoutMs ?? 10000);\n\n socket.once(\"connect\", () => {\n clearTimeout(timeout);\n resolve();\n });\n\n if (typeof socket.connect === \"function\") {\n socket.connect();\n }\n });\n },\n\n disconnect() {\n if (typeof socket.disconnect === \"function\") {\n socket.disconnect();\n }\n },\n\n onConnectionChange(handler: (c: boolean) => void) {\n connectionHandlers.push(handler);\n return () => {\n const idx = connectionHandlers.indexOf(handler);\n if (idx >= 0) connectionHandlers.splice(idx, 1);\n };\n },\n\n dispose() {\n for (const { event, handler } of attached.splice(0)) {\n socket.off(event, handler);\n }\n connectionHandlers.length = 0;\n buffer.length = 0;\n },\n };\n}\n\n/**\n * Minimal socket interface — compatible with Socket.IO client or server socket.\n * Only the methods OUI actually uses.\n */\nexport interface SocketLike {\n readonly connected?: boolean;\n /** An optional last argument is the receiver's acknowledgment callback, as Socket.IO takes it. */\n emit(event: string, ...args: any[]): void;\n on(event: string, handler: (...args: any[]) => void): void;\n off(event: string, handler: (...args: any[]) => void): void;\n once(event: string, handler: (...args: any[]) => void): void;\n connect?(): void;\n disconnect?(): void;\n}\n\n/** An approval as the wire carries it; anything else is dropped, so the runtime treats the request as unapproved. */\nfunction isApproval(value: unknown): value is OUIActionApproval {\n const a = value as Partial<OUIActionApproval> | null | undefined;\n return (\n !!a &&\n typeof a.approvalId === \"string\" &&\n !!a.approvalId &&\n typeof a.argsHash === \"string\"\n );\n}\n\n/** The receiver's acknowledgment callback. */\ntype Ack = (response: unknown) => void;\n\n/**\n * A receiver's acknowledgment: `{ ok: true }`, or `{ ok: false, error }` /\n * `{ ok: false, reason }` as a refusal; null for anything else.\n */\nfunction acknowledgmentOf(response: unknown): OUIAcknowledgment | null {\n const r = response as\n { ok?: unknown; error?: unknown; reason?: unknown } | null | undefined;\n if (!r || typeof r !== \"object\") return null;\n if (r.ok === true) return { ok: true };\n if (r.ok !== false) return null;\n const why =\n typeof r.error === \"string\"\n ? r.error\n : typeof r.reason === \"string\"\n ? r.reason\n : \"\";\n return { ok: false, reason: why || \"refused\" };\n}\n"]}
@@ -154,6 +154,108 @@ function hex32(n) {
154
154
  return (n >>> 0).toString(16).padStart(8, "0");
155
155
  }
156
156
 
157
+ // src/spec/attachments.ts
158
+ var OUI_ATTACHMENT_FORMAT = "oui-attachment";
159
+ function isAttachmentId(value) {
160
+ return typeof value === "string" && /^[A-Za-z0-9_-]{8,64}$/.test(value);
161
+ }
162
+ var ATTACHMENT_ID_PATTERN = /^[A-Za-z0-9_-]{8,64}$/;
163
+ function attachmentInputOf(schema) {
164
+ if (!schema || schema.format !== OUI_ATTACHMENT_FORMAT) return null;
165
+ const declared = schema["x-oui-attachment"];
166
+ const as = declared?.as === "text" ? "text" : "file";
167
+ const mediaTypes = Array.isArray(declared?.mediaTypes) ? declared.mediaTypes.filter((t) => typeof t === "string") : void 0;
168
+ return { as, ...mediaTypes?.length ? { mediaTypes } : {} };
169
+ }
170
+ function acceptsMediaType(input, mediaType) {
171
+ if (!input.mediaTypes?.length) return true;
172
+ const type = mediaType.split(";")[0].trim().toLowerCase();
173
+ return input.mediaTypes.some((accepted) => {
174
+ const a = accepted.toLowerCase();
175
+ return a.endsWith("/*") ? type.startsWith(a.slice(0, -1)) : a === type;
176
+ });
177
+ }
178
+ function attachmentInputs(schema) {
179
+ const found = [];
180
+ for (const [name, property] of Object.entries(schema?.properties ?? {})) {
181
+ const direct = attachmentInputOf(property);
182
+ if (direct) {
183
+ found.push({ path: [name], input: direct });
184
+ continue;
185
+ }
186
+ const item = property.type === "array" ? attachmentInputOf(property.items) : null;
187
+ if (item) found.push({ path: [name, "*"], input: item });
188
+ }
189
+ return found;
190
+ }
191
+ function misplacedAttachmentInputs(schema) {
192
+ const misplaced = [];
193
+ const visit = (node, path, depth) => {
194
+ if (!node || typeof node !== "object" || depth > 32) return;
195
+ const s = node;
196
+ if (s.format === OUI_ATTACHMENT_FORMAT) misplaced.push(path || "(input)");
197
+ const child = (value, at) => visit(value, at, depth + 1);
198
+ for (const [name, sub] of Object.entries(
199
+ s.properties ?? {}
200
+ ))
201
+ child(sub, path ? `${path}.${name}` : name);
202
+ if (s.items) child(s.items, `${path}[]`);
203
+ for (const key of ["anyOf", "oneOf", "allOf", "prefixItems"]) {
204
+ const list = s[key];
205
+ if (Array.isArray(list))
206
+ list.forEach((sub, i) => child(sub, `${path}.${key}[${i}]`));
207
+ }
208
+ for (const key of [
209
+ "additionalProperties",
210
+ "not",
211
+ "if",
212
+ "then",
213
+ "else",
214
+ "contains"
215
+ ])
216
+ if (s[key] && typeof s[key] === "object") child(s[key], `${path}.${key}`);
217
+ for (const key of ["patternProperties", "$defs", "definitions"]) {
218
+ const map = s[key];
219
+ if (map && typeof map === "object")
220
+ for (const [name, sub] of Object.entries(
221
+ map
222
+ ))
223
+ child(sub, `${path}.${key}.${name}`);
224
+ }
225
+ };
226
+ if (!schema) return misplaced;
227
+ const { properties, ...rest } = schema;
228
+ visit({ ...rest, format: void 0 }, "", 0);
229
+ for (const [name, property] of Object.entries(
230
+ properties ?? {}
231
+ )) {
232
+ if (attachmentInputOf(property)) {
233
+ const { format: _f, ...below } = property;
234
+ visit(below, name, 1);
235
+ continue;
236
+ }
237
+ if (property.type === "array" && attachmentInputOf(property.items)) {
238
+ const { items, ...list } = property;
239
+ const { format: _f, ...below } = items;
240
+ visit(list, name, 1);
241
+ visit(below, `${name}[]`, 2);
242
+ continue;
243
+ }
244
+ visit(property, name, 1);
245
+ }
246
+ return misplaced;
247
+ }
248
+ function attachmentIdsIn(schema, params) {
249
+ const ids = [];
250
+ for (const { path, input } of attachmentInputs(schema)) {
251
+ const value = params[path[0]];
252
+ const values = path.length === 2 ? Array.isArray(value) ? value : [] : [value];
253
+ for (const v of values)
254
+ if (typeof v === "string") ids.push({ id: v, property: path[0], input });
255
+ }
256
+ return ids;
257
+ }
258
+
157
259
  // src/spec/index-form.ts
158
260
  var INDEX_DESCRIPTION_CHARS = 160;
159
261
  var INDEX_INPUT_CHARS = 120;
@@ -234,8 +336,12 @@ function valueSummary(schema) {
234
336
  const range = min !== void 0 && max !== void 0 ? ` ${min}\u2013${max}` : min !== void 0 ? ` \u2265${min}` : max !== void 0 ? ` \u2264${max}` : "";
235
337
  return `${type}${range}${unitOf(schema)}`;
236
338
  }
237
- if (type === "string")
339
+ if (type === "string") {
340
+ const file = attachmentInputOf(schema);
341
+ if (file)
342
+ return file.mediaTypes?.length ? `file(${file.mediaTypes.join("|")})` : "file";
238
343
  return schema.format ? `string(${schema.format})` : "string";
344
+ }
239
345
  if (type === "array")
240
346
  return schema.items ? `list of ${valueSummary(schema.items)}` : "list";
241
347
  if (type === "object") {
@@ -445,6 +551,6 @@ function fitObservations(observations, budget) {
445
551
  return { observations: fitted, cuts: [...cuts.values()] };
446
552
  }
447
553
 
448
- export { ARGS_HASH_PATTERN, DEFINITION_HASH_HEX, FIT_LIST_STEPS, FIT_TEXT_CHARS, INDEX_DESCRIPTION_CHARS, INDEX_INPUT_CHARS, INDEX_INPUT_PROPERTIES, OUI_DESCRIBE_ACTION, OUI_EFFECT_ACCESS, OUI_EFFECT_KINDS, OUI_PROTOCOL_EVENTS, OUI_READ_ACTION, OUI_RUNTIME_SURFACE, argsHash, atPointer, canonicalJson, constantOf, definitionHash, discriminatorOf, effectAccess, firstSentence, fitObservations, indexEntry, jsonBytes, pointerStep, pointerSteps, requiresApproval, sortedJson, summarizeInput, surfaceIndex, surfacesHash, utf8Length, withoutTitleLeadIn };
449
- //# sourceMappingURL=chunk-JRXQLNUL.js.map
450
- //# sourceMappingURL=chunk-JRXQLNUL.js.map
554
+ export { ARGS_HASH_PATTERN, ATTACHMENT_ID_PATTERN, DEFINITION_HASH_HEX, FIT_LIST_STEPS, FIT_TEXT_CHARS, INDEX_DESCRIPTION_CHARS, INDEX_INPUT_CHARS, INDEX_INPUT_PROPERTIES, OUI_ATTACHMENT_FORMAT, OUI_DESCRIBE_ACTION, OUI_EFFECT_ACCESS, OUI_EFFECT_KINDS, OUI_PROTOCOL_EVENTS, OUI_READ_ACTION, OUI_RUNTIME_SURFACE, acceptsMediaType, argsHash, atPointer, attachmentIdsIn, attachmentInputOf, attachmentInputs, canonicalJson, constantOf, definitionHash, discriminatorOf, effectAccess, firstSentence, fitObservations, indexEntry, isAttachmentId, jsonBytes, misplacedAttachmentInputs, pointerStep, pointerSteps, requiresApproval, sortedJson, summarizeInput, surfaceIndex, surfacesHash, utf8Length, withoutTitleLeadIn };
555
+ //# sourceMappingURL=chunk-G4HLDVAI.js.map
556
+ //# sourceMappingURL=chunk-G4HLDVAI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/spec/types.ts","../src/spec/approval.ts","../src/spec/surfaces-hash.ts","../src/spec/attachments.ts","../src/spec/index-form.ts","../src/spec/fit.ts"],"names":[],"mappings":"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","file":"chunk-G4HLDVAI.js","sourcesContent":["import type { OUIActionApproval, OUIEffectKind } from \"./approval.js\";\n\n/**\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 title?: string;\n /** Annotations (`x-unit`, `x-rows`, …) a product's contract adds; OUI carries them unread. */\n [annotation: `x-${string}`]: unknown;\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 /** The action's name as a person reads it, for a confirmation the user approves. */\n title?: string;\n\n /**\n * What using the action does. A `transaction` runs only on the user's\n * approval of the exact request (see `requiresApproval`). Undeclared counts\n * as a write.\n */\n effect?: OUIEffectKind;\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 /**\n * Destructive: the action removes or replaces something the person made.\n * Unless its effect only reads, it runs only on the user's approval of the\n * exact request, which the surface runtime checks before it runs.\n */\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// ─── Index form (§7.3.8) ───────────────────────────────────────────────────────\n\n/**\n * One action as a snapshot and an answer carry it: enough to choose it and to\n * know what it takes in outline, without its definition. A page's actions\n * weigh what its whole catalogue weighs (on a studio page, several hundred\n * KB), and an agent runtime that received every definition could neither be\n * sent them in one frame nor give them all to its model. The definition of an\n * action is fetched when it is needed (`oui.describe`, §7.3.10).\n */\nexport interface OUIActionIndexEntry {\n /** The action's id. */\n id: string;\n /** Its name as a person reads it. */\n title?: string;\n /** The first sentence of its description, at most `INDEX_DESCRIPTION_CHARS` characters. */\n description: string;\n effect?: OUIEffectKind;\n confirm?: boolean;\n async?: boolean;\n estimatedDuration?: string;\n /** For an async action: how long its work is followed before it is reported as not finished. */\n maxDurationMs?: number;\n /** What it takes, in one line (`summarizeInput`): \"none\", \"value: number 0–100\", \"clipId, start?, +4 more\". */\n input: string;\n /**\n * A hash of the full definition: a fetched definition is good until this\n * changes. Opaque to a reader, which only compares it with the same action's\n * earlier one: 8 hex digits since 0.8, 16 before.\n */\n definitionHash: string;\n}\n\n/** A surface as a snapshot and an answer carry it in index form: its actions as index entries. */\nexport interface OUISurfaceIndex {\n id: string;\n name: string;\n description: string;\n version?: string;\n /** Observation definitions travel whole: they are small, and say how to read the values that follow. */\n observations?: OUIObservation[];\n index: OUIActionIndexEntry[];\n}\n\n/**\n * One place where a snapshot's or an answer's observations were shortened to\n * fit its byte budget (§7.3.9): a list cut to its first rows, a long text cut,\n * or a value left out. The rest is read with `oui.read` (§7.3.10), by this\n * surface, observation and path.\n */\nexport interface OUIFitCut {\n surface: string;\n observation: string;\n /** JSON Pointer (RFC 6901) into the observation's value; \"\" is the value itself. */\n path: string;\n kind: \"list\" | \"text\" | \"value\";\n /** Rows of a list, characters of a text, bytes of a value. */\n total: number;\n /** How many of them this frame keeps. */\n kept: number;\n}\n\n/** What was shortened or left out to fit a frame's byte budget (§7.3.9). */\nexport interface OUIFit {\n observations?: OUIFitCut[];\n /** The action's `data` was left out: its size, and the most a frame could carry. */\n data?: { bytes: number; limit: number };\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 * The turn of the agent's work this request belongs to. A client that runs\n * one turn at a time accepts a request only for its current turn (`accept`),\n * so a request sent late by a turn the person has stopped or superseded does\n * not run under their newer instruction. Optional: an agent runtime that\n * does not know of turns sends none, and a client then applies whatever rule\n * it had without it.\n */\n turnId?: string;\n\n /**\n * The user's approval this request runs on, for an action that needs one.\n * The surface runtime runs such an action only when this matches a grant\n * the tab received from the user's own confirmation, for exactly `params`.\n */\n approval?: OUIActionApproval;\n\n /**\n * The `surfacesHash` of the surfaces the agent runtime already holds for\n * this client: from its snapshot, or from an earlier result. A client whose\n * surfaces still hash to this answers without `surfaces`, so a result\n * carries the client's surfaces only when they changed (§7.3.4).\n */\n knownSurfaces?: string;\n}\n\n/**\n * Why a client's answer is shorter than the result it produced: the receiving\n * side refused the full answer (too large, or otherwise not accepted), so the\n * client sent it again without the parts named in `omitted`. The action's own\n * outcome — `success`, `error`, and `data` unless omitted — is still the one\n * that happened (§7.3.6).\n */\nexport interface OUIResultDelivery {\n trimmed: true;\n /** What the receiving side said when it refused the full answer. */\n reason: string;\n /** The fields left out of this answer. */\n omitted: Array<\"surfaces\" | \"index\" | \"observations\" | \"data\">;\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 * The surfaces active on the client once the action's effects settled.\n *\n * An action can change what the agent is able to do next: navigating\n * unmounts one page's surfaces and mounts another's. Without this, the agent\n * would act on the capability set it had before the action, which is the\n * set the action just replaced.\n */\n surfaces?: OUISurface[];\n\n /**\n * The same, in index form (§7.3.8): what a client sends in place of\n * `surfaces` unless it was made to send definitions.\n */\n index?: OUISurfaceIndex[];\n\n /** Latest observation values per surface once the action's effects settled. */\n observations?: OUIObservationSnapshot;\n\n /** What was shortened or left out so this answer fits its byte budget (§7.3.9). */\n fit?: OUIFit;\n\n /**\n * The hash of the client's surfaces once the action's effects settled\n * (`surfacesHash`). Always present from a client that sends it; `surfaces`\n * is then present only when this differs from the request's\n * `knownSurfaces`, and an agent runtime that holds surfaces with this hash\n * keeps using them.\n */\n surfacesHash?: string;\n\n /** Present when this answer was trimmed to be delivered (§7.3.6). */\n delivery?: OUIResultDelivery;\n\n /**\n * False when the client's deadline passed before its UI settled, so\n * `surfaces` and `observations` may still be changing. Absent or true\n * otherwise.\n */\n settled?: boolean;\n}\n\n/** Latest observation values, keyed by surface id and then observation id. */\nexport type OUIObservationSnapshot = Record<string, Record<string, unknown>>;\n\n/**\n * What a client can do right now: the surfaces it has mounted and their latest\n * observation values. A client sends this to its agent runtime (for example,\n * with each turn), and returns it on every action result.\n *\n * This is the full form: every action with its definition. A client made in\n * index form (§7.3.8) sends an `OUIIndexSnapshot` instead.\n */\nexport interface OUISurfaceSnapshot {\n surfaces: OUISurface[];\n observations: OUIObservationSnapshot;\n /**\n * `surfacesHash(surfaces)`: what an agent runtime sends back as a request's\n * `knownSurfaces`, so the client's answer need not repeat surfaces the\n * runtime already holds.\n */\n surfacesHash?: string;\n /** What was shortened so the snapshot fits its byte budget (§7.3.9). */\n fit?: OUIFit;\n}\n\n/** A client's snapshot in index form (§7.3.8): each action as an index entry, not its definition. */\nexport interface OUIIndexSnapshot {\n index: OUISurfaceIndex[];\n observations: OUIObservationSnapshot;\n /** `surfacesHash(index)`. */\n surfacesHash?: string;\n /** What was shortened so the snapshot fits its byte budget (§7.3.9). */\n fit?: OUIFit;\n}\n\n/** A snapshot as an agent runtime receives it: in either form. */\nexport type OUIClientSnapshot = OUISurfaceSnapshot | OUIIndexSnapshot;\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","/**\n * Approvals: an irreversible action runs only on an approval the user gave,\n * bound to the exact request.\n *\n * An agent runtime stops at an action that needs approval and shows the user\n * a confirmation. Its approval store issues a single-use grant when the user\n * confirms, and the request that then reaches the tab carries `approval:\n * { approvalId, argsHash }`. The surface runtime runs the action only when\n * that matches a grant this tab received from the user's own confirmation.\n *\n * Everything that checks a request computes the same args hash: SHA-256 over\n * the RFC 8785 (JCS) canonical JSON of its params, lowercase hex. The\n * published vectors (`oui-spec/approval-vectors.json`) hold every\n * implementation, in any language, to it.\n */\n\n/**\n * What using an action does. One vocabulary for every kind of action, so an\n * action is told apart by what it changes:\n *\n * | Effect | What it changes | Access |\n * |---|---|---|\n * | `view`, `selection`, `navigate`, `open` | What is shown | read |\n * | `edit` | The document, one undo step | write |\n * | `file` | Imports or exports a file | write |\n * | `mutate` | Backend data, through an API operation | write |\n * | `job` | Starts work that outlives the call | write |\n * | `transaction` | An irreversible external act: an order, a payment, a send, a publish | write, approved |\n */\nexport type OUIEffectKind =\n | \"view\"\n | \"selection\"\n | \"navigate\"\n | \"open\"\n | \"edit\"\n | \"file\"\n | \"mutate\"\n | \"job\"\n | \"transaction\";\n\n/** Every effect, in the order of the table above. */\nexport const OUI_EFFECT_KINDS: readonly OUIEffectKind[] = [\n \"view\",\n \"selection\",\n \"navigate\",\n \"open\",\n \"edit\",\n \"file\",\n \"mutate\",\n \"job\",\n \"transaction\",\n];\n\n/** Whether an effect only changes what is shown, or changes something. */\nexport const OUI_EFFECT_ACCESS: Readonly<\n Record<OUIEffectKind, \"read\" | \"write\">\n> = {\n view: \"read\",\n selection: \"read\",\n navigate: \"read\",\n open: \"read\",\n edit: \"write\",\n file: \"write\",\n mutate: \"write\",\n job: \"write\",\n transaction: \"write\",\n};\n\n/** `read` or `write`. An action that declares no effect is a `write`: nothing says it only shows. */\nexport function effectAccess(\n effect: OUIEffectKind | undefined,\n): \"read\" | \"write\" {\n return effect === undefined ? \"write\" : OUI_EFFECT_ACCESS[effect];\n}\n\n/**\n * Whether running an action needs the user's approval of the exact request: a\n * `transaction` always, and a `write` declared destructive. An agent\n * runtime's policy may require it of more; nothing waives these.\n */\nexport function requiresApproval(\n effect: OUIEffectKind | undefined,\n destructive?: boolean,\n): boolean {\n if (effect === \"transaction\") return true;\n return !!destructive && effectAccess(effect) === \"write\";\n}\n\n/** What a request for an approved action carries. */\nexport interface OUIActionApproval {\n approvalId: string;\n /** `argsHash(params)` of the request the user approved. */\n argsHash: string;\n}\n\n/** A grant this tab holds: the user approved this request here. */\nexport interface OUIApprovalGrant extends OUIActionApproval {\n /** Epoch ms after which the grant no longer admits anything. */\n expiresAt: number;\n}\n\n/** An args hash: 64 lowercase hex digits. */\nexport const ARGS_HASH_PATTERN = /^[0-9a-f]{64}$/;\n\n/**\n * The RFC 8785 canonical form of a JSON value:\n * - object members sorted by their names' UTF-16 code units, with no\n * whitespace;\n * - numbers in ECMAScript's shortest round-trip form (`-0` is `0`);\n * - strings escaped as ECMAScript's `JSON.stringify` escapes them.\n *\n * The value must be I-JSON (RFC 7493): anything JSON cannot carry — `NaN`,\n * infinities, `undefined` outside an object member, a bigint, a function, a\n * symbol, a class instance, or a string with a lone surrogate — is refused\n * rather than hashed as something the other end never receives. An object\n * member whose value is `undefined` is left out, as it is on the wire.\n */\nexport function canonicalJson(value: unknown): string {\n return serialize(value, \"$\");\n}\n\n/** SHA-256 of the canonical JSON of a request's params, lowercase hex. Runs wherever WebCrypto does. */\nexport async function argsHash(params: unknown): Promise<string> {\n const canonical = canonicalJson(params);\n const subtle = await webCrypto();\n const digest = await subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(canonical),\n );\n let hex = \"\";\n for (const byte of new Uint8Array(digest))\n hex += byte.toString(16).padStart(2, \"0\");\n return hex;\n}\n\n/**\n * WebCrypto: global in browsers and Node 19+; Node 18 has it only on\n * `node:crypto`, imported here by a specifier bundlers leave alone.\n */\nasync function webCrypto(): Promise<SubtleCrypto> {\n const global = globalThis.crypto?.subtle;\n if (global) return global;\n const nodeCrypto = \"node:crypto\";\n try {\n const mod = (await import(/* @vite-ignore */ nodeCrypto)) as {\n webcrypto?: { subtle?: SubtleCrypto };\n };\n if (mod.webcrypto?.subtle) return mod.webcrypto.subtle;\n } catch {\n // Not Node: fall through to the error below.\n }\n throw new Error(\n \"[OUI] argsHash needs WebCrypto (crypto.subtle), which this runtime does not provide\",\n );\n}\n\nfunction refuse(path: string, what: string): never {\n throw new TypeError(`[OUI] ${path} is not I-JSON: ${what}`);\n}\n\nfunction serialize(value: unknown, path: string): string {\n switch (typeof value) {\n case \"string\":\n return quote(value, path);\n case \"number\":\n if (!Number.isFinite(value)) refuse(path, String(value));\n // ECMAScript's Number-to-string is RFC 8785's number form, and prints -0 as 0.\n return JSON.stringify(value);\n case \"boolean\":\n return value ? \"true\" : \"false\";\n case \"object\": {\n if (value === null) return \"null\";\n if (Array.isArray(value)) {\n return `[${value.map((item, i) => serialize(item, `${path}[${i}]`)).join(\",\")}]`;\n }\n const proto = Object.getPrototypeOf(value);\n if (proto !== Object.prototype && proto !== null) {\n refuse(path, `a ${proto?.constructor?.name ?? \"non-plain\"} object`);\n }\n const record = value as Record<string, unknown>;\n // Default string order compares UTF-16 code units, which is RFC 8785's order.\n const keys = Object.keys(record)\n .filter((k) => record[k] !== undefined)\n .sort();\n return `{${keys\n .map(\n (k) =>\n `${quote(k, `${path} key`)}:${serialize(record[k], `${path}.${k}`)}`,\n )\n .join(\",\")}}`;\n }\n default:\n return refuse(path, typeof value);\n }\n}\n\nfunction quote(text: string, path: string): string {\n // I-JSON strings are well-formed Unicode: a lone surrogate has no UTF-8 form.\n for (let i = 0; i < text.length; i++) {\n const unit = text.charCodeAt(i);\n if (unit >= 0xd800 && unit <= 0xdbff) {\n const next = text.charCodeAt(i + 1);\n if (next >= 0xdc00 && next <= 0xdfff) {\n i++;\n continue;\n }\n refuse(path, `a lone surrogate at ${i}`);\n }\n if (unit >= 0xdc00 && unit <= 0xdfff)\n refuse(path, `a lone surrogate at ${i}`);\n }\n return JSON.stringify(text);\n}\n","/**\n * The identity of a set of surfaces, for an answer that need not repeat them\n * (§7.3.4).\n *\n * A client's surfaces are what an agent may do; every result used to carry\n * them all, so each answer weighed what the page's whole manifest weighs —\n * on a studio page with a hundred and fifty actions, about 265 KB for a click.\n * A relay that caps a frame then drops whole answers, and the agent hears\n * nothing. With this hash the agent runtime says which surfaces it holds\n * (`knownSurfaces`), and the client sends its surfaces only when they differ.\n *\n * The hash is of the surfaces' canonical JSON (object keys sorted), so it does\n * not depend on the order a manifest's fields were written in, and is the\n * same wherever it is computed. It is a 64-bit FNV-1a over the JSON's UTF-16\n * code units, kept as two 32-bit halves: not a security measure — the agent\n * runtime is told the surfaces by the same client that hashes them — but\n * collision-resistant enough that two different capability sets of one page\n * never share one.\n */\nimport type { OUISurface, OUISurfaceIndex } from \"./types.js\";\n\n/** The prefix names the algorithm, so a different one is a different hash rather than a false match. */\nconst PREFIX = \"fnv1a64:\";\n\n/** `surfaces`' hash, as a result's `surfacesHash` and a request's `knownSurfaces` carry it. */\nexport function surfacesHash(\n surfaces: readonly OUISurface[] | readonly OUISurfaceIndex[],\n): string {\n return PREFIX + fnv1a64(sortedJson(surfaces));\n}\n\n/**\n * JSON with every object's keys sorted, and what JSON cannot carry dropped as\n * JSON.stringify drops it. Not approval.ts's `canonicalJson`, which refuses\n * such values on purpose (an approval must hash exactly what crosses the\n * wire): a snapshot is taken on every answer, and must never throw on a\n * manifest that carries, say, an `undefined` in an array.\n */\nexport function sortedJson(value: unknown): string {\n return JSON.stringify(sortKeys(value)) ?? \"null\";\n}\n\nfunction sortKeys(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(sortKeys);\n if (value && typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n for (const key of Object.keys(value as Record<string, unknown>).sort()) {\n const member = (value as Record<string, unknown>)[key];\n if (member !== undefined) out[key] = sortKeys(member);\n }\n return out;\n }\n return value;\n}\n\n/**\n * 64-bit FNV-1a (offset 0xcbf29ce484222325, prime 0x100000001b3) in two 32-bit\n * halves, so it runs without BigInt and stays fast on a few hundred KB.\n */\nexport function fnv1a64(text: string): string {\n // The 64-bit offset basis, as high and low 32-bit halves.\n let hi = 0xcbf29ce4;\n let lo = 0x84222325;\n for (let i = 0; i < text.length; i++) {\n lo = (lo ^ text.charCodeAt(i)) >>> 0;\n // Multiply (hi:lo) by the prime 0x00000100_000001b3, keeping 64 bits:\n // lo*0x1b3, and hi*0x1b3 + lo*0x100 carried into the high half.\n const loProduct = lo * 0x1b3;\n const carry = Math.floor(loProduct / 0x100000000);\n const newLo = loProduct >>> 0;\n hi = (Math.imul(hi, 0x1b3) + Math.imul(lo, 0x100) + carry) >>> 0;\n lo = newLo;\n }\n return hex32(hi) + hex32(lo);\n}\n\nfunction hex32(n: number): string {\n return (n >>> 0).toString(16).padStart(8, \"0\");\n}\n","/**\n * An action input that takes a file the person attached (OUI spec §7.3.11,\n * ADR-0252 §2.13).\n *\n * The agent passes an attachment's id. The client resolves it, through its\n * host's file area, to what the input declares it takes, before the action's\n * handler runs:\n *\n * - `file`: a `File`, exactly what the person's own file choice produces;\n * - `text`: the file's text, for an input that takes markup or JSON.\n *\n * Declared on a string schema:\n * `{ type: 'string', format: 'oui-attachment', 'x-oui-attachment': { as: 'file', mediaTypes: ['image/png'] } }`.\n * The request stays small: only the id travels.\n */\nimport type { JSONSchema } from \"./types.js\";\n\n/** The JSON Schema `format` of an input that takes an attachment's id. */\nexport const OUI_ATTACHMENT_FORMAT = \"oui-attachment\";\n\n/** What an attachment input takes once resolved, and which files it accepts. */\nexport interface OUIAttachmentInput {\n as: \"file\" | \"text\";\n /** The media types it accepts; any when absent. A type ending in `/*` accepts the family. */\n mediaTypes?: string[];\n}\n\n/** Whether a string is an attachment id: opaque, 8 to 64 of A–Z, a–z, 0–9, `_` and `-`. */\nexport function isAttachmentId(value: unknown): value is string {\n return typeof value === \"string\" && /^[A-Za-z0-9_-]{8,64}$/.test(value);\n}\n\n/** The same rule as a pattern, for a validator's format. */\nexport const ATTACHMENT_ID_PATTERN = /^[A-Za-z0-9_-]{8,64}$/;\n\n/** The attachment declaration of a schema, when it is an attachment input. */\nexport function attachmentInputOf(\n schema: JSONSchema | undefined,\n): OUIAttachmentInput | null {\n if (!schema || schema.format !== OUI_ATTACHMENT_FORMAT) return null;\n const declared = schema[\"x-oui-attachment\"] as\n Partial<OUIAttachmentInput> | undefined;\n const as = declared?.as === \"text\" ? \"text\" : \"file\";\n const mediaTypes = Array.isArray(declared?.mediaTypes)\n ? declared.mediaTypes.filter((t): t is string => typeof t === \"string\")\n : undefined;\n return { as, ...(mediaTypes?.length ? { mediaTypes } : {}) };\n}\n\n/** Whether a media type is one an attachment input accepts. */\nexport function acceptsMediaType(\n input: OUIAttachmentInput,\n mediaType: string,\n): boolean {\n if (!input.mediaTypes?.length) return true;\n const type = mediaType.split(\";\")[0].trim().toLowerCase();\n return input.mediaTypes.some((accepted) => {\n const a = accepted.toLowerCase();\n return a.endsWith(\"/*\") ? type.startsWith(a.slice(0, -1)) : a === type;\n });\n}\n\n/**\n * Every attachment input of an action's input schema, by where its id sits in\n * the params: a property (`[\"logo\"]`), or each item of a list property\n * (`[\"images\", \"*\"]`). Only the input's own properties and their list items\n * are looked at: a file is an argument of the action, not buried in its data.\n */\nexport function attachmentInputs(\n schema: JSONSchema | undefined,\n): Array<{ path: [string] | [string, \"*\"]; input: OUIAttachmentInput }> {\n const found: Array<{\n path: [string] | [string, \"*\"];\n input: OUIAttachmentInput;\n }> = [];\n for (const [name, property] of Object.entries(schema?.properties ?? {})) {\n const direct = attachmentInputOf(property);\n if (direct) {\n found.push({ path: [name], input: direct });\n continue;\n }\n const item =\n property.type === \"array\" ? attachmentInputOf(property.items) : null;\n if (item) found.push({ path: [name, \"*\"], input: item });\n }\n return found;\n}\n\n/**\n * Where an action's input schema declares an attachment input anywhere other\n * than a property of the input or the items of a list property: inside an\n * object property, a list of lists, `anyOf`/`oneOf`/`allOf`, or anything a\n * schema nests. Such an input is neither checked nor resolved, so an action\n * declaring one is refused (§7.3.11). Each entry is a path in the schema, as\n * `property.sub`, `property[]`, `property.anyOf[0]`.\n */\nexport function misplacedAttachmentInputs(\n schema: JSONSchema | undefined,\n): string[] {\n const misplaced: string[] = [];\n const visit = (node: unknown, path: string, depth: number): void => {\n if (!node || typeof node !== \"object\" || depth > 32) return;\n const s = node as JSONSchema & Record<string, unknown>;\n if (s.format === OUI_ATTACHMENT_FORMAT) misplaced.push(path || \"(input)\");\n const child = (value: unknown, at: string) => visit(value, at, depth + 1);\n for (const [name, sub] of Object.entries(\n (s.properties as Record<string, unknown> | undefined) ?? {},\n ))\n child(sub, path ? `${path}.${name}` : name);\n if (s.items) child(s.items, `${path}[]`);\n for (const key of [\"anyOf\", \"oneOf\", \"allOf\", \"prefixItems\"] as const) {\n const list = s[key];\n if (Array.isArray(list))\n list.forEach((sub, i) => child(sub, `${path}.${key}[${i}]`));\n }\n for (const key of [\n \"additionalProperties\",\n \"not\",\n \"if\",\n \"then\",\n \"else\",\n \"contains\",\n ] as const)\n if (s[key] && typeof s[key] === \"object\") child(s[key], `${path}.${key}`);\n for (const key of [\"patternProperties\", \"$defs\", \"definitions\"] as const) {\n const map = s[key];\n if (map && typeof map === \"object\")\n for (const [name, sub] of Object.entries(\n map as Record<string, unknown>,\n ))\n child(sub, `${path}.${key}.${name}`);\n }\n };\n if (!schema) return misplaced;\n // The input's own properties, and the items of a list property, are where a\n // file may be: look below them, and at everything else the schema holds.\n const { properties, ...rest } = schema as JSONSchema &\n Record<string, unknown>;\n visit({ ...rest, format: undefined }, \"\", 0);\n for (const [name, property] of Object.entries(\n (properties as Record<string, JSONSchema> | undefined) ?? {},\n )) {\n if (attachmentInputOf(property)) {\n const { format: _f, ...below } = property as Record<string, unknown>;\n visit(below, name, 1);\n continue;\n }\n if (property.type === \"array\" && attachmentInputOf(property.items)) {\n const { items, ...list } = property as Record<string, unknown>;\n const { format: _f, ...below } = items as Record<string, unknown>;\n visit(list, name, 1);\n visit(below, `${name}[]`, 2);\n continue;\n }\n visit(property, name, 1);\n }\n return misplaced;\n}\n\n/** Every attachment id an action's params name, with the input that takes it. */\nexport function attachmentIdsIn(\n schema: JSONSchema | undefined,\n params: Record<string, unknown>,\n): Array<{ id: string; property: string; input: OUIAttachmentInput }> {\n const ids: Array<{\n id: string;\n property: string;\n input: OUIAttachmentInput;\n }> = [];\n for (const { path, input } of attachmentInputs(schema)) {\n const value = params[path[0]];\n const values =\n path.length === 2 ? (Array.isArray(value) ? value : []) : [value];\n for (const v of values)\n if (typeof v === \"string\") ids.push({ id: v, property: path[0], input });\n }\n return ids;\n}\n","/**\n * The index form of a surface (§7.3.8): each action as one entry that says what\n * it is and what it takes in outline, in place of its definition.\n *\n * Everything here is derived from the action's own definition, by rule, so two\n * clients with the same definition produce the same entry and the same hash.\n */\nimport { attachmentInputOf } from \"./attachments.js\";\nimport { fnv1a64, sortedJson } from \"./surfaces-hash.js\";\nimport type {\n JSONSchema,\n OUIAction,\n OUIActionIndexEntry,\n OUISurface,\n OUISurfaceIndex,\n} from \"./types.js\";\n\n/** The longest description an index entry carries. */\nexport const INDEX_DESCRIPTION_CHARS = 160;\n/** The longest input line an index entry carries. */\nexport const INDEX_INPUT_CHARS = 120;\n/** How many of an input's properties its line names before \"+N more\". */\nexport const INDEX_INPUT_PROPERTIES = 6;\n/** How many of an enum's values a line shows before it says how many there are. */\nconst INDEX_ENUM_VALUES = 4;\n\n/** The surface id the runtime itself answers (§7.3.10). No surface may be defined with it. */\nexport const OUI_RUNTIME_SURFACE = \"oui\";\n/** `oui.describe`: the full definitions of the actions asked for. */\nexport const OUI_DESCRIBE_ACTION = \"describe\";\n/** `oui.read`: part of an observation's value, by path, a page of a list at a time. */\nexport const OUI_READ_ACTION = \"read\";\n\n/** The bytes `text` takes as UTF-8, which is what a frame's size limit counts. */\nexport function utf8Length(text: string): number {\n let bytes = 0;\n for (let i = 0; i < text.length; i++) {\n const code = text.charCodeAt(i);\n if (code < 0x80) bytes += 1;\n else if (code < 0x800) bytes += 2;\n else if (code >= 0xd800 && code <= 0xdbff) {\n // A surrogate pair is one code point of four bytes.\n bytes += 4;\n i++;\n } else bytes += 3;\n }\n return bytes;\n}\n\n/** The bytes `value` takes as JSON on the wire; 0 for what JSON drops. */\nexport function jsonBytes(value: unknown): number {\n const json = JSON.stringify(value);\n return json === undefined ? 0 : utf8Length(json);\n}\n\n/** `text` cut to `max` characters, ending in \"…\" when it was cut. */\nfunction clip(text: string, max: number): string {\n return text.length <= max ? text : `${text.slice(0, max - 1).trimEnd()}…`;\n}\n\n/** A description's first sentence, on one line, at most `INDEX_DESCRIPTION_CHARS` characters. */\nexport function firstSentence(text: string): string {\n const line = text.replace(/\\s+/g, \" \").trim();\n // A sentence ends at \". \", \"! \" or \"? \": a full stop inside \"0.5\" or \"e.g.\" followed by a letter is not one.\n const end = line.search(/[.!?](?= [A-Z0-9\"'([])/);\n return clip(\n end >= 0 ? line.slice(0, end + 1) : line,\n INDEX_DESCRIPTION_CHARS,\n );\n}\n\nfunction typeOf(schema: JSONSchema): string {\n const t = schema.type;\n return Array.isArray(t) ? t.join(\"|\") : (t ?? \"\");\n}\n\nfunction unitOf(schema: JSONSchema): string {\n const unit = schema[\"x-unit\"];\n return typeof unit === \"string\" && unit ? ` ${unit}` : \"\";\n}\n\n/** The members of a schema's union, when it is one. */\nfunction unionOf(schema: JSONSchema): JSONSchema[] | null {\n const members = schema.oneOf ?? schema.anyOf;\n return members && members.length > 0 ? members : null;\n}\n\n/**\n * The property every member of a union fixes to its own constant, which is\n * what tells the members apart: `effect` in `{ effect: \"glow\", … } | { effect:\n * \"blur\", … }`. Null when the members share no such property.\n */\nexport function discriminatorOf(members: readonly JSONSchema[]): string | null {\n const first = members[0]?.properties;\n if (!first) return null;\n for (const name of Object.keys(first)) {\n const constants = members.map((m) => constantOf(m.properties?.[name]));\n if (\n constants.every((c) => c !== undefined) &&\n new Set(constants).size === members.length\n )\n return name;\n }\n return null;\n}\n\n/** The one value a schema allows, when it allows one. */\nexport function constantOf(\n schema: JSONSchema | undefined,\n): string | number | boolean | undefined {\n if (!schema) return undefined;\n if (\n typeof schema.const === \"string\" ||\n typeof schema.const === \"number\" ||\n typeof schema.const === \"boolean\"\n ) {\n return schema.const;\n }\n return schema.enum?.length === 1 ? schema.enum[0] : undefined;\n}\n\n/** A value's type in a few words: \"number 0–100 px\", \"a|b|c|d|…(12)\", \"list of string\". */\nfunction valueSummary(schema: JSONSchema): string {\n const constant = constantOf(schema);\n if (constant !== undefined && !schema.enum) return JSON.stringify(constant);\n if (schema.enum) {\n const shown = schema.enum.slice(0, INDEX_ENUM_VALUES).map(String).join(\"|\");\n return schema.enum.length > INDEX_ENUM_VALUES\n ? `${shown}|…(${schema.enum.length})`\n : shown;\n }\n const union = unionOf(schema);\n if (union) return `one of ${union.length}`;\n const type = typeOf(schema);\n if (type === \"number\" || type === \"integer\") {\n const { minimum: min, maximum: max } = schema;\n const range =\n min !== undefined && max !== undefined\n ? ` ${min}–${max}`\n : min !== undefined\n ? ` ≥${min}`\n : max !== undefined\n ? ` ≤${max}`\n : \"\";\n return `${type}${range}${unitOf(schema)}`;\n }\n if (type === \"string\") {\n // An attached file's id, which the client turns into the file (ADR-0252 §2.13).\n const file = attachmentInputOf(schema);\n if (file)\n return file.mediaTypes?.length\n ? `file(${file.mediaTypes.join(\"|\")})`\n : \"file\";\n return schema.format ? `string(${schema.format})` : \"string\";\n }\n if (type === \"array\")\n return schema.items ? `list of ${valueSummary(schema.items)}` : \"list\";\n if (type === \"object\") {\n const n = Object.keys(schema.properties ?? {}).length;\n return n > 0 ? `object(${n})` : \"object\";\n }\n return type || \"any\";\n}\n\n/**\n * What an action takes, in one line of at most `INDEX_INPUT_CHARS` characters:\n * - \"none\" for an action that takes nothing;\n * - each property with its type, required ones first, optional ones marked\n * \"?\", the first `INDEX_INPUT_PROPERTIES` of them, then \"+N more\";\n * - \"one of N shapes by <property>\" for a union.\n */\nexport function summarizeInput(schema: JSONSchema | undefined): string {\n if (!schema) return \"none\";\n const union = unionOf(schema);\n if (union) {\n const by = discriminatorOf(union);\n return clip(\n `one of ${union.length} shapes${by ? ` by ${by}` : \"\"}`,\n INDEX_INPUT_CHARS,\n );\n }\n const properties = schema.properties ?? {};\n const names = Object.keys(properties);\n if (names.length === 0)\n return typeOf(schema) && typeOf(schema) !== \"object\"\n ? valueSummary(schema)\n : \"none\";\n const required = new Set(schema.required ?? []);\n const ordered = [\n ...names.filter((n) => required.has(n)),\n ...names.filter((n) => !required.has(n)),\n ];\n const shown = ordered.slice(0, INDEX_INPUT_PROPERTIES);\n const more = ordered.length - shown.length;\n const parts = shown.map(\n (n) => `${n}${required.has(n) ? \"\" : \"?\"}: ${valueSummary(properties[n])}`,\n );\n if (more > 0) parts.push(`+${more} more`);\n return clip(parts.join(\", \"), INDEX_INPUT_CHARS);\n}\n\n/** The longest lead-in before a quoted title that is still a lead-in (\"Turn on or off\", \"Choose the face of\"). */\nconst TITLE_LEAD_IN_CHARS = 32;\n\n/**\n * A description without the opening that only repeats the action's title.\n *\n * An entry carries the title beside the description, and descriptions are\n * commonly written to stand alone: `Add artboard: Adds an artboard…`, or, for\n * a control, `Press \"Save\": Saves the project`. In an index that names the\n * title twice for every action, and an index is hundreds of actions. So an\n * opening of the title followed by \": \", or of a short lead-in, the title in\n * double quotes and \": \", is left out: what the entry keeps is what the title\n * does not already say. A description that does not open that way is kept as\n * it is, and one that is only its title is kept too.\n */\nexport function withoutTitleLeadIn(\n description: string,\n title: string | undefined,\n): string {\n const line = description.replace(/\\s+/g, \" \").trim();\n if (!title) return line;\n const name = title.replace(/\\s+/g, \" \").trim();\n if (!name) return line;\n let rest: string | undefined;\n if (line.startsWith(`${name}: `)) rest = line.slice(name.length + 2);\n else {\n const quoted = `\"${name}\": `;\n const at = line.indexOf(quoted);\n // A lead-in is a few words with no sentence in them: \"Press\", \"Type into\", \"Turn on or off\".\n if (\n at >= 0 &&\n at <= TITLE_LEAD_IN_CHARS &&\n !/[.:!?\"]/.test(line.slice(0, at))\n )\n rest = line.slice(at + quoted.length);\n }\n const kept = rest?.trim();\n return kept ? kept : line;\n}\n\n/** The hex digits an entry's `definitionHash` has: 32 bits. */\nexport const DEFINITION_HASH_HEX = 8;\n\n/**\n * The hash of an action's definition, as an index entry's `definitionHash`\n * carries it: the first 32 bits of the 64-bit FNV-1a of its sorted-key JSON.\n *\n * It answers one question, for one action: has this action's definition\n * changed since it was fetched? It is only ever compared with the same\n * action's earlier hash, so 32 bits are enough (a change goes unseen once in\n * 2^32, and costs one stale definition until the next change), and an index of\n * hundreds of actions carries half the digits. The hash of a whole page\n * (`surfacesHash`) is compared across everything on it, and stays 64 bits.\n */\nexport function definitionHash(action: OUIAction): string {\n return fnv1a64(sortedJson(action)).slice(0, DEFINITION_HASH_HEX);\n}\n\n/** An action's index entry (§7.3.8). */\nexport function indexEntry(action: OUIAction): OUIActionIndexEntry {\n return {\n id: action.id,\n ...(action.title ? { title: action.title } : {}),\n description: firstSentence(\n withoutTitleLeadIn(action.description, action.title),\n ),\n ...(action.effect !== undefined ? { effect: action.effect } : {}),\n ...(action.confirm ? { confirm: true } : {}),\n ...(action.async ? { async: true } : {}),\n ...(action.estimatedDuration\n ? { estimatedDuration: action.estimatedDuration }\n : {}),\n ...(action.polling?.maxDurationMs !== undefined\n ? { maxDurationMs: action.polling.maxDurationMs }\n : {}),\n input: summarizeInput(action.input),\n definitionHash: definitionHash(action),\n };\n}\n\n/** A surface in index form (§7.3.8). */\nexport function surfaceIndex(surface: OUISurface): OUISurfaceIndex {\n return {\n id: surface.id,\n name: surface.name,\n description: surface.description,\n ...(surface.version !== undefined ? { version: surface.version } : {}),\n ...(surface.observations ? { observations: surface.observations } : {}),\n index: surface.actions.map(indexEntry),\n };\n}\n","/**\n * Fitting what a client sends to a byte budget (§7.3.9).\n *\n * A frame larger than its receiver accepts is refused whole, and the agent\n * then knows nothing of the page. So the client shortens what it sends before\n * it sends it: the longest lists first, then long texts, then whole values,\n * and it says where it cut, so the rest can be read (`oui.read`, §7.3.10).\n *\n * The cuts are made by rule, in a fixed order, so the same state under the\n * same budget is always shortened the same way.\n */\nimport { jsonBytes } from \"./index-form.js\";\nimport type { OUIFitCut, OUIObservationSnapshot } from \"./types.js\";\n\n/** Rows a list keeps at each step of fitting, until the whole fits. */\nexport const FIT_LIST_STEPS = [200, 50, 20, 5, 0] as const;\n/** Characters a text keeps once lists alone did not make the whole fit. */\nexport const FIT_TEXT_CHARS = 2_000;\n\n/** One step into a JSON Pointer (RFC 6901). */\nexport function pointerStep(pointer: string, key: string | number): string {\n return `${pointer}/${String(key).replace(/~/g, \"~0\").replace(/\\//g, \"~1\")}`;\n}\n\n/** The steps of a JSON Pointer; \"\" is no steps. Throws on a pointer that does not start with \"/\". */\nexport function pointerSteps(pointer: string): string[] {\n if (pointer === \"\") return [];\n if (!pointer.startsWith(\"/\"))\n throw new Error(\n `\"${pointer}\" is not a JSON Pointer: it must be \"\" or start with \"/\"`,\n );\n return pointer\n .slice(1)\n .split(\"/\")\n .map((s) => s.replace(/~1/g, \"/\").replace(/~0/g, \"~\"));\n}\n\n/** The value a pointer names inside `value`, or `undefined` when nothing is there. */\nexport function atPointer(value: unknown, pointer: string): unknown {\n let at: unknown = value;\n for (const step of pointerSteps(pointer)) {\n if (Array.isArray(at)) {\n at = /^(0|[1-9]\\d*)$/.test(step) ? at[Number(step)] : undefined;\n } else if (at && typeof at === \"object\") {\n at = Object.prototype.hasOwnProperty.call(at, step)\n ? (at as Record<string, unknown>)[step]\n : undefined;\n } else return undefined;\n if (at === undefined) return undefined;\n }\n return at;\n}\n\ninterface Slot {\n /** The object or array holding the value. */\n holder: Record<string, unknown> | unknown[];\n key: string | number;\n surface: string;\n observation: string;\n path: string;\n}\n\n/** Every array and string inside the observations, each with where it sits. */\nfunction slots(\n observations: OUIObservationSnapshot,\n want: \"list\" | \"text\",\n): Slot[] {\n const found: Slot[] = [];\n const walk = (\n holder: Slot[\"holder\"],\n key: string | number,\n surface: string,\n observation: string,\n path: string,\n ) => {\n const value = (holder as Record<string | number, unknown>)[key];\n if (Array.isArray(value)) {\n if (want === \"list\")\n found.push({ holder, key, surface, observation, path });\n value.forEach((_, i) =>\n walk(value, i, surface, observation, pointerStep(path, i)),\n );\n } else if (value && typeof value === \"object\") {\n for (const k of Object.keys(value))\n walk(\n value as Record<string, unknown>,\n k,\n surface,\n observation,\n pointerStep(path, k),\n );\n } else if (typeof value === \"string\" && want === \"text\") {\n found.push({ holder, key, surface, observation, path });\n }\n };\n for (const surface of Object.keys(observations)) {\n for (const observation of Object.keys(observations[surface])) {\n walk(observations[surface], observation, surface, observation, \"\");\n }\n }\n return found;\n}\n\n/**\n * `observations` within `budget` bytes of JSON, and where they were cut.\n * Returned as they are when they already fit; otherwise a copy is shortened:\n * 1. every list longer than a step of `FIT_LIST_STEPS` is cut to it, a step at\n * a time, until the whole fits;\n * 2. then every text longer than `FIT_TEXT_CHARS` is cut to that;\n * 3. then whole observation values are left out, the largest first.\n */\nexport function fitObservations(\n observations: OUIObservationSnapshot,\n budget: number,\n): { observations: OUIObservationSnapshot; cuts: OUIFitCut[] } {\n if (jsonBytes(observations) <= budget) return { observations, cuts: [] };\n\n const fitted = JSON.parse(\n JSON.stringify(observations),\n ) as OUIObservationSnapshot;\n // One cut per place: a list cut twice is reported once, with its first length.\n const cuts = new Map<string, OUIFitCut>();\n const note = (\n slot: Slot,\n kind: OUIFitCut[\"kind\"],\n total: number,\n kept: number,\n ) => {\n const id = `${slot.surface}\\u0000${slot.observation}\\u0000${slot.path}`;\n const prior = cuts.get(id);\n cuts.set(id, {\n surface: slot.surface,\n observation: slot.observation,\n path: slot.path,\n kind,\n total: prior ? prior.total : total,\n kept,\n });\n };\n const fits = () => jsonBytes(fitted) <= budget;\n\n for (const rows of FIT_LIST_STEPS) {\n for (const slot of slots(fitted, \"list\")) {\n const list = (slot.holder as Record<string | number, unknown>)[\n slot.key\n ] as unknown[];\n if (list.length <= rows) continue;\n note(slot, \"list\", list.length, rows);\n list.length = rows;\n }\n // A cut inside a row that an outer list then dropped is no longer there to read.\n for (const [id, cut] of cuts) {\n if (\n cut.kind === \"list\" &&\n atPointer(fitted[cut.surface]?.[cut.observation], cut.path) ===\n undefined\n )\n cuts.delete(id);\n }\n if (fits()) return { observations: fitted, cuts: [...cuts.values()] };\n }\n\n for (const slot of slots(fitted, \"text\")) {\n const text = (slot.holder as Record<string | number, unknown>)[\n slot.key\n ] as string;\n if (text.length <= FIT_TEXT_CHARS) continue;\n note(slot, \"text\", text.length, FIT_TEXT_CHARS);\n (slot.holder as Record<string | number, unknown>)[slot.key] = text.slice(\n 0,\n FIT_TEXT_CHARS,\n );\n }\n if (fits()) return { observations: fitted, cuts: [...cuts.values()] };\n\n const values = Object.keys(fitted)\n .flatMap((surface) =>\n Object.keys(fitted[surface]).map((observation) => ({\n surface,\n observation,\n bytes: jsonBytes(fitted[surface][observation]),\n })),\n )\n .sort(\n (a, b) =>\n b.bytes - a.bytes ||\n a.surface.localeCompare(b.surface) ||\n a.observation.localeCompare(b.observation),\n );\n for (const { surface, observation, bytes } of values) {\n if (fits()) break;\n for (const [id, cut] of cuts) {\n if (cut.surface === surface && cut.observation === observation)\n cuts.delete(id);\n }\n fitted[surface][observation] = null;\n cuts.set(`${surface}\\u0000${observation}\\u0000`, {\n surface,\n observation,\n path: \"\",\n kind: \"value\",\n total: bytes,\n kept: 0,\n });\n }\n return { observations: fitted, cuts: [...cuts.values()] };\n}\n"]}