@opengeni/react 1.4.2 → 1.4.5-canary.37458084490001

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 (240) hide show
  1. package/README.md +17 -6
  2. package/dist/artifacts.d.ts +1 -0
  3. package/dist/artifacts.js +22 -15
  4. package/dist/artifacts.js.map +1 -1
  5. package/dist/{browser-viewer-WGJ43YGI.js → browser-viewer-CV23VIHB.js} +8 -6
  6. package/dist/chunk-3ZC6QPOM.js +174 -0
  7. package/dist/chunk-3ZC6QPOM.js.map +1 -0
  8. package/dist/{chunk-YVFRBXST.js → chunk-4BCVCJSU.js} +2 -2
  9. package/dist/{chunk-JHTIMBOL.js → chunk-5JSUNNQN.js} +26 -4
  10. package/dist/{chunk-JHTIMBOL.js.map → chunk-5JSUNNQN.js.map} +1 -1
  11. package/dist/{chunk-MDIXFKA3.js → chunk-6FOTSVWU.js} +303 -109
  12. package/dist/chunk-6FOTSVWU.js.map +1 -0
  13. package/dist/{chunk-IUHHPMAX.js → chunk-7RRBX5EM.js} +14 -85
  14. package/dist/chunk-7RRBX5EM.js.map +1 -0
  15. package/dist/{chunk-L2J3PU7A.js → chunk-7ZB7I3KP.js} +24 -98
  16. package/dist/chunk-7ZB7I3KP.js.map +1 -0
  17. package/dist/{chunk-LVS3MH5T.js → chunk-ATIRUHBZ.js} +128 -10
  18. package/dist/chunk-ATIRUHBZ.js.map +1 -0
  19. package/dist/chunk-BOFEQC6K.js +162 -0
  20. package/dist/chunk-BOFEQC6K.js.map +1 -0
  21. package/dist/{chunk-VCSERYXH.js → chunk-CESBPQP5.js} +309 -162
  22. package/dist/chunk-CESBPQP5.js.map +1 -0
  23. package/dist/{chunk-IYQCWGU5.js → chunk-GHJU7XG7.js} +35 -62
  24. package/dist/chunk-GHJU7XG7.js.map +1 -0
  25. package/dist/{chunk-G6YRCIYJ.js → chunk-HNVWMDNN.js} +55 -60
  26. package/dist/chunk-HNVWMDNN.js.map +1 -0
  27. package/dist/{chunk-PHBFJCEU.js → chunk-I5EGRXXG.js} +110 -7
  28. package/dist/chunk-I5EGRXXG.js.map +1 -0
  29. package/dist/{chunk-PBCZL4JP.js → chunk-INIZSNXT.js} +2 -2
  30. package/dist/{chunk-XS67YG5R.js → chunk-IX3K4THH.js} +24 -3
  31. package/dist/chunk-IX3K4THH.js.map +1 -0
  32. package/dist/chunk-IZV5FTJC.js +55 -0
  33. package/dist/chunk-IZV5FTJC.js.map +1 -0
  34. package/dist/chunk-JDJJMBB3.js +1883 -0
  35. package/dist/chunk-JDJJMBB3.js.map +1 -0
  36. package/dist/{chunk-C5BF4L26.js → chunk-KHF2VRXF.js} +7 -7
  37. package/dist/{chunk-QMMCJGFI.js → chunk-L5OKM2VX.js} +2 -2
  38. package/dist/chunk-LHF6BVM4.js +83 -0
  39. package/dist/chunk-LHF6BVM4.js.map +1 -0
  40. package/dist/chunk-N7S72EXK.js +25 -0
  41. package/dist/chunk-N7S72EXK.js.map +1 -0
  42. package/dist/{chunk-CVYCLFMH.js → chunk-PEHTX3V7.js} +19 -1
  43. package/dist/chunk-PEHTX3V7.js.map +1 -0
  44. package/dist/chunk-R5R5RQQD.js +51 -0
  45. package/dist/chunk-R5R5RQQD.js.map +1 -0
  46. package/dist/chunk-RI42H5IU.js +326 -0
  47. package/dist/chunk-RI42H5IU.js.map +1 -0
  48. package/dist/{chunk-JH7V627O.js → chunk-SHLZMAJN.js} +2 -11
  49. package/dist/chunk-SHLZMAJN.js.map +1 -0
  50. package/dist/{chunk-CREMJMVN.js → chunk-TZQSHCZN.js} +692 -1996
  51. package/dist/chunk-TZQSHCZN.js.map +1 -0
  52. package/dist/chunk-ZIB4H5LN.js +101 -0
  53. package/dist/chunk-ZIB4H5LN.js.map +1 -0
  54. package/dist/client.d.ts +9 -3
  55. package/dist/clipboard.js +1 -1
  56. package/dist/components/browser-viewer.d.ts +6 -0
  57. package/dist/components/composer.d.ts +3 -69
  58. package/dist/components/human-input-form.d.ts +3 -32
  59. package/dist/components/markdown.d.ts +8 -0
  60. package/dist/components/model-policy-picker.d.ts +4 -37
  61. package/dist/components/opper-mark.d.ts +7 -0
  62. package/dist/components/provider-recovery-notice.d.ts +15 -0
  63. package/dist/components/remark-soft-line-breaks.d.ts +38 -0
  64. package/dist/components/sandbox-workspace.d.ts +13 -0
  65. package/dist/components/session-chrome.d.ts +5 -3
  66. package/dist/components/session-conversation.d.ts +15 -3
  67. package/dist/composer-messages.d.ts +74 -0
  68. package/dist/composer-messages.js +9 -0
  69. package/dist/composer.js +15 -10
  70. package/dist/{computer-viewer-46UIN7F3.js → computer-viewer-K4CKYRX6.js} +4 -4
  71. package/dist/connect-setup.d.ts +2 -0
  72. package/dist/connect.d.ts +1 -1
  73. package/dist/connect.js +21 -6
  74. package/dist/connect.js.map +1 -1
  75. package/dist/{embedded-voice-NIL4RDX3.js → embedded-voice-3ZFWWJ6O.js} +6 -4
  76. package/dist/{embedded-voice-NIL4RDX3.js.map → embedded-voice-3ZFWWJ6O.js.map} +1 -1
  77. package/dist/hooks/shared-machines-list.d.ts +4 -0
  78. package/dist/hooks/use-client-config-flags.d.ts +6 -0
  79. package/dist/hooks/use-computer-session.d.ts +2 -0
  80. package/dist/hooks/use-goal.d.ts +2 -1
  81. package/dist/human-input-model.d.ts +40 -0
  82. package/dist/index.d.ts +4 -1
  83. package/dist/index.js +116 -73
  84. package/dist/index.js.map +1 -1
  85. package/dist/interaction.js +5 -5
  86. package/dist/{latest-question-2POFPYNB.js → latest-question-SWC6QEVN.js} +3 -3
  87. package/dist/lib/clipboard.d.ts +7 -0
  88. package/dist/lib/provider-recovery.d.ts +49 -0
  89. package/dist/machines.js +2 -2
  90. package/dist/model-mark-paths.d.ts +34 -0
  91. package/dist/model-mark-paths.js +16 -0
  92. package/dist/model-picker-model.d.ts +111 -0
  93. package/dist/model-picker-model.js +25 -0
  94. package/dist/model-picker-model.js.map +1 -0
  95. package/dist/{model-policy-picker-menu-WRNSRFQC.js → model-policy-picker-menu-NM4RPTY6.js} +6 -4
  96. package/dist/model-policy-picker-menu-NM4RPTY6.js.map +1 -0
  97. package/dist/model-policy.d.ts +10 -0
  98. package/dist/model-policy.js +5 -1
  99. package/dist/organization-model.d.ts +32 -0
  100. package/dist/organization-model.js +65 -0
  101. package/dist/organization-model.js.map +1 -0
  102. package/dist/{platform-activity-row-PJJVATTZ.js → platform-activity-row-NJ47YBXW.js} +7 -84
  103. package/dist/platform-activity-row-NJ47YBXW.js.map +1 -0
  104. package/dist/queue-presentation-model.d.ts +72 -0
  105. package/dist/queue-presentation-model.js +38 -0
  106. package/dist/queue-presentation-model.js.map +1 -0
  107. package/dist/{queue-surface-implementation-67FS7FUI.js → queue-surface-implementation-YPJFQ3O6.js} +24 -252
  108. package/dist/queue-surface-implementation-YPJFQ3O6.js.map +1 -0
  109. package/dist/realtime.js +5 -3
  110. package/dist/{sandbox-files-34CJJNOY.js → sandbox-files-RCVCMXG7.js} +5 -5
  111. package/dist/sandbox-files-RCVCMXG7.js.map +1 -0
  112. package/dist/sandbox-label-model.d.ts +23 -0
  113. package/dist/sandbox-label-model.js +28 -0
  114. package/dist/sandbox-label-model.js.map +1 -0
  115. package/dist/session-attention-model.d.ts +8 -0
  116. package/dist/session-attention-model.js +46 -0
  117. package/dist/session-attention-model.js.map +1 -0
  118. package/dist/session-feedback-model.d.ts +20 -0
  119. package/dist/session-feedback-model.js +56 -0
  120. package/dist/session-feedback-model.js.map +1 -0
  121. package/dist/session-list-model.d.ts +96 -0
  122. package/dist/session-list-model.js +219 -0
  123. package/dist/session-list-model.js.map +1 -0
  124. package/dist/session-status-model.d.ts +19 -0
  125. package/dist/session-ui.js +26 -17
  126. package/dist/session-ui.js.map +1 -1
  127. package/dist/session.js +8 -6
  128. package/dist/testing/session-scenarios.d.ts +10 -0
  129. package/dist/testing/session-scenarios.js +303 -0
  130. package/dist/testing/session-scenarios.js.map +1 -0
  131. package/dist/timeline/genie-copy.d.ts +3 -0
  132. package/dist/timeline/genie-loading.d.ts +11 -0
  133. package/dist/timeline/index.d.ts +1 -1
  134. package/dist/timeline/notice-presentation.d.ts +7 -0
  135. package/dist/timeline/patch-apply-command.d.ts +18 -0
  136. package/dist/timeline/platform-activity-presentation.d.ts +7 -0
  137. package/dist/timeline/presented-image.d.ts +6 -1
  138. package/dist/timeline/question-nav-model.d.ts +23 -0
  139. package/dist/timeline/registry.d.ts +10 -1
  140. package/dist/timeline/retained-loaders.d.ts +1 -1
  141. package/dist/timeline/tool-presentation.d.ts +172 -0
  142. package/dist/timeline/turn-summary-model.d.ts +90 -0
  143. package/dist/timeline/turn-summary.d.ts +4 -74
  144. package/dist/timeline/work-presentation.d.ts +42 -0
  145. package/dist/timeline-model.d.ts +24 -0
  146. package/dist/timeline-model.js +152 -0
  147. package/dist/timeline-model.js.map +1 -0
  148. package/package.json +47 -3
  149. package/src/artifacts.ts +1 -0
  150. package/src/client.ts +9 -3
  151. package/src/components/browser-viewer.tsx +23 -2
  152. package/src/components/claude-mark.tsx +2 -1
  153. package/src/components/composer.tsx +4 -144
  154. package/src/components/computer-viewer.tsx +139 -30
  155. package/src/components/grok-mark.tsx +2 -1
  156. package/src/components/human-input-form.tsx +13 -124
  157. package/src/components/markdown.tsx +19 -1
  158. package/src/components/message-timeline.tsx +45 -99
  159. package/src/components/model-mark.tsx +2 -1
  160. package/src/components/model-policy-picker-menu.tsx +30 -85
  161. package/src/components/model-policy-picker.tsx +15 -148
  162. package/src/components/opper-mark.tsx +18 -0
  163. package/src/components/provider-recovery-notice.tsx +41 -0
  164. package/src/components/queue-surface-implementation.tsx +20 -349
  165. package/src/components/remark-soft-line-breaks.ts +166 -0
  166. package/src/components/sandbox-workspace.tsx +17 -1
  167. package/src/components/session-chrome.tsx +114 -99
  168. package/src/components/session-conversation.tsx +55 -6
  169. package/src/components/session-list.tsx +1 -1
  170. package/src/components/session-status.tsx +17 -16
  171. package/src/composer-messages.ts +150 -0
  172. package/src/connect-setup.tsx +45 -11
  173. package/src/connect.ts +1 -1
  174. package/src/hooks/shared-machines-list.ts +34 -1
  175. package/src/hooks/use-browser-session.ts +445 -168
  176. package/src/hooks/use-client-config-flags.ts +8 -0
  177. package/src/hooks/use-computer-session.ts +334 -98
  178. package/src/hooks/use-goal.ts +66 -10
  179. package/src/human-input-model.ts +147 -0
  180. package/src/index.ts +16 -0
  181. package/src/lib/clipboard.ts +29 -0
  182. package/src/lib/format.ts +7 -0
  183. package/src/lib/provider-recovery.ts +202 -0
  184. package/src/model-mark-paths.ts +53 -0
  185. package/src/model-picker-model.ts +330 -0
  186. package/src/model-policy.ts +43 -2
  187. package/src/organization-model.ts +118 -0
  188. package/src/queue-presentation-model.ts +464 -0
  189. package/src/sandbox-label-model.ts +41 -0
  190. package/src/session-attention-model.ts +59 -0
  191. package/src/session-feedback-model.ts +95 -0
  192. package/src/session-list-model.ts +327 -0
  193. package/src/session-status-model.ts +62 -0
  194. package/src/testing/session-scenarios.ts +326 -0
  195. package/src/timeline/activity-rail.tsx +5 -17
  196. package/src/timeline/genie-copy.ts +19 -0
  197. package/src/timeline/genie-loading.tsx +13 -18
  198. package/src/timeline/index.ts +1 -0
  199. package/src/timeline/notice-presentation.ts +22 -0
  200. package/src/timeline/patch-apply-command.tsx +135 -0
  201. package/src/timeline/platform-activity-presentation.ts +122 -0
  202. package/src/timeline/platform-activity-row.tsx +6 -96
  203. package/src/timeline/presented-image.ts +16 -2
  204. package/src/timeline/question-nav-model.ts +28 -0
  205. package/src/timeline/registry.ts +11 -1
  206. package/src/timeline/retained-loaders.ts +9 -4
  207. package/src/timeline/rolling-activity.tsx +7 -19
  208. package/src/timeline/tool-presentation.ts +1316 -0
  209. package/src/timeline/tool-renderers.tsx +226 -1025
  210. package/src/timeline/turn-summary-model.ts +338 -0
  211. package/src/timeline/turn-summary.tsx +21 -326
  212. package/src/timeline/work-presentation.ts +139 -0
  213. package/src/timeline-model.ts +108 -0
  214. package/styles/compiled.css +8 -0
  215. package/styles/connect.css +4 -0
  216. package/dist/chunk-CREMJMVN.js.map +0 -1
  217. package/dist/chunk-CVYCLFMH.js.map +0 -1
  218. package/dist/chunk-G6YRCIYJ.js.map +0 -1
  219. package/dist/chunk-HXYOSSQO.js +0 -117
  220. package/dist/chunk-HXYOSSQO.js.map +0 -1
  221. package/dist/chunk-IUHHPMAX.js.map +0 -1
  222. package/dist/chunk-IYQCWGU5.js.map +0 -1
  223. package/dist/chunk-JH7V627O.js.map +0 -1
  224. package/dist/chunk-L2J3PU7A.js.map +0 -1
  225. package/dist/chunk-LVS3MH5T.js.map +0 -1
  226. package/dist/chunk-MDIXFKA3.js.map +0 -1
  227. package/dist/chunk-PHBFJCEU.js.map +0 -1
  228. package/dist/chunk-VCSERYXH.js.map +0 -1
  229. package/dist/chunk-XS67YG5R.js.map +0 -1
  230. package/dist/platform-activity-row-PJJVATTZ.js.map +0 -1
  231. package/dist/queue-surface-implementation-67FS7FUI.js.map +0 -1
  232. /package/dist/{browser-viewer-WGJ43YGI.js.map → browser-viewer-CV23VIHB.js.map} +0 -0
  233. /package/dist/{chunk-YVFRBXST.js.map → chunk-4BCVCJSU.js.map} +0 -0
  234. /package/dist/{chunk-PBCZL4JP.js.map → chunk-INIZSNXT.js.map} +0 -0
  235. /package/dist/{chunk-C5BF4L26.js.map → chunk-KHF2VRXF.js.map} +0 -0
  236. /package/dist/{chunk-QMMCJGFI.js.map → chunk-L5OKM2VX.js.map} +0 -0
  237. /package/dist/{computer-viewer-46UIN7F3.js.map → composer-messages.js.map} +0 -0
  238. /package/dist/{model-policy-picker-menu-WRNSRFQC.js.map → computer-viewer-K4CKYRX6.js.map} +0 -0
  239. /package/dist/{latest-question-2POFPYNB.js.map → latest-question-SWC6QEVN.js.map} +0 -0
  240. /package/dist/{sandbox-files-34CJJNOY.js.map → model-mark-paths.js.map} +0 -0
@@ -0,0 +1,28 @@
1
+ "use client";
2
+
3
+ // src/sandbox-label-model.ts
4
+ var CLOUD_SANDBOX_LABEL = "Cloud sandbox";
5
+ var NO_SANDBOX_LABEL = "No sandbox";
6
+ var LOCAL_SANDBOX_LABEL = "Local sandbox";
7
+ function sessionSandboxLabel(backend) {
8
+ if (backend === "none") return NO_SANDBOX_LABEL;
9
+ if (backend === "local") return "this computer";
10
+ if (backend === "docker") return LOCAL_SANDBOX_LABEL;
11
+ return CLOUD_SANDBOX_LABEL;
12
+ }
13
+ function machineDisplayName(machine) {
14
+ return machine.isSessionGroup ? sessionSandboxLabel(machine.kind) : machine.name;
15
+ }
16
+ function sessionComputeLabel(machines) {
17
+ const active = machines.find((machine) => machine.active);
18
+ return active ? machineDisplayName(active) : CLOUD_SANDBOX_LABEL;
19
+ }
20
+ export {
21
+ CLOUD_SANDBOX_LABEL,
22
+ LOCAL_SANDBOX_LABEL,
23
+ NO_SANDBOX_LABEL,
24
+ machineDisplayName,
25
+ sessionComputeLabel,
26
+ sessionSandboxLabel
27
+ };
28
+ //# sourceMappingURL=sandbox-label-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sandbox-label-model.ts"],"sourcesContent":["/**\n * User-facing names for where a session's commands run, shared by the web\n * sandbox switcher and every timeline that labels command rows (\"on Cloud\n * sandbox · …\"). No DOM, no React.\n */\nimport type { SandboxBackend } from \"@opengeni/sdk\";\nimport type { MachineView } from \"./types/machines\";\n\nexport const CLOUD_SANDBOX_LABEL = \"Cloud sandbox\";\nexport const NO_SANDBOX_LABEL = \"No sandbox\";\nexport const LOCAL_SANDBOX_LABEL = \"Local sandbox\";\n\n/**\n * User-facing name for a session's own managed box. Hosting vendors (Modal,\n * Daytona, ...) are deployment detail, not something a user chose, so hosted\n * providers read as the neutral \"Cloud sandbox\" and the local-dev Docker box as\n * \"Local sandbox\". The local backend runs directly on the host, so it keeps the\n * honest \"this computer\" instead of implying isolation. Connected Machines keep\n * their own names.\n */\nexport function sessionSandboxLabel(backend: SandboxBackend | string): string {\n if (backend === \"none\") return NO_SANDBOX_LABEL;\n if (backend === \"local\") return \"this computer\";\n if (backend === \"docker\") return LOCAL_SANDBOX_LABEL;\n return CLOUD_SANDBOX_LABEL;\n}\n\n/** Display name for a fleet row: the session's own box never shows its vendor. */\nexport function machineDisplayName(\n machine: Pick<MachineView, \"isSessionGroup\" | \"kind\" | \"name\">,\n): string {\n return machine.isSessionGroup ? sessionSandboxLabel(machine.kind) : machine.name;\n}\n\n/** The compute label a session timeline shows: the active machine, else the cloud box. */\nexport function sessionComputeLabel(\n machines: readonly Pick<MachineView, \"active\" | \"isSessionGroup\" | \"kind\" | \"name\">[],\n): string {\n const active = machines.find((machine) => machine.active);\n return active ? machineDisplayName(active) : CLOUD_SANDBOX_LABEL;\n}\n"],"mappings":";;;AAQO,IAAM,sBAAsB;AAC5B,IAAM,mBAAmB;AACzB,IAAM,sBAAsB;AAU5B,SAAS,oBAAoB,SAA0C;AAC5E,MAAI,YAAY,OAAQ,QAAO;AAC/B,MAAI,YAAY,QAAS,QAAO;AAChC,MAAI,YAAY,SAAU,QAAO;AACjC,SAAO;AACT;AAGO,SAAS,mBACd,SACQ;AACR,SAAO,QAAQ,iBAAiB,oBAAoB,QAAQ,IAAI,IAAI,QAAQ;AAC9E;AAGO,SAAS,oBACd,UACQ;AACR,QAAM,SAAS,SAAS,KAAK,CAAC,YAAY,QAAQ,MAAM;AACxD,SAAO,SAAS,mBAAmB,MAAM,IAAI;AAC/C;","names":[]}
@@ -0,0 +1,8 @@
1
+ import type { SessionEvent } from "@opengeni/sdk";
2
+ export declare const SESSION_ATTENTION_EVENT_TYPES: ReadonlySet<string>;
3
+ /**
4
+ * The latest delivered attention boundary, independent of raw token activity.
5
+ * A foreground reader acknowledges through this sequence, so streaming flushes
6
+ * never cause a personal-state write and later activity stays unread.
7
+ */
8
+ export declare function sessionAttentionReadThroughSequence(events: readonly SessionEvent[]): number;
@@ -0,0 +1,46 @@
1
+ "use client";
2
+
3
+ // src/session-attention-model.ts
4
+ var SESSION_ATTENTION_EVENT_TYPES = /* @__PURE__ */ new Set([
5
+ "agent.message.completed",
6
+ "turn.completed",
7
+ "turn.failed",
8
+ "session.requiresAction",
9
+ "session.humanInput.requested",
10
+ "tool.auth_needed",
11
+ "credential.auth_needed",
12
+ "goal.completed",
13
+ "goal.paused",
14
+ "goal.progress",
15
+ "goal.rewrite.proposed",
16
+ "rig.setup.failed",
17
+ "sandbox.operation.failed",
18
+ "sandbox.box.lost",
19
+ "workspace.revision.degraded",
20
+ "machine.op.failed",
21
+ "machine.link.lost",
22
+ "session.event.envelope_omitted"
23
+ ]);
24
+ function sessionAttentionReadThroughSequence(events) {
25
+ for (let index = events.length - 1; index >= 0; index -= 1) {
26
+ const event = events[index];
27
+ if (!SESSION_ATTENTION_EVENT_TYPES.has(event.type) || event.duplicateOfEventId || event.turnAssociation != null && event.turnAssociation !== "current")
28
+ continue;
29
+ const payload = event.payload && typeof event.payload === "object" ? event.payload : {};
30
+ if (event.type === "agent.message.completed" && (payload.phase === "commentary" || payload.text == null || payload.text === ""))
31
+ continue;
32
+ if (event.type === "turn.completed") {
33
+ if (Object.hasOwn(payload, "maintenance") || Object.hasOwn(payload, "segmentLimit")) continue;
34
+ const output = payload.output ?? payload.result;
35
+ if ((output == null || output === "") && (payload.reply == null || payload.reply === ""))
36
+ continue;
37
+ }
38
+ return event.sequence;
39
+ }
40
+ return 0;
41
+ }
42
+ export {
43
+ SESSION_ATTENTION_EVENT_TYPES,
44
+ sessionAttentionReadThroughSequence
45
+ };
46
+ //# sourceMappingURL=session-attention-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/session-attention-model.ts"],"sourcesContent":["import type { SessionEvent } from \"@opengeni/sdk\";\n\n// Keep this client scheduling predicate aligned with the meaningful-attention\n// predicate in packages/db/src/session-meaningful-events.ts. The server remains\n// authoritative; this only avoids personal-state writes for streaming activity.\nexport const SESSION_ATTENTION_EVENT_TYPES: ReadonlySet<string> = new Set([\n \"agent.message.completed\",\n \"turn.completed\",\n \"turn.failed\",\n \"session.requiresAction\",\n \"session.humanInput.requested\",\n \"tool.auth_needed\",\n \"credential.auth_needed\",\n \"goal.completed\",\n \"goal.paused\",\n \"goal.progress\",\n \"goal.rewrite.proposed\",\n \"rig.setup.failed\",\n \"sandbox.operation.failed\",\n \"sandbox.box.lost\",\n \"workspace.revision.degraded\",\n \"machine.op.failed\",\n \"machine.link.lost\",\n \"session.event.envelope_omitted\",\n]);\n\n/**\n * The latest delivered attention boundary, independent of raw token activity.\n * A foreground reader acknowledges through this sequence, so streaming flushes\n * never cause a personal-state write and later activity stays unread.\n */\nexport function sessionAttentionReadThroughSequence(events: readonly SessionEvent[]): number {\n for (let index = events.length - 1; index >= 0; index -= 1) {\n const event = events[index]!;\n if (\n !SESSION_ATTENTION_EVENT_TYPES.has(event.type) ||\n event.duplicateOfEventId ||\n (event.turnAssociation != null && event.turnAssociation !== \"current\")\n )\n continue;\n const payload =\n event.payload && typeof event.payload === \"object\"\n ? (event.payload as Record<string, unknown>)\n : {};\n if (\n event.type === \"agent.message.completed\" &&\n (payload.phase === \"commentary\" || payload.text == null || payload.text === \"\")\n )\n continue;\n if (event.type === \"turn.completed\") {\n if (Object.hasOwn(payload, \"maintenance\") || Object.hasOwn(payload, \"segmentLimit\")) continue;\n const output = payload.output ?? payload.result;\n if ((output == null || output === \"\") && (payload.reply == null || payload.reply === \"\"))\n continue;\n }\n return event.sequence;\n }\n return 0;\n}\n"],"mappings":";;;AAKO,IAAM,gCAAqD,oBAAI,IAAI;AAAA,EACxE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAOM,SAAS,oCAAoC,QAAyC;AAC3F,WAAS,QAAQ,OAAO,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG;AAC1D,UAAM,QAAQ,OAAO,KAAK;AAC1B,QACE,CAAC,8BAA8B,IAAI,MAAM,IAAI,KAC7C,MAAM,sBACL,MAAM,mBAAmB,QAAQ,MAAM,oBAAoB;AAE5D;AACF,UAAM,UACJ,MAAM,WAAW,OAAO,MAAM,YAAY,WACrC,MAAM,UACP,CAAC;AACP,QACE,MAAM,SAAS,8BACd,QAAQ,UAAU,gBAAgB,QAAQ,QAAQ,QAAQ,QAAQ,SAAS;AAE5E;AACF,QAAI,MAAM,SAAS,kBAAkB;AACnC,UAAI,OAAO,OAAO,SAAS,aAAa,KAAK,OAAO,OAAO,SAAS,cAAc,EAAG;AACrF,YAAM,SAAS,QAAQ,UAAU,QAAQ;AACzC,WAAK,UAAU,QAAQ,WAAW,QAAQ,QAAQ,SAAS,QAAQ,QAAQ,UAAU;AACnF;AAAA,IACJ;AACA,WAAO,MAAM;AAAA,EACf;AACA,SAAO;AACT;","names":[]}
@@ -0,0 +1,20 @@
1
+ import type { CreateFeedbackRequest, Feedback, FeedbackSentiment, OpenGeniClient } from "@opengeni/sdk";
2
+ export type FeedbackClient = Pick<OpenGeniClient, "createFeedback" | "listOwnFeedback">;
3
+ /** One shared read per session, with recovery after a transient network failure. */
4
+ export declare function loadSessionFeedback(client: Pick<OpenGeniClient, "listOwnFeedback">, workspaceId: string, sessionId: string, onLoaded: (result: Awaited<ReturnType<OpenGeniClient["listOwnFeedback"]>>) => void): () => void;
5
+ /** The first saved rating per turn (the list is newest-first). */
6
+ export declare function turnRatingsFromFeedback(feedback: readonly Feedback[]): Record<string, FeedbackSentiment>;
7
+ export type FeedbackPayload = Omit<CreateFeedbackRequest, "idempotencyKey">;
8
+ /**
9
+ * The request to send, reusing the previous idempotency key when the user
10
+ * retries the identical submission (a lost response must not duplicate it).
11
+ */
12
+ export declare function feedbackSubmission(payload: FeedbackPayload, previous: CreateFeedbackRequest | null, newKey: () => string): CreateFeedbackRequest;
13
+ export declare function feedbackDialogCopy(target: {
14
+ sessionId?: string | undefined;
15
+ turnId?: string | undefined;
16
+ }): {
17
+ title: string;
18
+ description: string;
19
+ };
20
+ export declare function feedbackSentimentLabel(sentiment: FeedbackSentiment): string;
@@ -0,0 +1,56 @@
1
+ "use client";
2
+
3
+ // src/session-feedback-model.ts
4
+ function loadSessionFeedback(client, workspaceId, sessionId, onLoaded) {
5
+ let current = true;
6
+ let delay = 1e3;
7
+ let timer;
8
+ const load = () => {
9
+ void client.listOwnFeedback(workspaceId, { sessionId, includeTurns: true }).then(
10
+ (result) => {
11
+ if (current) onLoaded(result);
12
+ },
13
+ () => {
14
+ if (!current) return;
15
+ timer = setTimeout(load, delay);
16
+ delay = Math.min(delay * 2, 3e4);
17
+ }
18
+ );
19
+ };
20
+ load();
21
+ return () => {
22
+ current = false;
23
+ clearTimeout(timer);
24
+ };
25
+ }
26
+ function turnRatingsFromFeedback(feedback) {
27
+ const ratings = {};
28
+ for (const entry of feedback) {
29
+ if (entry.turnId && entry.sentiment && !ratings[entry.turnId])
30
+ ratings[entry.turnId] = entry.sentiment;
31
+ }
32
+ return ratings;
33
+ }
34
+ function feedbackSubmission(payload, previous, newKey) {
35
+ if (previous && previous.sessionId === payload.sessionId && previous.turnId === payload.turnId && previous.sentiment === payload.sentiment && previous.comment === payload.comment) {
36
+ return previous;
37
+ }
38
+ return { ...payload, idempotencyKey: newKey() };
39
+ }
40
+ function feedbackDialogCopy(target) {
41
+ return {
42
+ title: target.turnId ? "Rate this reply" : target.sessionId ? "Rate this session" : "Send feedback",
43
+ description: target.sessionId ? "Share what worked or what could be better." : "Tell us what could make Opengeni better."
44
+ };
45
+ }
46
+ function feedbackSentimentLabel(sentiment) {
47
+ return sentiment === "positive" ? "Thumbs up" : "Thumbs down";
48
+ }
49
+ export {
50
+ feedbackDialogCopy,
51
+ feedbackSentimentLabel,
52
+ feedbackSubmission,
53
+ loadSessionFeedback,
54
+ turnRatingsFromFeedback
55
+ };
56
+ //# sourceMappingURL=session-feedback-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/session-feedback-model.ts"],"sourcesContent":["// Reply and session feedback shared by web and native: the one feedback read\n// per session (with recovery), saved turn ratings, the submission payload with\n// a retained idempotency key, and the dialog copy. No DOM, no React.\nimport type {\n CreateFeedbackRequest,\n Feedback,\n FeedbackSentiment,\n OpenGeniClient,\n} from \"@opengeni/sdk\";\n\nexport type FeedbackClient = Pick<OpenGeniClient, \"createFeedback\" | \"listOwnFeedback\">;\n\n/** One shared read per session, with recovery after a transient network failure. */\nexport function loadSessionFeedback(\n client: Pick<OpenGeniClient, \"listOwnFeedback\">,\n workspaceId: string,\n sessionId: string,\n onLoaded: (result: Awaited<ReturnType<OpenGeniClient[\"listOwnFeedback\"]>>) => void,\n): () => void {\n let current = true;\n let delay = 1_000;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const load = () => {\n void client.listOwnFeedback(workspaceId, { sessionId, includeTurns: true }).then(\n (result) => {\n if (current) onLoaded(result);\n },\n () => {\n if (!current) return;\n timer = setTimeout(load, delay);\n delay = Math.min(delay * 2, 30_000);\n },\n );\n };\n load();\n return () => {\n current = false;\n clearTimeout(timer);\n };\n}\n\n/** The first saved rating per turn (the list is newest-first). */\nexport function turnRatingsFromFeedback(\n feedback: readonly Feedback[],\n): Record<string, FeedbackSentiment> {\n const ratings: Record<string, FeedbackSentiment> = {};\n for (const entry of feedback) {\n if (entry.turnId && entry.sentiment && !ratings[entry.turnId])\n ratings[entry.turnId] = entry.sentiment;\n }\n return ratings;\n}\n\nexport type FeedbackPayload = Omit<CreateFeedbackRequest, \"idempotencyKey\">;\n\n/**\n * The request to send, reusing the previous idempotency key when the user\n * retries the identical submission (a lost response must not duplicate it).\n */\nexport function feedbackSubmission(\n payload: FeedbackPayload,\n previous: CreateFeedbackRequest | null,\n newKey: () => string,\n): CreateFeedbackRequest {\n if (\n previous &&\n previous.sessionId === payload.sessionId &&\n previous.turnId === payload.turnId &&\n previous.sentiment === payload.sentiment &&\n previous.comment === payload.comment\n ) {\n return previous;\n }\n return { ...payload, idempotencyKey: newKey() };\n}\n\nexport function feedbackDialogCopy(target: {\n sessionId?: string | undefined;\n turnId?: string | undefined;\n}) {\n return {\n title: target.turnId\n ? \"Rate this reply\"\n : target.sessionId\n ? \"Rate this session\"\n : \"Send feedback\",\n description: target.sessionId\n ? \"Share what worked or what could be better.\"\n : \"Tell us what could make Opengeni better.\",\n };\n}\n\nexport function feedbackSentimentLabel(sentiment: FeedbackSentiment): string {\n return sentiment === \"positive\" ? \"Thumbs up\" : \"Thumbs down\";\n}\n"],"mappings":";;;AAaO,SAAS,oBACd,QACA,aACA,WACA,UACY;AACZ,MAAI,UAAU;AACd,MAAI,QAAQ;AACZ,MAAI;AACJ,QAAM,OAAO,MAAM;AACjB,SAAK,OAAO,gBAAgB,aAAa,EAAE,WAAW,cAAc,KAAK,CAAC,EAAE;AAAA,MAC1E,CAAC,WAAW;AACV,YAAI,QAAS,UAAS,MAAM;AAAA,MAC9B;AAAA,MACA,MAAM;AACJ,YAAI,CAAC,QAAS;AACd,gBAAQ,WAAW,MAAM,KAAK;AAC9B,gBAAQ,KAAK,IAAI,QAAQ,GAAG,GAAM;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AACA,OAAK;AACL,SAAO,MAAM;AACX,cAAU;AACV,iBAAa,KAAK;AAAA,EACpB;AACF;AAGO,SAAS,wBACd,UACmC;AACnC,QAAM,UAA6C,CAAC;AACpD,aAAW,SAAS,UAAU;AAC5B,QAAI,MAAM,UAAU,MAAM,aAAa,CAAC,QAAQ,MAAM,MAAM;AAC1D,cAAQ,MAAM,MAAM,IAAI,MAAM;AAAA,EAClC;AACA,SAAO;AACT;AAQO,SAAS,mBACd,SACA,UACA,QACuB;AACvB,MACE,YACA,SAAS,cAAc,QAAQ,aAC/B,SAAS,WAAW,QAAQ,UAC5B,SAAS,cAAc,QAAQ,aAC/B,SAAS,YAAY,QAAQ,SAC7B;AACA,WAAO;AAAA,EACT;AACA,SAAO,EAAE,GAAG,SAAS,gBAAgB,OAAO,EAAE;AAChD;AAEO,SAAS,mBAAmB,QAGhC;AACD,SAAO;AAAA,IACL,OAAO,OAAO,SACV,oBACA,OAAO,YACL,sBACA;AAAA,IACN,aAAa,OAAO,YAChB,+CACA;AAAA,EACN;AACF;AAEO,SAAS,uBAAuB,WAAsC;AAC3E,SAAO,cAAc,aAAa,cAAc;AAClD;","names":[]}
@@ -0,0 +1,96 @@
1
+ import { type ClientModel, type Session, type SessionListEntry, type SessionStatus } from "@opengeni/sdk";
2
+ import { findPickerRow, type PickerModelRow } from "./model-policy.js";
3
+ /** A list row may be a compact page entry or a complete session response. */
4
+ export type SessionListRow = Session | SessionListEntry;
5
+ /**
6
+ * The title shown for a session: durable agent/user metadata once available,
7
+ * otherwise a bounded opening-prompt preview while automatic naming is still
8
+ * pending. Every list, header and row reads identically.
9
+ */
10
+ export declare function sessionDisplayTitle(session: SessionListRow): string;
11
+ /** The maximum length a session title may be renamed to. */
12
+ export declare const SESSION_TITLE_MAX_LENGTH = 200;
13
+ /**
14
+ * The value a rename editor seeds from. A safe provisional prompt preview is
15
+ * editable because it is also what the user sees; the UUID-derived reference
16
+ * remains an empty draft rather than becoming an accidental rename.
17
+ */
18
+ export declare function sessionRenameSeed(session: SessionListRow): string;
19
+ /**
20
+ * Resolve a submitted draft against the current display title. Returns the
21
+ * trimmed title to persist, or `null` when the edit is a no-op (empty,
22
+ * unchanged from what is already shown, or still equal to the value that
23
+ * seeded this edit) and should simply cancel.
24
+ */
25
+ export declare function resolveRenameSubmission(draft: string, display: string, editSeed?: string): string | null;
26
+ export type SessionRecencyGroup = "today" | "yesterday" | "previous7" | "older";
27
+ export declare const SESSION_GROUP_LABELS: Record<SessionRecencyGroup, string>;
28
+ /** The render order of recency groups, top → bottom. */
29
+ export declare const SESSION_GROUP_ORDER: SessionRecencyGroup[];
30
+ export declare function isRunningStatus(status: SessionStatus): boolean;
31
+ /** An idle session waiting on its own timer, while its control is active. */
32
+ export declare function sessionInputWait(session: Pick<SessionListRow, "status" | "effectiveControl" | "inputWait">): {
33
+ deadlineAt: string;
34
+ reason: string;
35
+ } | null;
36
+ export declare function hasActiveEffectiveControl(session: SessionListRow): boolean;
37
+ export declare function isEffectivelyRunning(session: SessionListRow): boolean;
38
+ /** Most-recent activity timestamp for a session (updatedAt, then createdAt). */
39
+ export declare function sessionActivityTime(session: SessionListRow): number;
40
+ /** Deterministic newest-first ordering for every flat or forest session list. */
41
+ export declare function compareSessionActivity(left: SessionListRow, right: SessionListRow): number;
42
+ /** Deterministic personal-pin order: newest pin first, then descending id. */
43
+ export declare function compareSessionPins(left: SessionListRow, right: SessionListRow): number;
44
+ /** Split explicit personal pins from ordinary rows without changing the input. */
45
+ export declare function partitionPinnedSessions<T extends SessionListRow>(sessions: T[]): {
46
+ pinned: T[];
47
+ ordinary: T[];
48
+ };
49
+ /**
50
+ * Which recency bucket a timestamp falls into, relative to `now`. "Today" and
51
+ * "Yesterday" are calendar-local; "Previous 7 days" is the rest of the trailing
52
+ * week; everything earlier is "Older".
53
+ */
54
+ export declare function recencyGroupFor(timestampMs: number, now?: Date): SessionRecencyGroup;
55
+ export type SessionRecencyBucket<T extends SessionListRow = SessionListRow> = {
56
+ group: SessionRecencyGroup;
57
+ label: string;
58
+ sessions: T[];
59
+ };
60
+ export type GroupedSessions<T extends SessionListRow = SessionListRow> = {
61
+ /** Running sessions, pinned above every recency group, most-recent first. */
62
+ running: T[];
63
+ /** Non-running sessions bucketed by recency (empty buckets dropped). */
64
+ grouped: SessionRecencyBucket<T>[];
65
+ };
66
+ /**
67
+ * Order + bucket the sessions for the rail. Running sessions are lifted into a
68
+ * synthetic, always-first position regardless of recency (rendered with a
69
+ * "running" marker); the remainder are bucketed by recency, most-recent first
70
+ * within each bucket. Empty groups are dropped.
71
+ */
72
+ export declare function groupSessionsForRail<T extends SessionListRow>(sessions: T[], now?: Date): GroupedSessions<T>;
73
+ export declare function relativeTimeLabel(value: string, now?: Date): string;
74
+ /** Codex subscription product ids are prefixed `codex/`. */
75
+ export declare function isCodexProductModel(modelId: string): boolean;
76
+ export type SessionStatusTone = "queued" | "running" | "waiting" | "idle" | "failed" | "cancelled";
77
+ export declare const SESSION_STATUS_TONE: Record<SessionStatus, SessionStatusTone>;
78
+ /** The status dot of a recent-session row: a background command reads as running. */
79
+ export declare function recentSessionStatus(session: Pick<SessionListRow, "status" | "backgroundCommandActivity">): {
80
+ tone: SessionStatusTone;
81
+ pulse: boolean;
82
+ };
83
+ /** A short `owner/repo` label from the session's first repository resource. */
84
+ export declare function sessionRepoLabel(session: Pick<Session, "resources">): string | null;
85
+ export declare function recentSessionModelPresentation<TCatalog extends ClientModel>(modelId: string, catalogRows: readonly PickerModelRow<TCatalog>[]): {
86
+ label: string;
87
+ billingClass: PickerModelRow["billingClass"];
88
+ logoUrl?: string | undefined;
89
+ };
90
+ /**
91
+ * The home screen's recent sessions: server pins first, then running, then
92
+ * recency buckets, capped. `sessions` keeps the all-visible-row contract, so
93
+ * its pins are removed before recombining the explicit pinned section.
94
+ */
95
+ export declare function recentSessionsForHome<T extends SessionListRow>(sessions: T[], pinned: T[], limit?: number, now?: Date): T[];
96
+ export { findPickerRow };
@@ -0,0 +1,219 @@
1
+ "use client";
2
+ import {
3
+ findPickerRow
4
+ } from "./chunk-IX3K4THH.js";
5
+
6
+ // src/session-list-model.ts
7
+ import {
8
+ deriveAutomaticSessionTitlePreview,
9
+ deriveSessionDisplayTitle,
10
+ sessionTitleIsPending
11
+ } from "@opengeni/sdk";
12
+ import { modelDisplayName } from "@opengeni/sdk/model-display";
13
+ function sessionDisplayTitle(session) {
14
+ return "displayTitle" in session ? session.displayTitle : deriveSessionDisplayTitle(session);
15
+ }
16
+ var SESSION_TITLE_MAX_LENGTH = 200;
17
+ function sessionRenameSeed(session) {
18
+ if ("renameSeed" in session) return session.renameSeed;
19
+ if (!sessionTitleIsPending(session)) {
20
+ return session.title?.trim() || "";
21
+ }
22
+ return deriveAutomaticSessionTitlePreview(session.initialMessage) ?? "";
23
+ }
24
+ function resolveRenameSubmission(draft, display, editSeed) {
25
+ const next = draft.trim();
26
+ if (!next || next === display || editSeed !== void 0 && next === editSeed.trim()) {
27
+ return null;
28
+ }
29
+ return next;
30
+ }
31
+ var SESSION_GROUP_LABELS = {
32
+ today: "Today",
33
+ yesterday: "Yesterday",
34
+ previous7: "Previous 7 days",
35
+ older: "Older"
36
+ };
37
+ var SESSION_GROUP_ORDER = [
38
+ "today",
39
+ "yesterday",
40
+ "previous7",
41
+ "older"
42
+ ];
43
+ var RUNNING_STATUSES = /* @__PURE__ */ new Set([
44
+ "running",
45
+ "queued",
46
+ "waiting_capacity",
47
+ "recovering",
48
+ "requires_action"
49
+ ]);
50
+ function isRunningStatus(status) {
51
+ return RUNNING_STATUSES.has(status);
52
+ }
53
+ function sessionInputWait(session) {
54
+ return session.status === "idle" && session.effectiveControl?.state === "active" ? session.inputWait ?? null : null;
55
+ }
56
+ function hasActiveEffectiveControl(session) {
57
+ return (session.effectiveControl?.state ?? "active") === "active";
58
+ }
59
+ function isEffectivelyRunning(session) {
60
+ return hasActiveEffectiveControl(session) && (isRunningStatus(session.status) || Boolean(sessionInputWait(session)));
61
+ }
62
+ function sessionActivityTime(session) {
63
+ const updated = Date.parse(session.updatedAt);
64
+ if (!Number.isNaN(updated)) {
65
+ return updated;
66
+ }
67
+ const created = Date.parse(session.createdAt);
68
+ return Number.isNaN(created) ? 0 : created;
69
+ }
70
+ function compareSessionActivity(left, right) {
71
+ return sessionActivityTime(right) - sessionActivityTime(left) || right.id.localeCompare(left.id);
72
+ }
73
+ function compareSessionPins(left, right) {
74
+ const leftPinnedAt = Date.parse(left.pinnedAt ?? "");
75
+ const rightPinnedAt = Date.parse(right.pinnedAt ?? "");
76
+ const leftTime = Number.isNaN(leftPinnedAt) ? 0 : leftPinnedAt;
77
+ const rightTime = Number.isNaN(rightPinnedAt) ? 0 : rightPinnedAt;
78
+ return rightTime - leftTime || right.id.localeCompare(left.id);
79
+ }
80
+ function partitionPinnedSessions(sessions) {
81
+ const pinned = [];
82
+ const ordinary = [];
83
+ for (const session of sessions) {
84
+ (session.pinned ? pinned : ordinary).push(session);
85
+ }
86
+ return { pinned: pinned.sort(compareSessionPins), ordinary };
87
+ }
88
+ function recencyGroupFor(timestampMs, now = /* @__PURE__ */ new Date()) {
89
+ const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();
90
+ const startOfYesterday = startOfToday - 24 * 60 * 60 * 1e3;
91
+ const startOfWeekWindow = startOfToday - 7 * 24 * 60 * 60 * 1e3;
92
+ if (timestampMs >= startOfToday) {
93
+ return "today";
94
+ }
95
+ if (timestampMs >= startOfYesterday) {
96
+ return "yesterday";
97
+ }
98
+ if (timestampMs >= startOfWeekWindow) {
99
+ return "previous7";
100
+ }
101
+ return "older";
102
+ }
103
+ function groupSessionsForRail(sessions, now = /* @__PURE__ */ new Date()) {
104
+ const running = sessions.filter(isEffectivelyRunning).sort(compareSessionActivity);
105
+ const rest = sessions.filter((session) => !isEffectivelyRunning(session)).sort(compareSessionActivity);
106
+ const buckets = /* @__PURE__ */ new Map();
107
+ for (const session of rest) {
108
+ const group = recencyGroupFor(sessionActivityTime(session), now);
109
+ const list = buckets.get(group) ?? [];
110
+ list.push(session);
111
+ buckets.set(group, list);
112
+ }
113
+ const grouped = [];
114
+ for (const group of SESSION_GROUP_ORDER) {
115
+ const list = buckets.get(group);
116
+ if (list && list.length > 0) {
117
+ grouped.push({
118
+ group,
119
+ label: SESSION_GROUP_LABELS[group],
120
+ sessions: list
121
+ });
122
+ }
123
+ }
124
+ return { running, grouped };
125
+ }
126
+ function relativeTimeLabel(value, now = /* @__PURE__ */ new Date()) {
127
+ const timestamp = Date.parse(value);
128
+ if (Number.isNaN(timestamp)) {
129
+ return "";
130
+ }
131
+ const diffSeconds = Math.max(0, Math.floor((now.getTime() - timestamp) / 1e3));
132
+ if (diffSeconds < 45) {
133
+ return "now";
134
+ }
135
+ const minutes = Math.floor(diffSeconds / 60);
136
+ if (minutes < 60) {
137
+ return `${minutes}m`;
138
+ }
139
+ const hours = Math.floor(minutes / 60);
140
+ if (hours < 24) {
141
+ return `${hours}h`;
142
+ }
143
+ const days = Math.floor(hours / 24);
144
+ if (days < 7) {
145
+ return `${days}d`;
146
+ }
147
+ return new Date(timestamp).toLocaleDateString(void 0, {
148
+ month: "short",
149
+ day: "numeric"
150
+ });
151
+ }
152
+ function isCodexProductModel(modelId) {
153
+ return modelId.startsWith("codex/");
154
+ }
155
+ var SESSION_STATUS_TONE = {
156
+ queued: "queued",
157
+ running: "running",
158
+ recovering: "running",
159
+ waiting_capacity: "waiting",
160
+ requires_action: "waiting",
161
+ idle: "idle",
162
+ failed: "failed",
163
+ cancelled: "cancelled"
164
+ };
165
+ function recentSessionStatus(session) {
166
+ const hasBackgroundCommand = session.backgroundCommandActivity !== void 0;
167
+ return {
168
+ tone: hasBackgroundCommand ? "running" : SESSION_STATUS_TONE[session.status],
169
+ pulse: hasBackgroundCommand || session.status === "running"
170
+ };
171
+ }
172
+ function sessionRepoLabel(session) {
173
+ const repo = session.resources.find((resource) => resource.kind === "repository");
174
+ if (!repo || repo.kind !== "repository") {
175
+ return null;
176
+ }
177
+ const parts = repo.uri.replace(/\.git$/, "").split("/").filter(Boolean);
178
+ return parts.length >= 2 ? parts.slice(-2).join("/") : parts.at(-1) ?? null;
179
+ }
180
+ function recentSessionModelPresentation(modelId, catalogRows) {
181
+ const row = findPickerRow([...catalogRows], modelId);
182
+ return {
183
+ label: row?.label ?? modelDisplayName(modelId),
184
+ logoUrl: row?.catalog.logoUrl,
185
+ billingClass: row?.billingClass ?? (isCodexProductModel(modelId) ? "codex_subscription" : "opengeni_credits")
186
+ };
187
+ }
188
+ function recentSessionsForHome(sessions, pinned, limit = 6, now = /* @__PURE__ */ new Date()) {
189
+ const ordinary = sessions.filter((session) => !session.pinned);
190
+ const { running, grouped } = groupSessionsForRail(ordinary, now);
191
+ return [...pinned, ...running, ...grouped.flatMap((bucket) => bucket.sessions)].slice(0, limit);
192
+ }
193
+ export {
194
+ SESSION_GROUP_LABELS,
195
+ SESSION_GROUP_ORDER,
196
+ SESSION_STATUS_TONE,
197
+ SESSION_TITLE_MAX_LENGTH,
198
+ compareSessionActivity,
199
+ compareSessionPins,
200
+ findPickerRow,
201
+ groupSessionsForRail,
202
+ hasActiveEffectiveControl,
203
+ isCodexProductModel,
204
+ isEffectivelyRunning,
205
+ isRunningStatus,
206
+ partitionPinnedSessions,
207
+ recencyGroupFor,
208
+ recentSessionModelPresentation,
209
+ recentSessionStatus,
210
+ recentSessionsForHome,
211
+ relativeTimeLabel,
212
+ resolveRenameSubmission,
213
+ sessionActivityTime,
214
+ sessionDisplayTitle,
215
+ sessionInputWait,
216
+ sessionRenameSeed,
217
+ sessionRepoLabel
218
+ };
219
+ //# sourceMappingURL=session-list-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/session-list-model.ts"],"sourcesContent":["// Pure session-list presentation shared by the web app (rail and recent\n// sessions) and native renderers: relative-time labels, recency bucketing\n// (Today / Yesterday / Previous 7 days / Older), the running-first ordering\n// rule, status tones and the compact row metadata. No DOM, no React.\nimport {\n deriveAutomaticSessionTitlePreview,\n deriveSessionDisplayTitle,\n sessionTitleIsPending,\n type ClientModel,\n type Session,\n type SessionListEntry,\n type SessionStatus,\n} from \"@opengeni/sdk\";\nimport { modelDisplayName } from \"@opengeni/sdk/model-display\";\nimport { findPickerRow, type PickerModelRow } from \"./model-policy\";\n\n/** A list row may be a compact page entry or a complete session response. */\nexport type SessionListRow = Session | SessionListEntry;\n\n/**\n * The title shown for a session: durable agent/user metadata once available,\n * otherwise a bounded opening-prompt preview while automatic naming is still\n * pending. Every list, header and row reads identically.\n */\nexport function sessionDisplayTitle(session: SessionListRow): string {\n return \"displayTitle\" in session ? session.displayTitle : deriveSessionDisplayTitle(session);\n}\n\n/** The maximum length a session title may be renamed to. */\nexport const SESSION_TITLE_MAX_LENGTH = 200;\n\n/**\n * The value a rename editor seeds from. A safe provisional prompt preview is\n * editable because it is also what the user sees; the UUID-derived reference\n * remains an empty draft rather than becoming an accidental rename.\n */\nexport function sessionRenameSeed(session: SessionListRow): string {\n if (\"renameSeed\" in session) return session.renameSeed;\n if (!sessionTitleIsPending(session)) {\n return session.title?.trim() || \"\";\n }\n return deriveAutomaticSessionTitlePreview(session.initialMessage) ?? \"\";\n}\n\n/**\n * Resolve a submitted draft against the current display title. Returns the\n * trimmed title to persist, or `null` when the edit is a no-op (empty,\n * unchanged from what is already shown, or still equal to the value that\n * seeded this edit) and should simply cancel.\n */\nexport function resolveRenameSubmission(\n draft: string,\n display: string,\n editSeed?: string,\n): string | null {\n const next = draft.trim();\n if (!next || next === display || (editSeed !== undefined && next === editSeed.trim())) {\n return null;\n }\n return next;\n}\n\nexport type SessionRecencyGroup = \"today\" | \"yesterday\" | \"previous7\" | \"older\";\n\nexport const SESSION_GROUP_LABELS: Record<SessionRecencyGroup, string> = {\n today: \"Today\",\n yesterday: \"Yesterday\",\n previous7: \"Previous 7 days\",\n older: \"Older\",\n};\n\n/** The render order of recency groups, top → bottom. */\nexport const SESSION_GROUP_ORDER: SessionRecencyGroup[] = [\n \"today\",\n \"yesterday\",\n \"previous7\",\n \"older\",\n];\n\n/** Live states that earn the pinned-to-top, breathing-dot treatment. */\nconst RUNNING_STATUSES = new Set<SessionStatus>([\n \"running\",\n \"queued\",\n \"waiting_capacity\",\n \"recovering\",\n \"requires_action\",\n]);\n\nexport function isRunningStatus(status: SessionStatus): boolean {\n return RUNNING_STATUSES.has(status);\n}\n\n/** An idle session waiting on its own timer, while its control is active. */\nexport function sessionInputWait(\n session: Pick<SessionListRow, \"status\" | \"effectiveControl\" | \"inputWait\">,\n) {\n return session.status === \"idle\" && session.effectiveControl?.state === \"active\"\n ? (session.inputWait ?? null)\n : null;\n}\n\nexport function hasActiveEffectiveControl(session: SessionListRow): boolean {\n return (session.effectiveControl?.state ?? \"active\") === \"active\";\n}\n\nexport function isEffectivelyRunning(session: SessionListRow): boolean {\n // Background commands have their own chat indicator, not agent working status.\n return (\n hasActiveEffectiveControl(session) &&\n (isRunningStatus(session.status) || Boolean(sessionInputWait(session)))\n );\n}\n\n/** Most-recent activity timestamp for a session (updatedAt, then createdAt). */\nexport function sessionActivityTime(session: SessionListRow): number {\n const updated = Date.parse(session.updatedAt);\n if (!Number.isNaN(updated)) {\n return updated;\n }\n const created = Date.parse(session.createdAt);\n return Number.isNaN(created) ? 0 : created;\n}\n\n/** Deterministic newest-first ordering for every flat or forest session list. */\nexport function compareSessionActivity(left: SessionListRow, right: SessionListRow): number {\n return sessionActivityTime(right) - sessionActivityTime(left) || right.id.localeCompare(left.id);\n}\n\n/** Deterministic personal-pin order: newest pin first, then descending id. */\nexport function compareSessionPins(left: SessionListRow, right: SessionListRow): number {\n const leftPinnedAt = Date.parse(left.pinnedAt ?? \"\");\n const rightPinnedAt = Date.parse(right.pinnedAt ?? \"\");\n const leftTime = Number.isNaN(leftPinnedAt) ? 0 : leftPinnedAt;\n const rightTime = Number.isNaN(rightPinnedAt) ? 0 : rightPinnedAt;\n return rightTime - leftTime || right.id.localeCompare(left.id);\n}\n\n/** Split explicit personal pins from ordinary rows without changing the input. */\nexport function partitionPinnedSessions<T extends SessionListRow>(\n sessions: T[],\n): {\n pinned: T[];\n ordinary: T[];\n} {\n const pinned: T[] = [];\n const ordinary: T[] = [];\n for (const session of sessions) {\n (session.pinned ? pinned : ordinary).push(session);\n }\n return { pinned: pinned.sort(compareSessionPins), ordinary };\n}\n\n/**\n * Which recency bucket a timestamp falls into, relative to `now`. \"Today\" and\n * \"Yesterday\" are calendar-local; \"Previous 7 days\" is the rest of the trailing\n * week; everything earlier is \"Older\".\n */\nexport function recencyGroupFor(timestampMs: number, now: Date = new Date()): SessionRecencyGroup {\n const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();\n const startOfYesterday = startOfToday - 24 * 60 * 60 * 1000;\n const startOfWeekWindow = startOfToday - 7 * 24 * 60 * 60 * 1000;\n if (timestampMs >= startOfToday) {\n return \"today\";\n }\n if (timestampMs >= startOfYesterday) {\n return \"yesterday\";\n }\n if (timestampMs >= startOfWeekWindow) {\n return \"previous7\";\n }\n return \"older\";\n}\n\nexport type SessionRecencyBucket<T extends SessionListRow = SessionListRow> = {\n group: SessionRecencyGroup;\n label: string;\n sessions: T[];\n};\n\nexport type GroupedSessions<T extends SessionListRow = SessionListRow> = {\n /** Running sessions, pinned above every recency group, most-recent first. */\n running: T[];\n /** Non-running sessions bucketed by recency (empty buckets dropped). */\n grouped: SessionRecencyBucket<T>[];\n};\n\n/**\n * Order + bucket the sessions for the rail. Running sessions are lifted into a\n * synthetic, always-first position regardless of recency (rendered with a\n * \"running\" marker); the remainder are bucketed by recency, most-recent first\n * within each bucket. Empty groups are dropped.\n */\nexport function groupSessionsForRail<T extends SessionListRow>(\n sessions: T[],\n now: Date = new Date(),\n): GroupedSessions<T> {\n const running = sessions.filter(isEffectivelyRunning).sort(compareSessionActivity);\n const rest = sessions\n .filter((session) => !isEffectivelyRunning(session))\n .sort(compareSessionActivity);\n\n const buckets = new Map<SessionRecencyGroup, T[]>();\n for (const session of rest) {\n const group = recencyGroupFor(sessionActivityTime(session), now);\n const list = buckets.get(group) ?? [];\n list.push(session);\n buckets.set(group, list);\n }\n\n const grouped: SessionRecencyBucket<T>[] = [];\n for (const group of SESSION_GROUP_ORDER) {\n const list = buckets.get(group);\n if (list && list.length > 0) {\n grouped.push({\n group,\n label: SESSION_GROUP_LABELS[group],\n sessions: list,\n });\n }\n }\n return { running, grouped };\n}\n\nexport function relativeTimeLabel(value: string, now: Date = new Date()): string {\n const timestamp = Date.parse(value);\n if (Number.isNaN(timestamp)) {\n return \"\";\n }\n const diffSeconds = Math.max(0, Math.floor((now.getTime() - timestamp) / 1000));\n if (diffSeconds < 45) {\n return \"now\";\n }\n const minutes = Math.floor(diffSeconds / 60);\n if (minutes < 60) {\n return `${minutes}m`;\n }\n const hours = Math.floor(minutes / 60);\n if (hours < 24) {\n return `${hours}h`;\n }\n const days = Math.floor(hours / 24);\n if (days < 7) {\n return `${days}d`;\n }\n return new Date(timestamp).toLocaleDateString(undefined, {\n month: \"short\",\n day: \"numeric\",\n });\n}\n\n/** Codex subscription product ids are prefixed `codex/`. */\nexport function isCodexProductModel(modelId: string): boolean {\n return modelId.startsWith(\"codex/\");\n}\n\nexport type SessionStatusTone = \"queued\" | \"running\" | \"waiting\" | \"idle\" | \"failed\" | \"cancelled\";\n\nexport const SESSION_STATUS_TONE: Record<SessionStatus, SessionStatusTone> = {\n queued: \"queued\",\n running: \"running\",\n recovering: \"running\",\n waiting_capacity: \"waiting\",\n requires_action: \"waiting\",\n idle: \"idle\",\n failed: \"failed\",\n cancelled: \"cancelled\",\n};\n\n/** The status dot of a recent-session row: a background command reads as running. */\nexport function recentSessionStatus(\n session: Pick<SessionListRow, \"status\" | \"backgroundCommandActivity\">,\n): { tone: SessionStatusTone; pulse: boolean } {\n const hasBackgroundCommand = session.backgroundCommandActivity !== undefined;\n return {\n tone: hasBackgroundCommand ? \"running\" : SESSION_STATUS_TONE[session.status],\n pulse: hasBackgroundCommand || session.status === \"running\",\n };\n}\n\n/** A short `owner/repo` label from the session's first repository resource. */\nexport function sessionRepoLabel(session: Pick<Session, \"resources\">): string | null {\n const repo = session.resources.find((resource) => resource.kind === \"repository\");\n if (!repo || repo.kind !== \"repository\") {\n return null;\n }\n const parts = repo.uri\n .replace(/\\.git$/, \"\")\n .split(\"/\")\n .filter(Boolean);\n return parts.length >= 2 ? parts.slice(-2).join(\"/\") : (parts.at(-1) ?? null);\n}\n\nexport function recentSessionModelPresentation<TCatalog extends ClientModel>(\n modelId: string,\n catalogRows: readonly PickerModelRow<TCatalog>[],\n): {\n label: string;\n billingClass: PickerModelRow[\"billingClass\"];\n logoUrl?: string | undefined;\n} {\n const row = findPickerRow([...catalogRows], modelId);\n return {\n label: row?.label ?? modelDisplayName(modelId),\n logoUrl: row?.catalog.logoUrl,\n billingClass:\n row?.billingClass ??\n (isCodexProductModel(modelId) ? \"codex_subscription\" : \"opengeni_credits\"),\n };\n}\n\n/**\n * The home screen's recent sessions: server pins first, then running, then\n * recency buckets, capped. `sessions` keeps the all-visible-row contract, so\n * its pins are removed before recombining the explicit pinned section.\n */\nexport function recentSessionsForHome<T extends SessionListRow>(\n sessions: T[],\n pinned: T[],\n limit = 6,\n now: Date = new Date(),\n): T[] {\n const ordinary = sessions.filter((session) => !session.pinned);\n const { running, grouped } = groupSessionsForRail(ordinary, now);\n return [...pinned, ...running, ...grouped.flatMap((bucket) => bucket.sessions)].slice(0, limit);\n}\n\nexport { findPickerRow };\n"],"mappings":"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","names":[]}
@@ -0,0 +1,19 @@
1
+ import type { SessionStatus } from "@opengeni/sdk";
2
+ /** Status token family (`--og-color-status-<tone>`) for a session status. */
3
+ export type SessionStatusTone = "queued" | "running" | "waiting" | "idle" | "failed" | "cancelled";
4
+ /** Renderer-neutral session status presentation: label, color family and liveness. */
5
+ export declare const SESSION_STATUS_PRESENTATION: Record<SessionStatus, {
6
+ label: string;
7
+ tone: SessionStatusTone;
8
+ pulse: boolean;
9
+ }>;
10
+ /**
11
+ * The status badge's color tokens (text, border and its alpha); the fill is the
12
+ * status color at 10%. Mirrors the web badge classes, for non-DOM renderers.
13
+ */
14
+ export declare const SESSION_STATUS_BADGE: Record<SessionStatus, {
15
+ text: string;
16
+ border: string;
17
+ borderAlpha: number;
18
+ fill: string;
19
+ }>;
@@ -1,7 +1,6 @@
1
1
  "use client";
2
2
  import {
3
3
  ApprovalSurface,
4
- BUILT_IN_TURN_SUMMARY_FACET_IDS,
5
4
  HumanInputForm,
6
5
  HumanInputSurface,
7
6
  KnowledgeActivityProvider,
@@ -20,7 +19,6 @@ import {
20
19
  ToolReviewHistoryProvider,
21
20
  UserMessageBody,
22
21
  createDefaultToolRegistry,
23
- createToolRegistry,
24
22
  defaultToolRegistry,
25
23
  sessionChromeGoalPillExplanation,
26
24
  sessionChromeGoalPillLabel,
@@ -28,25 +26,26 @@ import {
28
26
  setStartupDetails,
29
27
  useStartupDetails,
30
28
  userMessageLikelyNeedsDisclosure
31
- } from "./chunk-CREMJMVN.js";
29
+ } from "./chunk-TZQSHCZN.js";
30
+ import "./chunk-SHLZMAJN.js";
32
31
  import "./chunk-B27E3V37.js";
33
- import "./chunk-JH7V627O.js";
34
32
  import "./chunk-2HVLQ26H.js";
35
33
  import "./chunk-LJUMYUBO.js";
36
- import "./chunk-HXYOSSQO.js";
34
+ import "./chunk-YSRBFJMQ.js";
35
+ import "./chunk-BOFEQC6K.js";
37
36
  import {
38
37
  ArtifactLabelsProvider,
39
38
  DEFAULT_ARTIFACT_LABELS
40
39
  } from "./chunk-45NUOSXQ.js";
41
40
  import {
42
41
  createOlderHistoryLoadReceipt
43
- } from "./chunk-G6YRCIYJ.js";
44
- import "./chunk-QMMCJGFI.js";
45
- import "./chunk-T46QZH3E.js";
42
+ } from "./chunk-HNVWMDNN.js";
43
+ import "./chunk-L5OKM2VX.js";
46
44
  import {
47
45
  OpenGeniProvider
48
46
  } from "./chunk-PKCAYHDC.js";
49
- import "./chunk-PHBFJCEU.js";
47
+ import "./chunk-RI42H5IU.js";
48
+ import "./chunk-I5EGRXXG.js";
50
49
  import "./chunk-OYQQJL3J.js";
51
50
  import "./chunk-S2QH6EZ5.js";
52
51
  import {
@@ -56,17 +55,27 @@ import {
56
55
  useOpenGeniLinkResolver,
57
56
  viewerLinkResolver
58
57
  } from "./chunk-OGTTUYNT.js";
59
- import "./chunk-YSRBFJMQ.js";
60
- import "./chunk-CVYCLFMH.js";
61
- import "./chunk-IUHHPMAX.js";
62
- import "./chunk-PBCZL4JP.js";
63
- import "./chunk-IEE7WCLN.js";
58
+ import {
59
+ BUILT_IN_TURN_SUMMARY_FACET_IDS,
60
+ createToolRegistry
61
+ } from "./chunk-JDJJMBB3.js";
62
+ import "./chunk-ZIB4H5LN.js";
63
+ import "./chunk-R5R5RQQD.js";
64
+ import "./chunk-IZV5FTJC.js";
65
+ import "./chunk-T46QZH3E.js";
66
+ import "./chunk-PEHTX3V7.js";
67
+ import "./chunk-7RRBX5EM.js";
64
68
  import "./chunk-NX4ADH73.js";
65
- import "./chunk-L2J3PU7A.js";
69
+ import "./chunk-7ZB7I3KP.js";
66
70
  import "./chunk-PMV53IMM.js";
67
- import "./chunk-XS67YG5R.js";
71
+ import "./chunk-INIZSNXT.js";
72
+ import "./chunk-N7S72EXK.js";
73
+ import "./chunk-3ZC6QPOM.js";
74
+ import "./chunk-LHF6BVM4.js";
75
+ import "./chunk-IEE7WCLN.js";
68
76
  import "./chunk-XEA5BCMA.js";
69
- import "./chunk-LVS3MH5T.js";
77
+ import "./chunk-IX3K4THH.js";
78
+ import "./chunk-ATIRUHBZ.js";
70
79
  import "./chunk-GC3PH6N7.js";
71
80
  import "./chunk-QHUE7E4N.js";
72
81
  import "./chunk-CM7LVUKC.js";