@opengeni/sdk 3.3.2-canary.1 → 3.4.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 (295) hide show
  1. package/README.md +1007 -72
  2. package/dist/adapters/express.d.ts +31 -0
  3. package/dist/adapters/express.js +87 -0
  4. package/dist/adapters/express.js.map +1 -0
  5. package/dist/adapters/hono.d.ts +16 -0
  6. package/dist/adapters/hono.js +8 -0
  7. package/dist/adapters/hono.js.map +1 -0
  8. package/dist/adapters/next.d.ts +29 -0
  9. package/dist/adapters/next.js +22 -0
  10. package/dist/adapters/next.js.map +1 -0
  11. package/dist/allowance-refusal.d.ts +2 -0
  12. package/dist/allowance-refusal.js +50 -0
  13. package/dist/allowance-refusal.js.map +1 -0
  14. package/dist/app-links.d.ts +42 -0
  15. package/dist/app-links.js +66 -0
  16. package/dist/app-links.js.map +1 -0
  17. package/dist/artifact-catalog.d.ts +40 -0
  18. package/dist/artifact-client.d.ts +20 -8
  19. package/dist/artifacts.d.ts +1 -1
  20. package/dist/artifacts.js +8 -6
  21. package/dist/automations.js +8 -2
  22. package/dist/automations.js.map +1 -1
  23. package/dist/azure-live-transport.d.ts +32 -0
  24. package/dist/browser.d.ts +6 -2
  25. package/dist/browser.js +25 -5
  26. package/dist/chat/fold.d.ts +75 -0
  27. package/dist/chat/handler.d.ts +41 -0
  28. package/dist/chat/http.d.ts +67 -0
  29. package/dist/chat/ids.d.ts +34 -0
  30. package/dist/chat/index.d.ts +9 -0
  31. package/dist/chat/index.js +1369 -0
  32. package/dist/chat/index.js.map +1 -0
  33. package/dist/chat/openai.d.ts +30 -0
  34. package/dist/chat/opengeni.d.ts +129 -0
  35. package/dist/chat/types.d.ts +207 -0
  36. package/dist/chat/vercel.d.ts +49 -0
  37. package/dist/chats.d.ts +8 -0
  38. package/dist/chunk-4AHR4KGA.js +301 -0
  39. package/dist/chunk-4AHR4KGA.js.map +1 -0
  40. package/dist/chunk-6GYGMLX4.js +332 -0
  41. package/dist/chunk-6GYGMLX4.js.map +1 -0
  42. package/dist/chunk-7EWT3PV6.js +368 -0
  43. package/dist/chunk-7EWT3PV6.js.map +1 -0
  44. package/dist/chunk-FTWVVPR6.js +1665 -0
  45. package/dist/chunk-FTWVVPR6.js.map +1 -0
  46. package/dist/{chunk-VYCTL62C.js → chunk-GZQSWAKD.js} +1 -1
  47. package/dist/chunk-GZQSWAKD.js.map +1 -0
  48. package/dist/chunk-KGEABAID.js +71 -0
  49. package/dist/chunk-KGEABAID.js.map +1 -0
  50. package/dist/{chunk-YKZME56C.js → chunk-KWADQ227.js} +3 -3
  51. package/dist/{chunk-YKZME56C.js.map → chunk-KWADQ227.js.map} +1 -1
  52. package/dist/{chunk-E5BNEG2D.js → chunk-NCU5OAN7.js} +27 -2
  53. package/dist/chunk-NCU5OAN7.js.map +1 -0
  54. package/dist/{chunk-BESZFWMU.js → chunk-OI5YLASH.js} +73 -2
  55. package/dist/chunk-OI5YLASH.js.map +1 -0
  56. package/dist/chunk-OV3POE62.js +359 -0
  57. package/dist/chunk-OV3POE62.js.map +1 -0
  58. package/dist/chunk-P7UWKORG.js +561 -0
  59. package/dist/chunk-P7UWKORG.js.map +1 -0
  60. package/dist/chunk-QGEIL4TR.js +195 -0
  61. package/dist/chunk-QGEIL4TR.js.map +1 -0
  62. package/dist/{chunk-GY6RQPCG.js → chunk-S2NLS3ES.js} +3598 -1278
  63. package/dist/chunk-S2NLS3ES.js.map +1 -0
  64. package/dist/chunk-UM4ZXXJR.js +9 -0
  65. package/dist/chunk-UM4ZXXJR.js.map +1 -0
  66. package/dist/{chunk-TFCLHRZK.js → chunk-UME3X7CP.js} +28 -32
  67. package/dist/chunk-UME3X7CP.js.map +1 -0
  68. package/dist/chunk-VT4YM4XQ.js +210 -0
  69. package/dist/chunk-VT4YM4XQ.js.map +1 -0
  70. package/dist/chunk-WSYYXONG.js +1602 -0
  71. package/dist/chunk-WSYYXONG.js.map +1 -0
  72. package/dist/{chunk-6NEPJ7NC.js → chunk-WVCJRSGJ.js} +119 -14
  73. package/dist/chunk-WVCJRSGJ.js.map +1 -0
  74. package/dist/chunk-X5ITQVXE.js +15 -0
  75. package/dist/chunk-X5ITQVXE.js.map +1 -0
  76. package/dist/chunk-XA7HVIHI.js +126 -0
  77. package/dist/chunk-XA7HVIHI.js.map +1 -0
  78. package/dist/{chunk-QTBAMHEF.js → chunk-YJCHB7R3.js} +60 -12
  79. package/dist/chunk-YJCHB7R3.js.map +1 -0
  80. package/dist/chunk-YKIHNLWD.js +153 -0
  81. package/dist/chunk-YKIHNLWD.js.map +1 -0
  82. package/dist/chunk-ZDUBPV33.js +277 -0
  83. package/dist/chunk-ZDUBPV33.js.map +1 -0
  84. package/dist/client.d.ts +1056 -118
  85. package/dist/codex-realtime-controller.d.ts +13 -0
  86. package/dist/codex-realtime-controller.js +4 -2
  87. package/dist/codex-realtime-v3-wire.d.ts +3 -2
  88. package/dist/codex-realtime.d.ts +5 -1
  89. package/dist/company-brain.d.ts +1 -11
  90. package/dist/core.d.ts +6 -2
  91. package/dist/core.js +23 -6
  92. package/dist/deprecation.d.ts +47 -0
  93. package/dist/document-authority-client.d.ts +24 -2
  94. package/dist/document-authority.js +7 -5
  95. package/dist/editable-artifacts/index.d.ts +1 -1
  96. package/dist/editable-artifacts/types.d.ts +12 -2
  97. package/dist/editable-artifacts.js +19 -3
  98. package/dist/editable-artifacts.js.map +1 -1
  99. package/dist/embedding-client.d.ts +129 -0
  100. package/dist/errors.d.ts +64 -1
  101. package/dist/external-vault-receiver.d.ts +203 -0
  102. package/dist/external-vault-receiver.js +564 -0
  103. package/dist/external-vault-receiver.js.map +1 -0
  104. package/dist/feedback.d.ts +23 -0
  105. package/dist/gateway-realtime-transport.js +1 -1
  106. package/dist/github-repositories.d.ts +10 -0
  107. package/dist/github-repositories.js +36 -0
  108. package/dist/github-repositories.js.map +1 -0
  109. package/dist/index.d.ts +61 -11
  110. package/dist/index.js +555 -338
  111. package/dist/index.js.map +1 -1
  112. package/dist/insights-usage.d.ts +33 -0
  113. package/dist/insights-usage.js +7 -0
  114. package/dist/insights-usage.js.map +1 -0
  115. package/dist/interaction.d.ts +165 -71
  116. package/dist/interaction.js +2 -2
  117. package/dist/knowledge.d.ts +7 -0
  118. package/dist/knowledge.js +20 -0
  119. package/dist/knowledge.js.map +1 -0
  120. package/dist/known-tools.d.ts +4 -0
  121. package/dist/message-links.d.ts +68 -0
  122. package/dist/model-context.d.ts +68 -0
  123. package/dist/model-display.d.ts +2 -0
  124. package/dist/model-display.js +17 -0
  125. package/dist/model-display.js.map +1 -0
  126. package/dist/organization-integration-policy.d.ts +26 -0
  127. package/dist/organization-integration-policy.js +26 -0
  128. package/dist/organization-integration-policy.js.map +1 -0
  129. package/dist/pr-review-client.d.ts +1 -1
  130. package/dist/pr-review.d.ts +1 -1
  131. package/dist/pr-review.js.map +1 -1
  132. package/dist/preference-registry.d.ts +1 -1
  133. package/dist/prepared-mcp-setup.d.ts +5 -0
  134. package/dist/proxy.d.ts +13 -11
  135. package/dist/realtime.d.ts +1 -1
  136. package/dist/realtime.js +253 -7
  137. package/dist/realtime.js.map +1 -1
  138. package/dist/session-history-import.d.ts +22 -0
  139. package/dist/session-history-import.js +36 -0
  140. package/dist/session-history-import.js.map +1 -0
  141. package/dist/session-list-entries.d.ts +1 -0
  142. package/dist/session-list-entries.js +7 -0
  143. package/dist/session-list-entries.js.map +1 -0
  144. package/dist/session-message-search.d.ts +53 -0
  145. package/dist/session-proxy-client.d.ts +28 -0
  146. package/dist/session-proxy.d.ts +334 -0
  147. package/dist/session-proxy.js +24 -0
  148. package/dist/session-proxy.js.map +1 -0
  149. package/dist/session-titles.d.ts +2 -28
  150. package/dist/session-usage-limits.d.ts +10 -0
  151. package/dist/session-usage-limits.js +43 -0
  152. package/dist/session-usage-limits.js.map +1 -0
  153. package/dist/shared-catalog-loader.d.ts +34 -0
  154. package/dist/site-ai.d.ts +35 -0
  155. package/dist/site-bridge-host.d.ts +112 -0
  156. package/dist/site-bridge-host.js +286 -0
  157. package/dist/site-bridge-host.js.map +1 -0
  158. package/dist/site-browser-entry.d.ts +1 -0
  159. package/dist/site-browser-runtime.gen.d.ts +1 -0
  160. package/dist/site-data.d.ts +178 -0
  161. package/dist/site-document.d.ts +5 -0
  162. package/dist/site-document.js +20 -0
  163. package/dist/site-document.js.map +1 -0
  164. package/dist/site-document.test.d.ts +1 -0
  165. package/dist/site-http.d.ts +17 -0
  166. package/dist/site-sql.d.ts +31 -0
  167. package/dist/site-tool-bridge.d.ts +57 -0
  168. package/dist/site.d.ts +186 -0
  169. package/dist/site.js +63 -0
  170. package/dist/site.js.map +1 -0
  171. package/dist/skills.d.ts +75 -0
  172. package/dist/sse.d.ts +1 -1
  173. package/dist/stream.d.ts +2 -0
  174. package/dist/tenant-workspaces.d.ts +47 -0
  175. package/dist/tenant-workspaces.js +8 -0
  176. package/dist/tenant-workspaces.js.map +1 -0
  177. package/dist/tool-auth.d.ts +87 -0
  178. package/dist/tool-auth.js +23 -0
  179. package/dist/tool-auth.js.map +1 -0
  180. package/dist/tool-display-metadata.d.ts +3 -0
  181. package/dist/tools-37DCTCNZ.js +12 -0
  182. package/dist/tools-37DCTCNZ.js.map +1 -0
  183. package/dist/tools.d.ts +81 -0
  184. package/dist/transcription.d.ts +1 -1
  185. package/dist/types.d.ts +2785 -592
  186. package/dist/usage-allowances.d.ts +36 -0
  187. package/dist/usage-allowances.js +80 -0
  188. package/dist/usage-allowances.js.map +1 -0
  189. package/dist/vault-types.d.ts +324 -0
  190. package/dist/vaults-api.d.ts +65 -0
  191. package/dist/workspace-artifacts.d.ts +47 -5
  192. package/dist/workspace-instruction-policies.d.ts +2 -2
  193. package/dist/workspace-integrations.d.ts +74 -0
  194. package/dist/workspace-integrations.js +67 -0
  195. package/dist/workspace-integrations.js.map +1 -0
  196. package/dist/workspace-state.d.ts +8 -71
  197. package/package.json +99 -5
  198. package/src/adapters/express.ts +136 -0
  199. package/src/adapters/hono.ts +18 -0
  200. package/src/adapters/next.ts +42 -0
  201. package/src/allowance-refusal.ts +5 -0
  202. package/src/app-links.ts +117 -0
  203. package/src/artifact-catalog.ts +51 -0
  204. package/src/artifact-client.ts +40 -49
  205. package/src/artifacts.ts +1 -0
  206. package/src/automations-client.ts +8 -2
  207. package/src/azure-live-transport.ts +286 -0
  208. package/src/browser.ts +35 -0
  209. package/src/chat/fold.ts +431 -0
  210. package/src/chat/handler.ts +240 -0
  211. package/src/chat/http.ts +257 -0
  212. package/src/chat/ids.ts +85 -0
  213. package/src/chat/index.ts +88 -0
  214. package/src/chat/openai.ts +439 -0
  215. package/src/chat/opengeni.ts +737 -0
  216. package/src/chat/types.ts +219 -0
  217. package/src/chat/vercel.ts +204 -0
  218. package/src/chats.ts +16 -0
  219. package/src/client.ts +5595 -1847
  220. package/src/codex-realtime-controller.ts +163 -8
  221. package/src/codex-realtime-v3-wire.ts +4 -3
  222. package/src/codex-realtime-v3.ts +12 -3
  223. package/src/codex-realtime.ts +11 -3
  224. package/src/company-brain.ts +0 -40
  225. package/src/core.ts +18 -0
  226. package/src/deprecation.ts +149 -0
  227. package/src/document-authority-client.ts +104 -1
  228. package/src/editable-artifacts/controller.ts +36 -2
  229. package/src/editable-artifacts/index.ts +1 -0
  230. package/src/editable-artifacts/types.ts +29 -16
  231. package/src/embedding-client.ts +519 -0
  232. package/src/errors.ts +281 -5
  233. package/src/external-vault-receiver.ts +914 -0
  234. package/src/feedback.ts +20 -0
  235. package/src/gateway-realtime-transport.ts +3 -3
  236. package/src/github-repositories.ts +60 -0
  237. package/src/index.ts +592 -65
  238. package/src/insights-usage.ts +64 -0
  239. package/src/interaction.ts +315 -93
  240. package/src/knowledge.ts +72 -0
  241. package/src/known-tools.ts +279 -0
  242. package/src/message-links.ts +178 -0
  243. package/src/model-context.ts +113 -0
  244. package/src/model-display.ts +11 -0
  245. package/src/organization-integration-policy.ts +54 -0
  246. package/src/pr-review-client.ts +1 -1
  247. package/src/pr-review.ts +1 -1
  248. package/src/preference-registry.ts +2 -0
  249. package/src/prepared-mcp-setup.ts +123 -0
  250. package/src/proxy.ts +23 -12
  251. package/src/realtime.ts +15 -6
  252. package/src/session-history-import.ts +84 -0
  253. package/src/session-list-entries.ts +1 -0
  254. package/src/session-message-search.ts +47 -0
  255. package/src/session-proxy-client.ts +68 -0
  256. package/src/session-proxy.ts +2098 -0
  257. package/src/session-titles.ts +8 -82
  258. package/src/session-usage-limits.ts +71 -0
  259. package/src/shared-catalog-loader.ts +169 -0
  260. package/src/site-ai.ts +284 -0
  261. package/src/site-bridge-host.ts +422 -0
  262. package/src/site-browser-entry.ts +6 -0
  263. package/src/site-browser-runtime.gen.ts +2 -0
  264. package/src/site-data.ts +372 -0
  265. package/src/site-document.test.ts +64 -0
  266. package/src/site-document.ts +18 -0
  267. package/src/site-http.ts +171 -0
  268. package/src/site-sql.ts +153 -0
  269. package/src/site-tool-bridge.ts +401 -0
  270. package/src/site.ts +878 -0
  271. package/src/skills.ts +69 -0
  272. package/src/sse.ts +9 -3
  273. package/src/stream.ts +33 -10
  274. package/src/tenant-workspaces.ts +148 -0
  275. package/src/tool-auth.ts +301 -0
  276. package/src/tool-display-metadata.ts +27 -0
  277. package/src/tools.ts +452 -0
  278. package/src/transcription.ts +3 -0
  279. package/src/types.ts +3142 -594
  280. package/src/usage-allowances.ts +189 -0
  281. package/src/vault-types.ts +379 -0
  282. package/src/vaults-api.ts +339 -0
  283. package/src/workspace-artifacts.ts +55 -6
  284. package/src/workspace-instruction-policies.ts +2 -1
  285. package/src/workspace-integrations.ts +402 -0
  286. package/src/workspace-state.ts +8 -82
  287. package/dist/chunk-6NEPJ7NC.js.map +0 -1
  288. package/dist/chunk-BESZFWMU.js.map +0 -1
  289. package/dist/chunk-E5BNEG2D.js.map +0 -1
  290. package/dist/chunk-GY6RQPCG.js.map +0 -1
  291. package/dist/chunk-OO5LPTO7.js +0 -132
  292. package/dist/chunk-OO5LPTO7.js.map +0 -1
  293. package/dist/chunk-QTBAMHEF.js.map +0 -1
  294. package/dist/chunk-TFCLHRZK.js.map +0 -1
  295. package/dist/chunk-VYCTL62C.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../contracts/src/model-display.ts"],"sourcesContent":["/**\n * One display identity for a model everywhere outside the Models settings page.\n *\n * Catalog ids carry routing facts (`codex/`, `organization-claude-subscription/`,\n * `workspace-openrouter/anthropic/...`) and custom models may have no curated\n * label. People should only ever see the model itself: `GPT-6.1 Sol`,\n * `Opus 5.5`. The same upstream model therefore renders identically\n * whether an organization or a workspace connection serves it.\n *\n * Pure and dependency-free so the API, SDK, React package and web app share it.\n */\n\nexport type ModelVendor =\n | \"openai\"\n | \"anthropic\"\n | \"xai\"\n | \"google\"\n | \"meta\"\n | \"mistral\"\n | \"deepseek\"\n | \"moonshot\"\n | \"qwen\"\n | \"zhipu\"\n | \"nvidia\";\n\nexport type ModelDisplayInput =\n | string\n | {\n id: string;\n label?: string | null | undefined;\n logoUrl?: string | null | undefined;\n upstreamModelId?: string | null | undefined;\n deployment?: { upstreamModelId?: string | null | undefined } | null | undefined;\n };\n\n/** Catalog maker logo; remote images must use HTTPS without embedded credentials. */\nexport function modelLogoUrl(input: ModelDisplayInput): string | null {\n const value = typeof input === \"string\" ? undefined : input.logoUrl;\n if (!value || value.length > 2048 || value !== value.trim()) return null;\n try {\n const url = new URL(value);\n return url.protocol === \"https:\" && !url.username && !url.password ? value : null;\n } catch {\n return null;\n }\n}\n\nconst WORDS: Readonly<Record<string, string>> = {\n gpt: \"GPT\",\n chatgpt: \"ChatGPT\",\n claude: \"Claude\",\n grok: \"Grok\",\n gemini: \"Gemini\",\n gemma: \"Gemma\",\n llama: \"Llama\",\n deepseek: \"DeepSeek\",\n qwen: \"Qwen\",\n glm: \"GLM\",\n kimi: \"Kimi\",\n mistral: \"Mistral\",\n codestral: \"Codestral\",\n devstral: \"Devstral\",\n magistral: \"Magistral\",\n nemotron: \"Nemotron\",\n oss: \"OSS\",\n // Region-pinned gateway routes (Opper `aws/claude-sonnet-4-6-eu`).\n eu: \"EU\",\n};\n\n/** The upstream model slug without routing prefixes or `:variant` suffixes. */\nexport function modelSlug(value: string): string {\n const last = value.split(\"/\").filter(Boolean).at(-1) ?? value;\n return last.replace(/:[^:]*$/, \"\") || last;\n}\n\nfunction upstreamOf(input: Exclude<ModelDisplayInput, string>): string | null {\n return input.upstreamModelId?.trim() || input.deployment?.upstreamModelId?.trim() || null;\n}\n\nfunction titleToken(token: string, index: number): string {\n const lower = token.toLowerCase();\n const word = WORDS[lower];\n if (word) return word;\n // OpenAI reasoning series stay lowercase: o3, o4 Mini.\n if (index === 0 && /^o\\d+$/.test(lower)) return lower;\n // Sizes and lettered versions read as identifiers: 120B, V4, K3, A12B.\n if (/^\\d+(?:\\.\\d+)?[bkmt]$/.test(lower) || /^[a-z]\\d+[a-z\\d]*$/.test(lower)) {\n return lower.toUpperCase();\n }\n if (/^\\d/.test(token)) return lower;\n return lower.charAt(0).toUpperCase() + lower.slice(1);\n}\n\n/** `claude-opus-5-5` → `Claude Opus 5.5`, `codex/gpt-6.1-sol` → `GPT-6.1 Sol`. */\nexport function humanizeModelSlug(value: string): string {\n const slug = modelSlug(value.trim())\n // Snapshot dates are release detail, not a different model name.\n .replace(/[-_](?:\\d{8}|\\d{4}-\\d{2}-\\d{2})$/, \"\")\n .replace(/[-_]latest$/i, \"\");\n const raw = slug.split(/[-_\\s]+/).filter(Boolean);\n if (raw.length === 0) return value.trim() || value;\n // Consecutive short numbers are one version: 5-5 → 5.5, 3-5 → 3.5. Longer\n // numbers are snapshots (gpt-4-1106-preview), never a minor version.\n const tokens: string[] = [];\n for (const token of raw) {\n const previous = tokens.at(-1);\n if (previous !== undefined && /^\\d{1,2}$/.test(token) && /^\\d{1,2}$/.test(previous)) {\n tokens[tokens.length - 1] = `${previous}.${token}`;\n continue;\n }\n tokens.push(token);\n }\n const words = tokens.map(titleToken);\n // OpenAI's own spelling joins family and version: GPT-6.1, GPT-4o.\n if (words[0] === \"GPT\" && words.length > 1 && /^\\d/.test(words[1]!)) {\n return [`GPT-${words[1]}`, ...words.slice(2)].join(\" \");\n }\n return words.join(\" \");\n}\n\n/**\n * True when a catalog label is only the model's identifier: empty, or exactly\n * its id, upstream id, or any trailing path of them (`claude-opus-4-8`,\n * `anthropic/claude-sonnet-4.6`). Any other label is a curated name and wins.\n */\nexport function isRawModelLabel(\n label: string,\n ids: readonly (string | null | undefined)[] = [],\n): boolean {\n const text = label.trim();\n if (!text) return true;\n return ids.some((id) => {\n if (!id) return false;\n const segments = id.trim().split(\"/\").filter(Boolean);\n return segments.some((_, index) => {\n const tail = segments.slice(index).join(\"/\");\n return tail === text || modelSlug(tail) === text;\n });\n });\n}\n\n/**\n * The clean name to show for a model: its curated catalog label when it has\n * one, otherwise a readable form of the upstream model id. Never a routing\n * prefix, connection id or connection scope. Anthropic's Opus, Sonnet and\n * Haiku families drop the redundant `Claude` word (the maker mark already says\n * it): `Opus 5.5`, `Sonnet 4.6 EU`.\n */\nexport function modelDisplayName(input: ModelDisplayInput): string {\n if (typeof input === \"string\") {\n // A bare id is humanized; text with spaces is already a name (\"Workspace default\").\n return input.trim() && !/\\s/.test(input.trim())\n ? withoutClaudeFamilyPrefix(humanizeModelSlug(input))\n : input;\n }\n const upstream = upstreamOf(input);\n const label = input.label?.trim();\n if (label && !isRawModelLabel(label, [input.id, upstream])) {\n return withoutClaudeFamilyPrefix(label);\n }\n return withoutClaudeFamilyPrefix(humanizeModelSlug(upstream ?? label ?? input.id));\n}\n\n/** `Claude Opus 5.5` → `Opus 5.5`; other names (`Claude 3.5 Sonnet`) unchanged. */\nfunction withoutClaudeFamilyPrefix(name: string): string {\n return name.replace(/^Claude\\s+(?=(?:Opus|Sonnet|Haiku)\\b)/, \"\");\n}\n\nconst VENDOR_PATTERNS: ReadonlyArray<readonly [ModelVendor, RegExp]> = [\n [\"anthropic\", /^claude\\b/],\n [\"openai\", /^(?:gpt|chatgpt|o\\d+|codex|dall-e|sora|text-embedding|whisper)\\b/],\n [\"xai\", /^grok\\b/],\n [\"google\", /^(?:gemini|gemma)\\b/],\n [\"meta\", /^llama\\b/],\n [\"mistral\", /^(?:mistral|codestral|devstral|magistral|ministral|pixtral)\\b/],\n [\"deepseek\", /^deepseek\\b/],\n [\"moonshot\", /^(?:kimi|moonshot)\\b/],\n [\"qwen\", /^(?:qwen|qwq)\\b/],\n [\"zhipu\", /^glm\\b/],\n [\"nvidia\", /^nemotron\\b/],\n];\n\n/** OpenRouter / Gateway vendor path segments (`anthropic/claude-…`). */\nconst VENDOR_SEGMENTS: Readonly<Record<string, ModelVendor>> = {\n anthropic: \"anthropic\",\n openai: \"openai\",\n \"x-ai\": \"xai\",\n xai: \"xai\",\n google: \"google\",\n \"meta-llama\": \"meta\",\n mistralai: \"mistral\",\n deepseek: \"deepseek\",\n moonshotai: \"moonshot\",\n qwen: \"qwen\",\n \"z-ai\": \"zhipu\",\n nvidia: \"nvidia\",\n};\n\nfunction vendorFromSlug(slug: string): ModelVendor | null {\n for (const [vendor, pattern] of VENDOR_PATTERNS) if (pattern.test(slug)) return vendor;\n return null;\n}\n\n/** Who makes the model, for its logo. Null when it cannot be told. */\nexport function modelVendor(input: ModelDisplayInput): ModelVendor | null {\n const ids = typeof input === \"string\" ? [input] : [upstreamOf(input), input.id];\n for (const id of ids) {\n if (!id) continue;\n const lower = id.trim().toLowerCase();\n if (lower.startsWith(\"codex/\")) return \"openai\";\n if (lower.startsWith(\"supergrok/\")) return \"xai\";\n const vendor = vendorFromSlug(modelSlug(lower));\n if (vendor) return vendor;\n const segment = lower.split(\"/\").filter(Boolean).at(-2);\n if (segment && Object.hasOwn(VENDOR_SEGMENTS, segment)) return VENDOR_SEGMENTS[segment]!;\n }\n if (typeof input !== \"string\" && input.label) {\n return vendorFromSlug(input.label.trim().toLowerCase().replace(/\\s+/g, \"-\"));\n }\n return null;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,277 @@
1
+ // ../contracts/src/session-titles.ts
2
+ var AUTOMATIC_SESSION_TITLE_MAX_GRAPHEMES = 80;
3
+ var AUTOMATIC_SESSION_TITLE_FALLBACK = "New conversation";
4
+ var PROMPT_PREVIEW_SCAN_MAX_CODE_UNITS = 4096;
5
+ var SESSION_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
6
+ var titleSegmenter;
7
+ var KNOWN_SENSITIVE_VALUE_PATTERNS = [
8
+ /-----BEGIN [A-Z ]*PRIVATE KEY-----/iu,
9
+ /\bBearer\s+[A-Za-z0-9._~+/=-]{8,}/iu,
10
+ /\b(?:sk-(?:proj-)?|gh[oprsu]_|github_pat_|glpat-|xox[baprs]-)[A-Za-z0-9_-]{8,}/iu,
11
+ /\bAKIA[0-9A-Z]{16}\b/u,
12
+ /\bAIza[0-9A-Za-z_-]{20,}\b/u,
13
+ /\beyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/u,
14
+ /[?&](?:access_token|api_key|apikey|password|secret|token)=[^\s&#]+/iu
15
+ ];
16
+ var URI_SCHEME_CANDIDATE_PATTERN = /\b[a-z][a-z0-9+.-]*:\S+/giu;
17
+ var WINDOWS_DRIVE_PATH_PATTERN = /^[a-z]:[\\/](?![\\/])[^:]*$/iu;
18
+ var SCHEMELESS_HOST_CANDIDATE_PATTERN = /\b(?:www\.)?(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z](?:[a-z0-9-]{0,61}[a-z0-9])?(?::\d{1,5})?(?:[/?#][^\s]*)?/giu;
19
+ var SCHEMELESS_LOCAL_NETWORK_PATTERNS = [
20
+ /\blocalhost(?:(?::\d{1,5})(?:[/?#][^\s]*)?|[/?#][^\s]*)/iu,
21
+ /\b(?:(?:25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|1?\d?\d)(?:(?::\d{1,5})(?:[/?#][^\s]*)?|[/?#][^\s]*)/u,
22
+ /\[(?=[0-9a-f:.]*:[0-9a-f:.]*\])[0-9a-f:.]+\](?:(?::\d{1,5})(?:[/?#][^\s]*)?|[/?#][^\s]*)/iu
23
+ ];
24
+ var FILE_LIKE_HOST_SUFFIXES = /* @__PURE__ */ new Set([
25
+ "css",
26
+ "html",
27
+ "js",
28
+ "json",
29
+ "jsx",
30
+ "lock",
31
+ "md",
32
+ "sql",
33
+ "toml",
34
+ "ts",
35
+ "tsx",
36
+ "xml",
37
+ "yaml",
38
+ "yml"
39
+ ]);
40
+ var DOTTED_TECHNOLOGY_PATH_AUTHORITIES = /* @__PURE__ */ new Set([
41
+ "ASP.NET",
42
+ "AWS.SDK",
43
+ "Microsoft.Extensions",
44
+ "System.IO"
45
+ ]);
46
+ var SECRET_ASSIGNMENT_CANDIDATE_PATTERN = /(?:^|[^A-Za-z0-9])(?:(['"])([A-Za-z][A-Za-z0-9_. -]*)\1|([A-Za-z][A-Za-z0-9_.-]*))\s*[=:]\s*[^\s,;]+/gu;
47
+ var SECRET_LABEL_ASSIGNMENT_PATTERN = /\b(?:api[ _-]?key|access[ _-]?token|auth[ _-]?token|credential|credentials|password|passwd|private[ _-]?key|secret|token)\b\s*[=:]\s*[^\s,;]+/iu;
48
+ var SENSITIVE_ASSIGNMENT_KEY_SUFFIXES = /* @__PURE__ */ new Set([
49
+ "credential",
50
+ "credentials",
51
+ "password",
52
+ "passwd",
53
+ "secret",
54
+ "token"
55
+ ]);
56
+ var COMPACT_SENSITIVE_ASSIGNMENT_KEY_SUFFIXES = [
57
+ "apikey",
58
+ "accesskey",
59
+ "accesskeyid",
60
+ "accesstoken",
61
+ "authtoken",
62
+ "credential",
63
+ "credentials",
64
+ "password",
65
+ "passwd",
66
+ "privatekey",
67
+ "secret",
68
+ "secretkey",
69
+ "token"
70
+ ];
71
+ var SENSITIVE_ASSIGNMENT_KEY_WORD_SUFFIXES = [
72
+ ["api", "key"],
73
+ ["access", "key"],
74
+ ["access", "key", "id"],
75
+ ["auth", "key"],
76
+ ["private", "key"],
77
+ ["secret", "key"]
78
+ ];
79
+ function hasWordSuffix(words, suffix) {
80
+ if (words.length < suffix.length) return false;
81
+ const offset = words.length - suffix.length;
82
+ return suffix.every((word, index) => words[offset + index] === word);
83
+ }
84
+ function containsSensitiveAssignment(value) {
85
+ for (const match of value.matchAll(SECRET_ASSIGNMENT_CANDIDATE_PATTERN)) {
86
+ const key = match[2] ?? match[3];
87
+ if (!key) continue;
88
+ const words = key.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").toLowerCase().split(/[^a-z0-9]+/).filter(Boolean);
89
+ const last = words.at(-1);
90
+ if (last && SENSITIVE_ASSIGNMENT_KEY_SUFFIXES.has(last)) return true;
91
+ if (last && COMPACT_SENSITIVE_ASSIGNMENT_KEY_SUFFIXES.some((suffix) => last.endsWith(suffix))) {
92
+ return true;
93
+ }
94
+ if (SENSITIVE_ASSIGNMENT_KEY_WORD_SUFFIXES.some((suffix) => hasWordSuffix(words, suffix))) {
95
+ return true;
96
+ }
97
+ }
98
+ return false;
99
+ }
100
+ function containsUriScheme(value) {
101
+ for (const match of value.matchAll(URI_SCHEME_CANDIDATE_PATTERN)) {
102
+ if (!WINDOWS_DRIVE_PATH_PATTERN.test(match[0])) return true;
103
+ }
104
+ return false;
105
+ }
106
+ function isDottedTechnologyPath(candidate) {
107
+ if (/[?:#]/u.test(candidate)) return false;
108
+ const [authority, ...pathSegments] = candidate.split("/");
109
+ if (!authority || pathSegments.length === 0 || pathSegments.some((segment) => !segment)) {
110
+ return false;
111
+ }
112
+ if (!DOTTED_TECHNOLOGY_PATH_AUTHORITIES.has(authority) || pathSegments.some((segment) => !/^[A-Z][A-Za-z0-9_-]*$/u.test(segment))) {
113
+ return false;
114
+ }
115
+ return true;
116
+ }
117
+ function containsSchemelessUrl(value) {
118
+ if (SCHEMELESS_LOCAL_NETWORK_PATTERNS.some((pattern) => pattern.test(value))) return true;
119
+ for (const match of value.matchAll(SCHEMELESS_HOST_CANDIDATE_PATTERN)) {
120
+ const candidate = match[0];
121
+ if (candidate.toLowerCase().startsWith("www.")) return true;
122
+ if (!/[/?#]/u.test(candidate)) continue;
123
+ const authority = candidate.split(/[/?#]/u, 1)[0] ?? "";
124
+ const hostname = authority.replace(/:\d{1,5}$/u, "");
125
+ const suffix = hostname.split(".").at(-1)?.toLowerCase();
126
+ if (suffix && FILE_LIKE_HOST_SUFFIXES.has(suffix)) continue;
127
+ if (isDottedTechnologyPath(candidate)) continue;
128
+ return true;
129
+ }
130
+ return false;
131
+ }
132
+ var OPAQUE_IDENTIFIER_PATTERN = /\b(?=[A-Za-z0-9_-]{32,}\b)(?=[A-Za-z0-9_-]*[A-Za-z])(?=[A-Za-z0-9_-]*\d)[A-Za-z0-9_-]+\b/u;
133
+ var DEFAULT_IGNORABLE_CODE_POINTS = /\p{Default_Ignorable_Code_Point}+/gu;
134
+ var ESCAPED_QUOTE_DELIMITERS = /\\+(?=["'])/gu;
135
+ function automaticTitleDetectionValue(value) {
136
+ return value.normalize("NFKC").replace(DEFAULT_IGNORABLE_CODE_POINTS, "").replace(ESCAPED_QUOTE_DELIMITERS, "");
137
+ }
138
+ function containsSensitiveAutomaticSessionTitleValue(value) {
139
+ const detectionValue = automaticTitleDetectionValue(value);
140
+ if (KNOWN_SENSITIVE_VALUE_PATTERNS.some((pattern) => pattern.test(detectionValue))) return true;
141
+ if (containsUriScheme(detectionValue)) return true;
142
+ if (containsSchemelessUrl(detectionValue)) return true;
143
+ if (SECRET_LABEL_ASSIGNMENT_PATTERN.test(detectionValue)) return true;
144
+ if (containsSensitiveAssignment(detectionValue)) return true;
145
+ if (OPAQUE_IDENTIFIER_PATTERN.test(detectionValue)) return true;
146
+ return false;
147
+ }
148
+ function automaticTitleGraphemes(value) {
149
+ if (titleSegmenter === void 0) {
150
+ titleSegmenter = typeof Intl.Segmenter === "function" ? new Intl.Segmenter(void 0, { granularity: "grapheme" }) : null;
151
+ }
152
+ if (titleSegmenter) {
153
+ return Array.from(titleSegmenter.segment(value), (part) => part.segment);
154
+ }
155
+ const graphemes = [];
156
+ for (const point of value) {
157
+ const prior = graphemes.at(-1);
158
+ if (prior && (/^[\p{Mark}\u{FE0E}\u{FE0F}\p{Emoji_Modifier}]$/u.test(point) || point === "\u200D" || prior.endsWith("\u200D"))) {
159
+ graphemes[graphemes.length - 1] = `${prior}${point}`;
160
+ } else {
161
+ graphemes.push(point);
162
+ }
163
+ }
164
+ return graphemes;
165
+ }
166
+ var MODEL_CONTROL_TOKEN = /<[||][^<>||\s]{1,64}[||]>/gu;
167
+ function withoutModelControlTokens(value) {
168
+ return value.replace(MODEL_CONTROL_TOKEN, "\n");
169
+ }
170
+ function cleanStoredSessionTitle(title, titleSource) {
171
+ if (title === null || title === void 0) return null;
172
+ if (titleSource === "user") return title;
173
+ const stripped = withoutModelControlTokens(title);
174
+ if (stripped === title) return title;
175
+ return stripped.split("\n").map((part) => part.trim()).find(Boolean) ?? null;
176
+ }
177
+ function boundAutomaticSessionTitle(value) {
178
+ const words = value.split(/\s+/u);
179
+ const wordBounded = words.length > 10 ? words.slice(0, 10).join(" ") : value;
180
+ const graphemes = automaticTitleGraphemes(wordBounded);
181
+ if (graphemes.length <= AUTOMATIC_SESSION_TITLE_MAX_GRAPHEMES) return wordBounded;
182
+ const prefix = graphemes.slice(0, AUTOMATIC_SESSION_TITLE_MAX_GRAPHEMES).join("");
183
+ const lastWhitespace = prefix.search(/\s+\S*$/u);
184
+ return (lastWhitespace >= 16 ? prefix.slice(0, lastWhitespace) : prefix).trimEnd();
185
+ }
186
+ function deriveAutomaticSessionTitlePreview(value) {
187
+ if (typeof value !== "string") return null;
188
+ const lines = value.slice(0, PROMPT_PREVIEW_SCAN_MAX_CODE_UNITS).replace(/[\u0000-\u001f\u007f-\u009f]+/gu, "\n").split(/\n+/u);
189
+ for (const candidate of lines) {
190
+ const line = candidate.trim();
191
+ if (!line || containsSensitiveAutomaticSessionTitleValue(line)) continue;
192
+ const preview = boundAutomaticSessionTitle(line.replace(/\s+/gu, " ")).replace(/[\s.!?,;:\-–—]+$/u, "").trim();
193
+ if (preview) return preview;
194
+ }
195
+ return null;
196
+ }
197
+ function automaticSessionReferenceTitle(id) {
198
+ const sessionId = typeof id === "string" ? id.trim() : "";
199
+ return SESSION_ID_PATTERN.test(sessionId) ? `Conversation ${sessionId.slice(0, 13)}` : AUTOMATIC_SESSION_TITLE_FALLBACK;
200
+ }
201
+ function sessionTitleIsPending(input) {
202
+ const title = input.title?.trim() ?? "";
203
+ return input.titleSource !== "user" && (!title || title === AUTOMATIC_SESSION_TITLE_FALLBACK);
204
+ }
205
+ function deriveSessionDisplayTitle(input, options = {}) {
206
+ const title = input.title?.trim() ?? "";
207
+ if (input.titleSource === "user") {
208
+ return title || automaticSessionReferenceTitle(input.id);
209
+ }
210
+ if (title && !sessionTitleIsPending(input)) {
211
+ const clean = cleanStoredSessionTitle(title, input.titleSource)?.trim();
212
+ if (clean) return clean;
213
+ }
214
+ for (const key of options.metadataKeys ?? []) {
215
+ const value = input.metadata?.[key];
216
+ if (typeof value === "string" && value.trim().length > 0) {
217
+ return value.trim();
218
+ }
219
+ }
220
+ return deriveAutomaticSessionTitlePreview(input.initialMessage) ?? automaticSessionReferenceTitle(input.id);
221
+ }
222
+
223
+ // ../contracts/src/session-list-entries.ts
224
+ function sessionListEntry(session) {
225
+ const origin = session.metadata._opengeniSiteOrigin;
226
+ const siteOrigin = origin && typeof origin.siteId === "string" && /^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/i.test(origin.siteId) && typeof origin.title === "string" ? { siteId: origin.siteId, title: origin.title } : null;
227
+ const scheduledTaskId = session.metadata.scheduledTaskId;
228
+ return {
229
+ id: session.id,
230
+ workspaceId: session.workspaceId,
231
+ accountId: session.accountId,
232
+ status: session.status,
233
+ backgroundCommandActivity: session.backgroundCommandActivity,
234
+ hasSchedules: session.hasSchedules,
235
+ title: session.title,
236
+ titleSource: session.titleSource,
237
+ displayTitle: deriveSessionDisplayTitle(session),
238
+ renameSeed: sessionTitleIsPending(session) ? deriveAutomaticSessionTitlePreview(session.initialMessage) ?? "" : session.title?.trim() ?? "",
239
+ scheduledTaskId: typeof scheduledTaskId === "string" && scheduledTaskId.length > 0 ? scheduledTaskId : null,
240
+ siteOrigin,
241
+ ...session.model ? { model: session.model } : {},
242
+ ...session.reasoningEffort ? { reasoningEffort: session.reasoningEffort } : {},
243
+ createdBy: session.createdBy,
244
+ channelId: session.channelId,
245
+ parentSessionId: session.parentSessionId,
246
+ rootSessionId: session.rootSessionId,
247
+ effectiveControl: session.effectiveControl,
248
+ inputWait: session.inputWait,
249
+ lastSequence: session.lastSequence,
250
+ pinned: session.pinned ?? false,
251
+ pinnedAt: session.pinnedAt ?? null,
252
+ pinVersion: session.pinVersion ?? 0,
253
+ unread: session.unread ?? false,
254
+ activelyWorking: session.activelyWorking ?? false,
255
+ attentionVersion: session.attentionVersion ?? 0,
256
+ archived: session.archived ?? false,
257
+ archivedAt: session.archivedAt ?? null,
258
+ importedArchive: session.importedArchive,
259
+ ...session.retention ? { retention: session.retention } : {},
260
+ archiveVersion: session.archiveVersion ?? 0,
261
+ treeStats: session.treeStats,
262
+ requiresActionSince: session.requiresActionSince,
263
+ // Lets lists tell a runtime-held session apart from one waiting on a person.
264
+ ...session.admissionBlock !== void 0 ? { admissionBlock: session.admissionBlock } : {},
265
+ createdAt: session.createdAt,
266
+ updatedAt: session.updatedAt
267
+ };
268
+ }
269
+
270
+ export {
271
+ AUTOMATIC_SESSION_TITLE_FALLBACK,
272
+ deriveAutomaticSessionTitlePreview,
273
+ sessionTitleIsPending,
274
+ deriveSessionDisplayTitle,
275
+ sessionListEntry
276
+ };
277
+ //# sourceMappingURL=chunk-ZDUBPV33.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../contracts/src/session-titles.ts","../../contracts/src/session-list-entries.ts"],"sourcesContent":["/** Human-authored session titles keep the existing public API ceiling. */\nexport const SESSION_TITLE_MAX_CHARACTERS = 200;\n\n/**\n * Automatic titles are intentionally much shorter than the manual rename\n * ceiling. This is measured in grapheme clusters so emoji and combining text\n * are never split into malformed display strings.\n */\nexport const AUTOMATIC_SESSION_TITLE_MAX_GRAPHEMES = 80;\n\n/**\n * Safe durable title used until semantic generation succeeds. It contains no\n * user prompt bytes, so provider failure/offline operation cannot leak a\n * credential or leave a raw prompt prefix in navigation surfaces.\n */\nexport const AUTOMATIC_SESSION_TITLE_FALLBACK = \"New conversation\";\n\n// Session creation accepts a body far larger than a navigation label. Bound\n// the source before any replace/split/normalization so a persisted large prompt\n// cannot amplify memory or CPU on every client render.\nexport const PROMPT_PREVIEW_SCAN_MAX_CODE_UNITS = 4_096;\n\nconst SESSION_ID_PATTERN =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;\n\nlet titleSegmenter: Intl.Segmenter | null | undefined;\n\nconst KNOWN_SENSITIVE_VALUE_PATTERNS = [\n /-----BEGIN [A-Z ]*PRIVATE KEY-----/iu,\n /\\bBearer\\s+[A-Za-z0-9._~+/=-]{8,}/iu,\n /\\b(?:sk-(?:proj-)?|gh[oprsu]_|github_pat_|glpat-|xox[baprs]-)[A-Za-z0-9_-]{8,}/iu,\n /\\bAKIA[0-9A-Z]{16}\\b/u,\n /\\bAIza[0-9A-Za-z_-]{20,}\\b/u,\n /\\beyJ[A-Za-z0-9_-]+\\.eyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\b/u,\n /[?&](?:access_token|api_key|apikey|password|secret|token)=[^\\s&#]+/iu,\n] as const;\n\nconst URI_SCHEME_CANDIDATE_PATTERN = /\\b[a-z][a-z0-9+.-]*:\\S+/giu;\nconst WINDOWS_DRIVE_PATH_PATTERN = /^[a-z]:[\\\\/](?![\\\\/])[^:]*$/iu;\n\nconst SCHEMELESS_HOST_CANDIDATE_PATTERN =\n /\\b(?:www\\.)?(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z](?:[a-z0-9-]{0,61}[a-z0-9])?(?::\\d{1,5})?(?:[/?#][^\\s]*)?/giu;\n\nconst SCHEMELESS_LOCAL_NETWORK_PATTERNS = [\n /\\blocalhost(?:(?::\\d{1,5})(?:[/?#][^\\s]*)?|[/?#][^\\s]*)/iu,\n /\\b(?:(?:25[0-5]|2[0-4]\\d|1?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|1?\\d?\\d)(?:(?::\\d{1,5})(?:[/?#][^\\s]*)?|[/?#][^\\s]*)/u,\n /\\[(?=[0-9a-f:.]*:[0-9a-f:.]*\\])[0-9a-f:.]+\\](?:(?::\\d{1,5})(?:[/?#][^\\s]*)?|[/?#][^\\s]*)/iu,\n] as const;\n\nconst FILE_LIKE_HOST_SUFFIXES = new Set([\n \"css\",\n \"html\",\n \"js\",\n \"json\",\n \"jsx\",\n \"lock\",\n \"md\",\n \"sql\",\n \"toml\",\n \"ts\",\n \"tsx\",\n \"xml\",\n \"yaml\",\n \"yml\",\n]);\n\n// These authorities are established framework/namespace notation whose exact\n// casing is meaningful. Keep this exception deliberately narrow: generic\n// PascalCase or uppercase authorities remain host-like because an uppercase\n// real domain (for example MICROSOFT.COM/Admin) must not bypass the URL gate.\nconst DOTTED_TECHNOLOGY_PATH_AUTHORITIES = new Set([\n \"ASP.NET\",\n \"AWS.SDK\",\n \"Microsoft.Extensions\",\n \"System.IO\",\n]);\n\nconst SECRET_ASSIGNMENT_CANDIDATE_PATTERN =\n /(?:^|[^A-Za-z0-9])(?:(['\"])([A-Za-z][A-Za-z0-9_. -]*)\\1|([A-Za-z][A-Za-z0-9_.-]*))\\s*[=:]\\s*[^\\s,;]+/gu;\n\nconst SECRET_LABEL_ASSIGNMENT_PATTERN =\n /\\b(?:api[ _-]?key|access[ _-]?token|auth[ _-]?token|credential|credentials|password|passwd|private[ _-]?key|secret|token)\\b\\s*[=:]\\s*[^\\s,;]+/iu;\n\nconst SENSITIVE_ASSIGNMENT_KEY_SUFFIXES = new Set([\n \"credential\",\n \"credentials\",\n \"password\",\n \"passwd\",\n \"secret\",\n \"token\",\n]);\n\nconst COMPACT_SENSITIVE_ASSIGNMENT_KEY_SUFFIXES = [\n \"apikey\",\n \"accesskey\",\n \"accesskeyid\",\n \"accesstoken\",\n \"authtoken\",\n \"credential\",\n \"credentials\",\n \"password\",\n \"passwd\",\n \"privatekey\",\n \"secret\",\n \"secretkey\",\n \"token\",\n] as const;\n\nconst SENSITIVE_ASSIGNMENT_KEY_WORD_SUFFIXES = [\n [\"api\", \"key\"],\n [\"access\", \"key\"],\n [\"access\", \"key\", \"id\"],\n [\"auth\", \"key\"],\n [\"private\", \"key\"],\n [\"secret\", \"key\"],\n] as const;\n\nfunction hasWordSuffix(words: readonly string[], suffix: readonly string[]): boolean {\n if (words.length < suffix.length) return false;\n const offset = words.length - suffix.length;\n return suffix.every((word, index) => words[offset + index] === word);\n}\n\nfunction containsSensitiveAssignment(value: string): boolean {\n for (const match of value.matchAll(SECRET_ASSIGNMENT_CANDIDATE_PATTERN)) {\n const key = match[2] ?? match[3];\n if (!key) continue;\n const words = key\n .replace(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n .replace(/([A-Z]+)([A-Z][a-z])/g, \"$1 $2\")\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter(Boolean);\n const last = words.at(-1);\n if (last && SENSITIVE_ASSIGNMENT_KEY_SUFFIXES.has(last)) return true;\n if (last && COMPACT_SENSITIVE_ASSIGNMENT_KEY_SUFFIXES.some((suffix) => last.endsWith(suffix))) {\n return true;\n }\n if (SENSITIVE_ASSIGNMENT_KEY_WORD_SUFFIXES.some((suffix) => hasWordSuffix(words, suffix))) {\n return true;\n }\n }\n return false;\n}\n\nfunction containsUriScheme(value: string): boolean {\n for (const match of value.matchAll(URI_SCHEME_CANDIDATE_PATTERN)) {\n // A Windows drive path is the one scheme-shaped token accepted here. Keep\n // the exception exact: one separator after the drive letter and no later\n // colon, so x://host and a nested scheme remain rejected.\n if (!WINDOWS_DRIVE_PATH_PATTERN.test(match[0])) return true;\n }\n return false;\n}\n\nfunction isDottedTechnologyPath(candidate: string): boolean {\n if (/[?:#]/u.test(candidate)) return false;\n const [authority, ...pathSegments] = candidate.split(\"/\");\n if (!authority || pathSegments.length === 0 || pathSegments.some((segment) => !segment)) {\n return false;\n }\n if (\n !DOTTED_TECHNOLOGY_PATH_AUTHORITIES.has(authority) ||\n pathSegments.some((segment) => !/^[A-Z][A-Za-z0-9_-]*$/u.test(segment))\n ) {\n return false;\n }\n return true;\n}\n\nfunction containsSchemelessUrl(value: string): boolean {\n if (SCHEMELESS_LOCAL_NETWORK_PATTERNS.some((pattern) => pattern.test(value))) return true;\n\n for (const match of value.matchAll(SCHEMELESS_HOST_CANDIDATE_PATTERN)) {\n const candidate = match[0];\n if (candidate.toLowerCase().startsWith(\"www.\")) return true;\n if (!/[/?#]/u.test(candidate)) continue;\n\n const authority = candidate.split(/[/?#]/u, 1)[0] ?? \"\";\n const hostname = authority.replace(/:\\d{1,5}$/u, \"\");\n const suffix = hostname.split(\".\").at(-1)?.toLowerCase();\n if (suffix && FILE_LIKE_HOST_SUFFIXES.has(suffix)) continue;\n if (isDottedTechnologyPath(candidate)) continue;\n return true;\n }\n return false;\n}\n\nconst OPAQUE_IDENTIFIER_PATTERN =\n /\\b(?=[A-Za-z0-9_-]{32,}\\b)(?=[A-Za-z0-9_-]*[A-Za-z])(?=[A-Za-z0-9_-]*\\d)[A-Za-z0-9_-]+\\b/u;\n\nconst DEFAULT_IGNORABLE_CODE_POINTS = /\\p{Default_Ignorable_Code_Point}+/gu;\nconst ESCAPED_QUOTE_DELIMITERS = /\\\\+(?=[\"'])/gu;\n\nconst TITLE_LABEL_PATTERN =\n /^(?:(?:suggested|generated|concise)\\s+)?(?:(?:session|chat|conversation|task)\\s+)?title\\s*[:\\-–—]\\s*/iu;\n\nconst LEADING_BOILERPLATE_PATTERNS = [\n /^(?:hi|hello|hey)(?:\\s+there)?\\s*[,!:.\\-–—]*\\s*/iu,\n /^(?:i\\s+(?:would\\s+like|want|need)\\s+you\\s+to|i['’]d\\s+like\\s+you\\s+to)\\s+/iu,\n /^(?:please\\s+)?(?:can|could|would|will)\\s+you\\s+/iu,\n /^(?:your|the)\\s+(?:task|job)\\s+is\\s+to\\s+/iu,\n /^(?:please\\s+)?help\\s+me\\s+(?:to\\s+)?/iu,\n /^please(?:\\s*[,!:.\\-–—]+\\s*|\\s+|$)/iu,\n] as const;\n\nfunction automaticTitleDetectionValue(value: string): string {\n // Detection uses a compatibility-normalized shadow value so fullwidth\n // punctuation/letters, invisible token splits, and serialized quote\n // delimiters cannot evade the policy.\n // The accepted title itself stays byte-for-byte in the user's language and\n // emoji form; this shadow is never returned or persisted.\n return value\n .normalize(\"NFKC\")\n .replace(DEFAULT_IGNORABLE_CODE_POINTS, \"\")\n .replace(ESCAPED_QUOTE_DELIMITERS, \"\");\n}\n\nfunction hasVisibleAutomaticTitleContent(value: string): boolean {\n return automaticTitleDetectionValue(value).trim().length > 0;\n}\n\n/**\n * Whether a bounded automatic-title candidate contains a credential, URL, or\n * opaque identifier that must stay out of navigation and other display-title\n * surfaces. Callers handling an unbounded source must bound it before invoking\n * this helper.\n */\nexport function containsSensitiveAutomaticSessionTitleValue(value: string): boolean {\n const detectionValue = automaticTitleDetectionValue(value);\n\n if (KNOWN_SENSITIVE_VALUE_PATTERNS.some((pattern) => pattern.test(detectionValue))) return true;\n if (containsUriScheme(detectionValue)) return true;\n if (containsSchemelessUrl(detectionValue)) return true;\n if (SECRET_LABEL_ASSIGNMENT_PATTERN.test(detectionValue)) return true;\n if (containsSensitiveAssignment(detectionValue)) return true;\n if (OPAQUE_IDENTIFIER_PATTERN.test(detectionValue)) return true;\n return false;\n}\n\nfunction stripAutomaticTitleBoilerplate(value: string): string {\n let title = value;\n for (let pass = 0; pass < 4; pass += 1) {\n const before = title;\n title = title\n .replace(/^(?:```[^\\n]*|[\\s#>*_`\"'“”‘’\\-–—]+)+/u, \"\")\n .replace(TITLE_LABEL_PATTERN, \"\");\n for (const pattern of LEADING_BOILERPLATE_PATTERNS) {\n title = title.replace(pattern, \"\");\n }\n title = title.trim();\n if (title === before) break;\n }\n return title;\n}\n\nconst AUTOMATIC_TITLE_TRAILING_PUNCTUATION = /[\\s.!?,;:\\-–—]+$/u;\n\n// Closing quote and markdown marks, mapped to the distinct opening mark that\n// would pair with them inside the title.\nconst TRAILING_WRAPPER_MARKS = new Map<string, string | null>([\n ['\"', null],\n [\"'\", null],\n [\"`\", null],\n [\"*\", null],\n [\"”\", \"“\"],\n [\"’\", \"‘\"],\n [\"»\", \"«\"],\n]);\n\n/**\n * Remove trailing punctuation and a closing quote or markdown mark whose\n * opening counterpart was already stripped as a leading wrapper, so\n * `\"Pod Crash Debugging\"` and `**Pod Crash Debugging**` do not keep a dangling\n * closing mark. A mark that still pairs with one inside the title stays.\n */\nfunction trimAutomaticTitleEnd(value: string): string {\n let title = value;\n for (let pass = 0; pass < 4; pass += 1) {\n const before = title;\n title = title.replace(AUTOMATIC_TITLE_TRAILING_PUNCTUATION, \"\");\n const last = title.at(-1);\n const opening = last === undefined ? undefined : TRAILING_WRAPPER_MARKS.get(last);\n if (last !== undefined && opening !== undefined) {\n let rest = title;\n while (rest.endsWith(last)) rest = rest.slice(0, -last.length);\n if (!rest.includes(last) && (opening === null || !rest.includes(opening))) {\n title = rest;\n }\n }\n if (title === before) break;\n }\n return title.trim();\n}\n\nfunction automaticTitleGraphemes(value: string): string[] {\n if (titleSegmenter === undefined) {\n titleSegmenter =\n typeof Intl.Segmenter === \"function\"\n ? new Intl.Segmenter(undefined, { granularity: \"grapheme\" })\n : null;\n }\n if (titleSegmenter) {\n return Array.from(titleSegmenter.segment(value), (part) => part.segment);\n }\n\n // Older embedded runtimes may not ship Intl.Segmenter. Preserve surrogate\n // pairs plus common combining/emoji sequences instead of failing module load\n // or slicing UTF-16 code units.\n const graphemes: string[] = [];\n for (const point of value) {\n const prior = graphemes.at(-1);\n if (\n prior &&\n (/^[\\p{Mark}\\u{FE0E}\\u{FE0F}\\p{Emoji_Modifier}]$/u.test(point) ||\n point === \"\\u200d\" ||\n prior.endsWith(\"\\u200d\"))\n ) {\n graphemes[graphemes.length - 1] = `${prior}${point}`;\n } else {\n graphemes.push(point);\n }\n }\n return graphemes;\n}\n\n/**\n * Model control tokens such as `<|fim_suffix|>`, `<|im_end|>` or `<|end▁of▁sentence|>`\n * sometimes leak into generated text. They are never title content: each one\n * becomes a line break, so a title keeps only its first real segment.\n */\nconst MODEL_CONTROL_TOKEN = /<[||][^<>||\\s]{1,64}[||]>/gu;\n\nfunction withoutModelControlTokens(value: string): string {\n return value.replace(MODEL_CONTROL_TOKEN, \"\\n\");\n}\n\n/**\n * Read-side cleanup for a durable title. Automatic titles written before\n * control-token stripping can still hold a token (\"Release plan<|fim_suffix|>\");\n * those keep only their first real segment, and a token-only title reads as no\n * title. Human renames and titles without a token are returned unchanged.\n */\nexport function cleanStoredSessionTitle(\n title: string | null | undefined,\n titleSource: string | null | undefined,\n): string | null {\n if (title === null || title === undefined) return null;\n if (titleSource === \"user\") return title;\n const stripped = withoutModelControlTokens(title);\n if (stripped === title) return title;\n return (\n stripped\n .split(\"\\n\")\n .map((part) => part.trim())\n .find(Boolean) ?? null\n );\n}\n\n/** Bound an already-normalized automatic-title candidate without splitting graphemes. */\nexport function boundAutomaticSessionTitle(value: string): string {\n const words = value.split(/\\s+/u);\n const wordBounded = words.length > 10 ? words.slice(0, 10).join(\" \") : value;\n const graphemes = automaticTitleGraphemes(wordBounded);\n if (graphemes.length <= AUTOMATIC_SESSION_TITLE_MAX_GRAPHEMES) return wordBounded;\n\n const prefix = graphemes.slice(0, AUTOMATIC_SESSION_TITLE_MAX_GRAPHEMES).join(\"\");\n const lastWhitespace = prefix.search(/\\s+\\S*$/u);\n return (lastWhitespace >= 16 ? prefix.slice(0, lastWhitespace) : prefix).trimEnd();\n}\n\n/**\n * Normalize a model/system-authored title before it reaches durable session\n * metadata. Human renames intentionally do not use this path.\n *\n * Returns null when the candidate is empty, only boilerplate, or appears to\n * contain a credential/opaque prompt value. Callers should retain the current\n * title (normally {@link AUTOMATIC_SESSION_TITLE_FALLBACK}) in that case.\n */\nexport function normalizeAutomaticSessionTitle(value: string): string | null {\n const firstLine = withoutModelControlTokens(value)\n .replace(/[\\u0000-\\u001f\\u007f-\\u009f]+/gu, \"\\n\")\n .split(/\\n+/u)\n .map((line) => line.trim())\n .find(Boolean);\n if (\n !firstLine ||\n !hasVisibleAutomaticTitleContent(firstLine) ||\n containsSensitiveAutomaticSessionTitleValue(firstLine)\n ) {\n return null;\n }\n\n let title = trimAutomaticTitleEnd(\n stripAutomaticTitleBoilerplate(firstLine).replace(/\\s+/gu, \" \"),\n );\n if (\n !title ||\n !hasVisibleAutomaticTitleContent(title) ||\n containsSensitiveAutomaticSessionTitleValue(title)\n ) {\n return null;\n }\n\n title = trimAutomaticTitleEnd(boundAutomaticSessionTitle(title));\n if (!title || !hasVisibleAutomaticTitleContent(title)) return null;\n return title;\n}\n\nexport type SessionDisplayTitleInput = {\n id?: string | null | undefined;\n title?: string | null | undefined;\n titleSource?: \"user\" | \"agent\" | null | undefined;\n initialMessage?: string | null | undefined;\n metadata?: Readonly<Record<string, unknown>> | undefined;\n};\n\nexport type SessionDisplayTitleOptions = {\n /** Optional metadata fields to try before the opening-prompt preview. */\n metadataKeys?: readonly string[] | undefined;\n};\n\n/**\n * Derive a bounded, sensitive-safe preview from the opening prompt.\n *\n * Unsafe leading lines are skipped instead of forcing the whole session back\n * to a generic label. This covers prompts that begin with a pasted URL or\n * identifier followed by an ordinary natural-language request on the next\n * line, without putting the rejected value into navigation surfaces.\n */\nexport function deriveAutomaticSessionTitlePreview(value: unknown): string | null {\n if (typeof value !== \"string\") return null;\n\n const lines = value\n .slice(0, PROMPT_PREVIEW_SCAN_MAX_CODE_UNITS)\n .replace(/[\\u0000-\\u001f\\u007f-\\u009f]+/gu, \"\\n\")\n .split(/\\n+/u);\n\n for (const candidate of lines) {\n const line = candidate.trim();\n if (!line || containsSensitiveAutomaticSessionTitleValue(line)) continue;\n\n const preview = boundAutomaticSessionTitle(line.replace(/\\s+/gu, \" \"))\n .replace(/[\\s.!?,;:\\-–—]+$/u, \"\")\n .trim();\n if (preview) return preview;\n }\n\n return null;\n}\n\nfunction automaticSessionReferenceTitle(id: unknown): string {\n const sessionId = typeof id === \"string\" ? id.trim() : \"\";\n return SESSION_ID_PATTERN.test(sessionId)\n ? `Conversation ${sessionId.slice(0, 13)}`\n : AUTOMATIC_SESSION_TITLE_FALLBACK;\n}\n\n/**\n * Whether the durable title still represents the automatic-title pending state.\n * A user-authored title always wins, even when its literal value is the marker.\n */\nexport function sessionTitleIsPending(input: SessionDisplayTitleInput): boolean {\n const title = input.title?.trim() ?? \"\";\n return input.titleSource !== \"user\" && (!title || title === AUTOMATIC_SESSION_TITLE_FALLBACK);\n}\n\n/**\n * Derive the title a human-facing client should display for a session.\n *\n * A semantic agent title or human rename wins. While automatic naming is still\n * pending, clients show a short, sensitive-safe preview of the opening prompt.\n * If no safe prompt text exists, a UUID-derived reference keeps real sessions\n * distinguishable without exposing prompt bytes. The durable pending marker is\n * therefore an internal lifecycle value rather than the ordinary visible name.\n */\nexport function deriveSessionDisplayTitle(\n input: SessionDisplayTitleInput,\n options: SessionDisplayTitleOptions = {},\n): string {\n const title = input.title?.trim() ?? \"\";\n if (input.titleSource === \"user\") {\n return title || automaticSessionReferenceTitle(input.id);\n }\n if (title && !sessionTitleIsPending(input)) {\n const clean = cleanStoredSessionTitle(title, input.titleSource)?.trim();\n if (clean) return clean;\n }\n\n for (const key of options.metadataKeys ?? []) {\n const value = input.metadata?.[key];\n if (typeof value === \"string\" && value.trim().length > 0) {\n return value.trim();\n }\n }\n\n return (\n deriveAutomaticSessionTitlePreview(input.initialMessage) ??\n automaticSessionReferenceTitle(input.id)\n );\n}\n","import type { Session, SessionListEntry } from \"./index\";\nimport {\n deriveAutomaticSessionTitlePreview,\n deriveSessionDisplayTitle,\n sessionTitleIsPending,\n} from \"./session-titles\";\n\n/** Explicit list projection. Detail/configuration remains available from getSession. */\nexport type SessionListEntryInput = Omit<\n SessionListEntry,\n | \"displayTitle\"\n | \"renameSeed\"\n | \"scheduledTaskId\"\n | \"siteOrigin\"\n | \"pinned\"\n | \"pinnedAt\"\n | \"pinVersion\"\n | \"unread\"\n | \"activelyWorking\"\n | \"attentionVersion\"\n | \"archived\"\n | \"archivedAt\"\n | \"archiveVersion\"\n> &\n Partial<\n Pick<\n Session,\n | \"pinned\"\n | \"pinnedAt\"\n | \"pinVersion\"\n | \"unread\"\n | \"activelyWorking\"\n | \"attentionVersion\"\n | \"archived\"\n | \"archivedAt\"\n | \"archiveVersion\"\n >\n > &\n Pick<Session, \"metadata\" | \"initialMessage\">;\n\nexport function sessionListEntry(session: SessionListEntryInput): SessionListEntry {\n const origin = session.metadata._opengeniSiteOrigin as\n | { siteId?: unknown; title?: unknown }\n | undefined;\n const siteOrigin =\n origin &&\n typeof origin.siteId === \"string\" &&\n /^[\\da-f]{8}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{12}$/i.test(origin.siteId) &&\n typeof origin.title === \"string\"\n ? { siteId: origin.siteId, title: origin.title }\n : null;\n const scheduledTaskId = session.metadata.scheduledTaskId;\n return {\n id: session.id,\n workspaceId: session.workspaceId,\n accountId: session.accountId,\n status: session.status,\n backgroundCommandActivity: session.backgroundCommandActivity,\n hasSchedules: session.hasSchedules,\n title: session.title,\n titleSource: session.titleSource,\n displayTitle: deriveSessionDisplayTitle(session),\n renameSeed: sessionTitleIsPending(session)\n ? (deriveAutomaticSessionTitlePreview(session.initialMessage) ?? \"\")\n : (session.title?.trim() ?? \"\"),\n scheduledTaskId:\n typeof scheduledTaskId === \"string\" && scheduledTaskId.length > 0 ? scheduledTaskId : null,\n siteOrigin,\n ...(session.model ? { model: session.model } : {}),\n ...(session.reasoningEffort ? { reasoningEffort: session.reasoningEffort } : {}),\n createdBy: session.createdBy,\n channelId: session.channelId,\n parentSessionId: session.parentSessionId,\n rootSessionId: session.rootSessionId,\n effectiveControl: session.effectiveControl,\n inputWait: session.inputWait,\n lastSequence: session.lastSequence,\n pinned: session.pinned ?? false,\n pinnedAt: session.pinnedAt ?? null,\n pinVersion: session.pinVersion ?? 0,\n unread: session.unread ?? false,\n activelyWorking: session.activelyWorking ?? false,\n attentionVersion: session.attentionVersion ?? 0,\n archived: session.archived ?? false,\n archivedAt: session.archivedAt ?? null,\n importedArchive: session.importedArchive,\n ...(session.retention ? { retention: session.retention } : {}),\n archiveVersion: session.archiveVersion ?? 0,\n treeStats: session.treeStats,\n requiresActionSince: session.requiresActionSince,\n // Lets lists tell a runtime-held session apart from one waiting on a person.\n ...(session.admissionBlock !== undefined ? { admissionBlock: session.admissionBlock } : {}),\n createdAt: session.createdAt,\n updatedAt: session.updatedAt,\n };\n}\n"],"mappings":"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","names":[]}