@opengeni/sdk 0.57.0 → 1.0.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 (291) hide show
  1. package/README.md +1017 -26
  2. package/dist/accounts.d.ts +153 -0
  3. package/dist/accounts.js +307 -0
  4. package/dist/accounts.js.map +1 -0
  5. package/dist/adapters/express.d.ts +31 -0
  6. package/dist/adapters/express.js +87 -0
  7. package/dist/adapters/express.js.map +1 -0
  8. package/dist/adapters/hono.d.ts +16 -0
  9. package/dist/adapters/hono.js +8 -0
  10. package/dist/adapters/hono.js.map +1 -0
  11. package/dist/adapters/next.d.ts +29 -0
  12. package/dist/adapters/next.js +22 -0
  13. package/dist/adapters/next.js.map +1 -0
  14. package/dist/allowance-refusal.d.ts +2 -0
  15. package/dist/allowance-refusal.js +50 -0
  16. package/dist/allowance-refusal.js.map +1 -0
  17. package/dist/artifact-catalog.d.ts +31 -0
  18. package/dist/artifact-client.d.ts +23 -11
  19. package/dist/artifacts.d.ts +1 -1
  20. package/dist/artifacts.js +7 -5
  21. package/dist/automations-client.d.ts +17 -0
  22. package/dist/automations.d.ts +3 -0
  23. package/dist/automations.js +84 -0
  24. package/dist/automations.js.map +1 -0
  25. package/dist/browser.d.ts +11 -0
  26. package/dist/browser.js +47 -0
  27. package/dist/browser.js.map +1 -0
  28. package/dist/chat/fold.d.ts +75 -0
  29. package/dist/chat/handler.d.ts +41 -0
  30. package/dist/chat/http.d.ts +67 -0
  31. package/dist/chat/ids.d.ts +34 -0
  32. package/dist/chat/index.d.ts +9 -0
  33. package/dist/chat/index.js +1694 -0
  34. package/dist/chat/index.js.map +1 -0
  35. package/dist/chat/openai.d.ts +30 -0
  36. package/dist/chat/opengeni.d.ts +128 -0
  37. package/dist/chat/types.d.ts +207 -0
  38. package/dist/chat/vercel.d.ts +49 -0
  39. package/dist/chats.d.ts +8 -0
  40. package/dist/{chunk-JDLDDRNE.js → chunk-2UXZUCEZ.js} +291 -34
  41. package/dist/chunk-2UXZUCEZ.js.map +1 -0
  42. package/dist/chunk-4SMEOV3P.js +246 -0
  43. package/dist/chunk-4SMEOV3P.js.map +1 -0
  44. package/dist/{chunk-JRPFWI6T.js → chunk-AH5D5Q5V.js} +31 -35
  45. package/dist/chunk-AH5D5Q5V.js.map +1 -0
  46. package/dist/chunk-APXVSSSY.js +301 -0
  47. package/dist/chunk-APXVSSSY.js.map +1 -0
  48. package/dist/chunk-DUVIYER4.js +639 -0
  49. package/dist/chunk-DUVIYER4.js.map +1 -0
  50. package/dist/{chunk-PKQ377ED.js → chunk-FG3OO5LM.js} +2686 -611
  51. package/dist/chunk-FG3OO5LM.js.map +1 -0
  52. package/dist/chunk-GZYZT22T.js +260 -0
  53. package/dist/chunk-GZYZT22T.js.map +1 -0
  54. package/dist/chunk-HMGADJGZ.js +150 -0
  55. package/dist/chunk-HMGADJGZ.js.map +1 -0
  56. package/dist/{chunk-YKZME56C.js → chunk-KWADQ227.js} +3 -3
  57. package/dist/{chunk-YKZME56C.js.map → chunk-KWADQ227.js.map} +1 -1
  58. package/dist/chunk-LY2K6ELJ.js +126 -0
  59. package/dist/chunk-LY2K6ELJ.js.map +1 -0
  60. package/dist/chunk-MOTJYIYL.js +340 -0
  61. package/dist/chunk-MOTJYIYL.js.map +1 -0
  62. package/dist/{chunk-ST5DDKJP.js → chunk-NC57YMUO.js} +121 -3
  63. package/dist/chunk-NC57YMUO.js.map +1 -0
  64. package/dist/chunk-RWKB6YZG.js +1270 -0
  65. package/dist/chunk-RWKB6YZG.js.map +1 -0
  66. package/dist/chunk-U6CV2SXO.js +195 -0
  67. package/dist/chunk-U6CV2SXO.js.map +1 -0
  68. package/dist/chunk-UM4ZXXJR.js +9 -0
  69. package/dist/chunk-UM4ZXXJR.js.map +1 -0
  70. package/dist/chunk-V6GIY62B.js +229 -0
  71. package/dist/chunk-V6GIY62B.js.map +1 -0
  72. package/dist/chunk-WU6GQG25.js +268 -0
  73. package/dist/chunk-WU6GQG25.js.map +1 -0
  74. package/dist/{chunk-VWE2QIVO.js → chunk-XNG7YGR3.js} +23 -6
  75. package/dist/chunk-XNG7YGR3.js.map +1 -0
  76. package/dist/{chunk-HJ3HHUT5.js → chunk-YIKA2QT4.js} +33 -2
  77. package/dist/chunk-YIKA2QT4.js.map +1 -0
  78. package/dist/chunk-ZKPY6YAJ.js +135 -0
  79. package/dist/chunk-ZKPY6YAJ.js.map +1 -0
  80. package/dist/client.d.ts +740 -94
  81. package/dist/codex-realtime-controller.d.ts +3 -0
  82. package/dist/codex-realtime-controller.js +2 -2
  83. package/dist/codex-realtime-v3.d.ts +13 -2
  84. package/dist/company-brain.d.ts +22 -0
  85. package/dist/company-profile.d.ts +14 -1
  86. package/dist/core.d.ts +9 -3
  87. package/dist/core.js +25 -6
  88. package/dist/deprecation.d.ts +47 -0
  89. package/dist/document-authority-client.d.ts +51 -0
  90. package/dist/document-authority.d.ts +2 -0
  91. package/dist/document-authority.js +12 -0
  92. package/dist/document-authority.js.map +1 -0
  93. package/dist/editable-artifacts/browser-session.d.ts +7 -3
  94. package/dist/editable-artifacts/controller.d.ts +4 -1
  95. package/dist/editable-artifacts/errors.d.ts +1 -1
  96. package/dist/editable-artifacts/http-live-transport.d.ts +6 -2
  97. package/dist/editable-artifacts/index.d.ts +2 -0
  98. package/dist/editable-artifacts/open-failure.d.ts +9 -0
  99. package/dist/editable-artifacts/types.d.ts +6 -3
  100. package/dist/editable-artifacts/worker/kernel-adapter.d.ts +1 -1
  101. package/dist/editable-artifacts-worker.js +44 -17
  102. package/dist/editable-artifacts-worker.js.map +1 -1
  103. package/dist/editable-artifacts.js +240 -121
  104. package/dist/editable-artifacts.js.map +1 -1
  105. package/dist/embedding-client.d.ts +129 -0
  106. package/dist/errors.d.ts +36 -1
  107. package/dist/feedback.d.ts +23 -0
  108. package/dist/gateway-realtime-transport.js +1 -1
  109. package/dist/github-repositories.d.ts +10 -0
  110. package/dist/github-repositories.js +36 -0
  111. package/dist/github-repositories.js.map +1 -0
  112. package/dist/index.d.ts +56 -11
  113. package/dist/index.js +242 -125
  114. package/dist/index.js.map +1 -1
  115. package/dist/interaction.d.ts +84 -1
  116. package/dist/interaction.js +6 -1
  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/message-links.d.ts +68 -0
  121. package/dist/model-context.d.ts +68 -0
  122. package/dist/model-display.d.ts +2 -0
  123. package/dist/model-display.js +15 -0
  124. package/dist/model-display.js.map +1 -0
  125. package/dist/model-picker-order.d.ts +1 -0
  126. package/dist/model-picker-order.js +10 -0
  127. package/dist/model-picker-order.js.map +1 -0
  128. package/dist/organization-integration-policy.d.ts +26 -0
  129. package/dist/organization-integration-policy.js +26 -0
  130. package/dist/organization-integration-policy.js.map +1 -0
  131. package/dist/organization-private-session-settings.d.ts +6 -0
  132. package/dist/organization-private-session-settings.js +22 -0
  133. package/dist/organization-private-session-settings.js.map +1 -0
  134. package/dist/organization-user-setup.d.ts +8 -0
  135. package/dist/organization-user-setup.js +16 -0
  136. package/dist/organization-user-setup.js.map +1 -0
  137. package/dist/pr-review-client.d.ts +16 -0
  138. package/dist/pr-review.d.ts +4 -0
  139. package/dist/pr-review.js +62 -0
  140. package/dist/pr-review.js.map +1 -0
  141. package/dist/preference-registry.d.ts +9 -1
  142. package/dist/proxy.d.ts +7 -5
  143. package/dist/realtime.d.ts +3 -1
  144. package/dist/realtime.js +6 -6
  145. package/dist/realtime.js.map +1 -1
  146. package/dist/retained-artifacts.d.ts +5 -1
  147. package/dist/session-history-import.d.ts +22 -0
  148. package/dist/session-history-import.js +36 -0
  149. package/dist/session-history-import.js.map +1 -0
  150. package/dist/session-list-entries.d.ts +1 -0
  151. package/dist/session-list-entries.js +7 -0
  152. package/dist/session-list-entries.js.map +1 -0
  153. package/dist/session-message-search.d.ts +53 -0
  154. package/dist/session-proxy-client.d.ts +24 -0
  155. package/dist/session-proxy.d.ts +245 -0
  156. package/dist/session-proxy.js +24 -0
  157. package/dist/session-proxy.js.map +1 -0
  158. package/dist/session-titles.d.ts +2 -0
  159. package/dist/site-browser-entry.d.ts +1 -0
  160. package/dist/site-browser-runtime.gen.d.ts +1 -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 +16 -0
  166. package/dist/site-tool-bridge.d.ts +44 -0
  167. package/dist/site.d.ts +101 -0
  168. package/dist/site.js +49 -0
  169. package/dist/site.js.map +1 -0
  170. package/dist/skills.d.ts +75 -0
  171. package/dist/stream.d.ts +2 -0
  172. package/dist/tenant-workspaces.d.ts +47 -0
  173. package/dist/tenant-workspaces.js +8 -0
  174. package/dist/tenant-workspaces.js.map +1 -0
  175. package/dist/tool-auth.d.ts +87 -0
  176. package/dist/tool-auth.js +23 -0
  177. package/dist/tool-auth.js.map +1 -0
  178. package/dist/tool-display-metadata.d.ts +3 -0
  179. package/dist/tools-FXBLUWAE.js +12 -0
  180. package/dist/tools-FXBLUWAE.js.map +1 -0
  181. package/dist/tools.d.ts +61 -0
  182. package/dist/types.d.ts +2863 -424
  183. package/dist/usage-allowances.d.ts +36 -0
  184. package/dist/usage-allowances.js +80 -0
  185. package/dist/usage-allowances.js.map +1 -0
  186. package/dist/workspace-artifacts.d.ts +33 -5
  187. package/dist/workspace-instruction-policies.d.ts +24 -2
  188. package/dist/workspace-integrations.d.ts +74 -0
  189. package/dist/workspace-integrations.js +65 -0
  190. package/dist/workspace-integrations.js.map +1 -0
  191. package/dist/workspace-learning.d.ts +124 -0
  192. package/dist/workspace-state.d.ts +8 -71
  193. package/package.json +108 -3
  194. package/src/accounts.ts +443 -0
  195. package/src/adapters/express.ts +136 -0
  196. package/src/adapters/hono.ts +18 -0
  197. package/src/adapters/next.ts +42 -0
  198. package/src/allowance-refusal.ts +5 -0
  199. package/src/artifact-catalog.ts +41 -0
  200. package/src/artifact-client.ts +43 -52
  201. package/src/artifacts.ts +7 -1
  202. package/src/automations-client.ts +124 -0
  203. package/src/automations.ts +15 -0
  204. package/src/browser.ts +54 -0
  205. package/src/chat/fold.ts +431 -0
  206. package/src/chat/handler.ts +240 -0
  207. package/src/chat/http.ts +257 -0
  208. package/src/chat/ids.ts +85 -0
  209. package/src/chat/index.ts +87 -0
  210. package/src/chat/openai.ts +439 -0
  211. package/src/chat/opengeni.ts +722 -0
  212. package/src/chat/types.ts +219 -0
  213. package/src/chat/vercel.ts +204 -0
  214. package/src/chats.ts +16 -0
  215. package/src/client.ts +4084 -515
  216. package/src/codex-realtime-controller.ts +235 -5
  217. package/src/codex-realtime-v3.ts +162 -31
  218. package/src/codex-realtime.ts +1 -1
  219. package/src/company-brain.ts +59 -0
  220. package/src/company-profile.ts +17 -1
  221. package/src/core.ts +23 -1
  222. package/src/deprecation.ts +149 -0
  223. package/src/document-authority-client.ts +219 -0
  224. package/src/document-authority.ts +17 -0
  225. package/src/editable-artifacts/browser-session.ts +36 -22
  226. package/src/editable-artifacts/controller.ts +102 -47
  227. package/src/editable-artifacts/errors.ts +2 -0
  228. package/src/editable-artifacts/http-live-transport.ts +62 -37
  229. package/src/editable-artifacts/index.ts +6 -0
  230. package/src/editable-artifacts/open-failure.ts +79 -0
  231. package/src/editable-artifacts/storage.ts +31 -40
  232. package/src/editable-artifacts/types.ts +6 -3
  233. package/src/editable-artifacts/worker/kernel-adapter.ts +23 -7
  234. package/src/editable-artifacts/worker/runtime.ts +26 -13
  235. package/src/editable-artifacts/worker/wire-codec.ts +23 -5
  236. package/src/embedding-client.ts +519 -0
  237. package/src/errors.ts +169 -2
  238. package/src/feedback.ts +20 -0
  239. package/src/gateway-realtime-transport.ts +3 -3
  240. package/src/github-repositories.ts +60 -0
  241. package/src/index.ts +561 -41
  242. package/src/interaction.ts +276 -4
  243. package/src/knowledge.ts +72 -0
  244. package/src/message-links.ts +178 -0
  245. package/src/model-context.ts +112 -0
  246. package/src/model-display.ts +10 -0
  247. package/src/model-picker-order.ts +6 -0
  248. package/src/organization-integration-policy.ts +54 -0
  249. package/src/organization-private-session-settings.ts +33 -0
  250. package/src/organization-user-setup.ts +31 -0
  251. package/src/pr-review-client.ts +92 -0
  252. package/src/pr-review.ts +17 -0
  253. package/src/preference-registry.ts +11 -0
  254. package/src/proxy.ts +17 -6
  255. package/src/realtime.ts +1 -0
  256. package/src/retained-artifacts.ts +101 -0
  257. package/src/session-history-import.ts +84 -0
  258. package/src/session-list-entries.ts +1 -0
  259. package/src/session-message-search.ts +47 -0
  260. package/src/session-proxy-client.ts +64 -0
  261. package/src/session-proxy.ts +1473 -0
  262. package/src/session-titles.ts +10 -0
  263. package/src/site-browser-entry.ts +6 -0
  264. package/src/site-browser-runtime.gen.ts +2 -0
  265. package/src/site-document.test.ts +64 -0
  266. package/src/site-document.ts +18 -0
  267. package/src/site-http.ts +162 -0
  268. package/src/site-tool-bridge.ts +146 -0
  269. package/src/site.ts +585 -0
  270. package/src/skills.ts +69 -0
  271. package/src/sse.ts +8 -2
  272. package/src/stream.ts +38 -4
  273. package/src/tenant-workspaces.ts +148 -0
  274. package/src/tool-auth.ts +301 -0
  275. package/src/tool-display-metadata.ts +19 -0
  276. package/src/tools.ts +396 -0
  277. package/src/types.ts +3346 -501
  278. package/src/usage-allowances.ts +189 -0
  279. package/src/workspace-artifacts.ts +40 -6
  280. package/src/workspace-instruction-policies.ts +26 -1
  281. package/src/workspace-integrations.ts +402 -0
  282. package/src/workspace-learning.ts +138 -0
  283. package/src/workspace-state.ts +8 -82
  284. package/dist/chunk-GU6JF75T.js +0 -119
  285. package/dist/chunk-GU6JF75T.js.map +0 -1
  286. package/dist/chunk-HJ3HHUT5.js.map +0 -1
  287. package/dist/chunk-JDLDDRNE.js.map +0 -1
  288. package/dist/chunk-JRPFWI6T.js.map +0 -1
  289. package/dist/chunk-PKQ377ED.js.map +0 -1
  290. package/dist/chunk-ST5DDKJP.js.map +0 -1
  291. package/dist/chunk-VWE2QIVO.js.map +0 -1
package/src/site.ts ADDED
@@ -0,0 +1,585 @@
1
+ export { createSiteToolBridge, isSiteCatalogStaleError } from "./site-tool-bridge";
2
+ export type {
3
+ SiteToolBridge,
4
+ SiteToolCaller,
5
+ SiteToolCallRequest,
6
+ CreateSiteToolBridgeOptions,
7
+ } from "./site-tool-bridge";
8
+ import {
9
+ OpenGeniToolsClient,
10
+ type OpenGeniToolTransport,
11
+ type OpenGeniWorkspaceTools,
12
+ } from "./tools";
13
+ import { OpenGeniClient } from "./client";
14
+ import { sitePortFetch, siteSessionPath, SITE_WORKSPACE } from "./site-http";
15
+ export {
16
+ isSiteHttpRequest,
17
+ serveSiteHttp,
18
+ siteSessionPath,
19
+ type SiteHttpRequest,
20
+ } from "./site-http";
21
+ import type {
22
+ ToolGatewayCallRequest,
23
+ ToolGatewayCallResponse,
24
+ ToolGatewayCatalog,
25
+ ToolGatewayDeclarationsResponse,
26
+ } from "./types";
27
+
28
+ export const OPENGENI_SITE_BRIDGE_VERSION = 2 as const;
29
+ export const OPENGENI_SITE_BRIDGE_CONNECT = "opengeni.site.connect" as const;
30
+ export const OPENGENI_SITE_BRIDGE_READY = "opengeni.site.ready" as const;
31
+ export const OPENGENI_SITE_BRIDGE_REQUEST = "opengeni.site.request" as const;
32
+ export const OPENGENI_SITE_BRIDGE_RESPONSE = "opengeni.site.response" as const;
33
+ export const OPENGENI_SITE_BRIDGE_CANCEL = "opengeni.site.cancel" as const;
34
+ export const OPENGENI_SITE_BRIDGE_BOOTSTRAP_GLOBAL = "__opengeniSiteBridgeBootstrapV2" as const;
35
+ export const OPENGENI_SITE_LOCAL_CODEMODE_PATH = "/__opengeni/site-tools" as const;
36
+
37
+ export type OpenGeniSiteBridgeConnectMessage = {
38
+ type: typeof OPENGENI_SITE_BRIDGE_CONNECT;
39
+ version: typeof OPENGENI_SITE_BRIDGE_VERSION;
40
+ };
41
+
42
+ export type OpenGeniSiteBridgeReadyMessage = {
43
+ type: typeof OPENGENI_SITE_BRIDGE_READY;
44
+ version: typeof OPENGENI_SITE_BRIDGE_VERSION;
45
+ };
46
+
47
+ /** Site-originated calls cannot carry host-only approval tokens or Site-version authority. */
48
+ export type OpenGeniSiteToolCallRequest = Omit<
49
+ ToolGatewayCallRequest,
50
+ "approvalToken" | "siteArtifactId" | "siteVersionId"
51
+ >;
52
+
53
+ /** Host-filtered catalog projection. Tenant routing context never enters Site code. */
54
+ export type OpenGeniSiteToolCatalog = Omit<ToolGatewayCatalog, "accountId" | "workspaceId">;
55
+
56
+ export type OpenGeniSiteWorkspaceTools = OpenGeniWorkspaceTools<OpenGeniSiteToolCatalog>;
57
+
58
+ export type OpenGeniSiteBridgeRequestMessage = {
59
+ type: typeof OPENGENI_SITE_BRIDGE_REQUEST;
60
+ version: typeof OPENGENI_SITE_BRIDGE_VERSION;
61
+ requestId: string;
62
+ } & (
63
+ | { method: "catalog" }
64
+ | { method: "call"; payload: OpenGeniSiteToolCallRequest }
65
+ | { method: "declarations" }
66
+ );
67
+
68
+ export type OpenGeniSiteBridgeCancelMessage = {
69
+ type: typeof OPENGENI_SITE_BRIDGE_CANCEL;
70
+ version: typeof OPENGENI_SITE_BRIDGE_VERSION;
71
+ requestId: string;
72
+ };
73
+
74
+ export type OpenGeniSiteBridgeResponseMessage = {
75
+ type: typeof OPENGENI_SITE_BRIDGE_RESPONSE;
76
+ version: typeof OPENGENI_SITE_BRIDGE_VERSION;
77
+ requestId: string;
78
+ } & (
79
+ | {
80
+ ok: true;
81
+ value: OpenGeniSiteToolCatalog | ToolGatewayCallResponse | ToolGatewayDeclarationsResponse;
82
+ }
83
+ | {
84
+ ok: false;
85
+ error: {
86
+ code: string;
87
+ message: string;
88
+ retryable: boolean;
89
+ outcomeUnknown?: boolean;
90
+ };
91
+ }
92
+ );
93
+
94
+ export type OpenGeniSiteClient = {
95
+ /** Ordinary SDK, including React session/composer methods and SSE streams. */
96
+ readonly client: OpenGeniClient;
97
+ /** Host-bound routing alias, not a credential or a caller-selected tenant. */
98
+ readonly workspaceId: string;
99
+ /** Workspace-bound typed facade. The parent host owns workspace identity and credentials. */
100
+ readonly tools: OpenGeniSiteWorkspaceTools;
101
+ close(): void;
102
+ };
103
+
104
+ export type OpenGeniSiteClientOptions = {
105
+ /** Advanced embedding seam; ordinary Sites accept bootstrap only from their exact parent. */
106
+ parentWindow?: MessageEventSource;
107
+ /** Advanced embedding seam for listening to the host's document-bound bootstrap message. */
108
+ siteWindow?: Pick<Window, "parent" | "addEventListener" | "removeEventListener">;
109
+ /** Test/embedding seam for an already document-bound host bootstrap port. */
110
+ bootstrapPort?: MessagePort;
111
+ connectTimeoutMs?: number;
112
+ requestTimeoutMs?: number;
113
+ createMessageChannel?: () => MessageChannel;
114
+ /** Local-preview seam. Top-level pages use this same-origin Codemode proxy automatically. */
115
+ localCodemodePath?: string | false;
116
+ /** Test/embedding seam for local-preview requests. */
117
+ fetch?: typeof globalThis.fetch;
118
+ };
119
+
120
+ export class OpenGeniSiteBridgeError extends Error {
121
+ constructor(
122
+ readonly code: string,
123
+ message: string,
124
+ readonly retryable = false,
125
+ readonly outcomeUnknown = false,
126
+ ) {
127
+ super(message);
128
+ this.name = "OpenGeniSiteBridgeError";
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Create the browser client used by a Site. Published iframes use the parent
134
+ * MessagePort; top-level sandbox previews use the same-origin Codemode adapter.
135
+ * Credentials remain in the selected host and never enter Site code.
136
+ */
137
+ export function createOpenGeniSiteClient(
138
+ options: OpenGeniSiteClientOptions = {},
139
+ ): OpenGeniSiteClient {
140
+ const transport = shouldUseLocalCodemode(options)
141
+ ? new OpenGeniSiteLocalCodemodeTransport(options)
142
+ : new OpenGeniSiteBridgeTransport(options);
143
+ return {
144
+ client: new OpenGeniClient({
145
+ baseUrl: "https://site.opengeni.invalid",
146
+ fetch: (input, init) => transport.fetch(input, init),
147
+ }),
148
+ workspaceId: SITE_WORKSPACE,
149
+ tools: new OpenGeniToolsClient(transport).forWorkspace("site-host"),
150
+ close: () => transport.close(),
151
+ };
152
+ }
153
+
154
+ class OpenGeniSiteLocalCodemodeTransport implements OpenGeniToolTransport {
155
+ private readonly fetchImpl: typeof globalThis.fetch;
156
+ private readonly basePath: string;
157
+
158
+ constructor(options: OpenGeniSiteClientOptions) {
159
+ this.fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);
160
+ const configured = options.localCodemodePath;
161
+ this.basePath = (
162
+ typeof configured === "string" ? configured : OPENGENI_SITE_LOCAL_CODEMODE_PATH
163
+ ).replace(/\/+$/u, "");
164
+ }
165
+
166
+ close(): void {}
167
+
168
+ async fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {
169
+ const request = new Request(input, init);
170
+ const url = new URL(request.url);
171
+ const path = `${url.pathname}${url.search}`;
172
+ siteSessionPath(path, SITE_WORKSPACE, request.method);
173
+ return this.fetchImpl(`${this.basePath}/sdk${path}`, {
174
+ method: request.method,
175
+ headers: request.headers,
176
+ signal: request.signal,
177
+ ...(request.body ? { body: await request.text() } : {}),
178
+ });
179
+ }
180
+
181
+ async requestJson<T>(
182
+ method: string,
183
+ path: string,
184
+ body?: unknown,
185
+ _query?: Record<string, string>,
186
+ options: { signal?: AbortSignal } = {},
187
+ ): Promise<T> {
188
+ const suffix = localCodemodeSuffix(method, path);
189
+ const response = await this.fetchImpl(`${this.basePath}${suffix}`, {
190
+ method,
191
+ ...(options.signal ? { signal: options.signal } : {}),
192
+ ...(body === undefined
193
+ ? {}
194
+ : {
195
+ headers: { "content-type": "application/json" },
196
+ body: JSON.stringify(body),
197
+ }),
198
+ });
199
+ const value = (await response.json()) as unknown;
200
+ if (response.ok) return value as T;
201
+ const envelope = isRecord(value) && isRecord(value.error) ? value.error : {};
202
+ throw new OpenGeniSiteBridgeError(
203
+ typeof envelope.code === "string" ? envelope.code : "local_codemode_error",
204
+ typeof envelope.message === "string"
205
+ ? envelope.message
206
+ : `Local Site tool request failed with HTTP ${response.status}`,
207
+ envelope.retryable === true,
208
+ envelope.outcomeUnknown === true,
209
+ );
210
+ }
211
+ }
212
+
213
+ function shouldUseLocalCodemode(options: OpenGeniSiteClientOptions): boolean {
214
+ if (options.localCodemodePath === false || options.bootstrapPort) return false;
215
+ if (typeof options.localCodemodePath === "string") return true;
216
+ const siteWindow = options.siteWindow ?? globalThis.window;
217
+ return Boolean(siteWindow && siteWindow.parent === siteWindow);
218
+ }
219
+
220
+ function localCodemodeSuffix(method: string, path: string): string {
221
+ if (method === "GET" && path.endsWith("/tools/catalog")) return "/catalog";
222
+ if (method === "GET" && path.endsWith("/tools/declarations")) return "/declarations";
223
+ if (method === "POST" && path.endsWith("/tools/calls")) return "/calls";
224
+ throw new OpenGeniSiteBridgeError("unsupported_request", "Unsupported Site tool request");
225
+ }
226
+
227
+ export function isOpenGeniSiteBridgeConnectMessage(
228
+ value: unknown,
229
+ ): value is OpenGeniSiteBridgeConnectMessage {
230
+ return (
231
+ isRecord(value) &&
232
+ value.type === OPENGENI_SITE_BRIDGE_CONNECT &&
233
+ value.version === OPENGENI_SITE_BRIDGE_VERSION
234
+ );
235
+ }
236
+
237
+ export function isOpenGeniSiteBridgeRequestMessage(
238
+ value: unknown,
239
+ ): value is OpenGeniSiteBridgeRequestMessage {
240
+ if (
241
+ !isRecord(value) ||
242
+ value.type !== OPENGENI_SITE_BRIDGE_REQUEST ||
243
+ value.version !== OPENGENI_SITE_BRIDGE_VERSION ||
244
+ typeof value.requestId !== "string" ||
245
+ !value.requestId
246
+ ) {
247
+ return false;
248
+ }
249
+ if (value.method === "catalog" || value.method === "declarations") return true;
250
+ return value.method === "call" && isRecord(value.payload);
251
+ }
252
+
253
+ export function isOpenGeniSiteBridgeCancelMessage(
254
+ value: unknown,
255
+ ): value is OpenGeniSiteBridgeCancelMessage {
256
+ return (
257
+ isRecord(value) &&
258
+ value.type === OPENGENI_SITE_BRIDGE_CANCEL &&
259
+ value.version === OPENGENI_SITE_BRIDGE_VERSION &&
260
+ typeof value.requestId === "string" &&
261
+ Boolean(value.requestId)
262
+ );
263
+ }
264
+
265
+ /** Strip every host-only field before a call crosses the Site boundary. */
266
+ export function sanitizeOpenGeniSiteToolCallRequest(
267
+ value: ToolGatewayCallRequest,
268
+ ): OpenGeniSiteToolCallRequest {
269
+ return {
270
+ ...(value.operationId === undefined ? {} : { operationId: value.operationId }),
271
+ catalogDigest: value.catalogDigest,
272
+ identity: value.identity,
273
+ arguments: value.arguments,
274
+ };
275
+ }
276
+
277
+ class OpenGeniSiteBridgeTransport implements OpenGeniToolTransport {
278
+ private readonly options: OpenGeniSiteClientOptions;
279
+ private readonly bootstrap: SiteBridgeBootstrap;
280
+ private port: MessagePort | null = null;
281
+ private connecting: Promise<MessagePort> | null = null;
282
+ private closed = false;
283
+
284
+ constructor(options: OpenGeniSiteClientOptions) {
285
+ this.options = options;
286
+ this.bootstrap = createSiteBridgeBootstrap(options);
287
+ }
288
+
289
+ async fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {
290
+ return sitePortFetch(await this.connect(), input, init);
291
+ }
292
+
293
+ async requestJson<T>(
294
+ method: string,
295
+ path: string,
296
+ body?: unknown,
297
+ _query?: Record<string, string>,
298
+ requestOptions: { signal?: AbortSignal; timeoutMs?: number } = {},
299
+ ): Promise<T> {
300
+ if (method === "GET" && path.endsWith("/tools/catalog")) {
301
+ return (await this.request({ method: "catalog" }, requestOptions)) as T;
302
+ }
303
+ if (method === "GET" && path.endsWith("/tools/declarations")) {
304
+ return (await this.request({ method: "declarations" }, requestOptions)) as T;
305
+ }
306
+ if (method === "POST" && path.endsWith("/tools/calls")) {
307
+ if (!isRecord(body)) throw new TypeError("Site tool call payload is required");
308
+ return (await this.request(
309
+ {
310
+ method: "call",
311
+ payload: sanitizeOpenGeniSiteToolCallRequest(body as ToolGatewayCallRequest),
312
+ },
313
+ requestOptions,
314
+ )) as T;
315
+ }
316
+ throw new OpenGeniSiteBridgeError("unsupported_request", "Unsupported Site bridge request");
317
+ }
318
+
319
+ close(): void {
320
+ if (this.closed) return;
321
+ this.closed = true;
322
+ this.bootstrap.close();
323
+ this.port?.close();
324
+ this.port = null;
325
+ }
326
+
327
+ private async request(
328
+ request:
329
+ | { method: "catalog" }
330
+ | { method: "call"; payload: OpenGeniSiteToolCallRequest }
331
+ | { method: "declarations" },
332
+ options: { signal?: AbortSignal; timeoutMs?: number },
333
+ ): Promise<unknown> {
334
+ const port = await this.connect();
335
+ const requestId = crypto.randomUUID();
336
+ const timeoutMs = positiveTimeout(
337
+ options.timeoutMs ?? this.options.requestTimeoutMs ?? 120_000,
338
+ "requestTimeoutMs",
339
+ );
340
+ return await new Promise((resolve, reject) => {
341
+ const timeout = setTimeout(() => {
342
+ cleanup();
343
+ cancel(port, requestId);
344
+ reject(
345
+ request.method === "call"
346
+ ? new OpenGeniSiteBridgeError(
347
+ "timeout",
348
+ "Site tool request timed out after execution may have started",
349
+ false,
350
+ true,
351
+ )
352
+ : new OpenGeniSiteBridgeError("timeout", "Site tool request timed out", true),
353
+ );
354
+ }, timeoutMs);
355
+ const abort = () => {
356
+ cleanup();
357
+ cancel(port, requestId);
358
+ reject(options.signal?.reason ?? new DOMException("Request aborted", "AbortError"));
359
+ };
360
+ const onMessage = (event: MessageEvent<unknown>) => {
361
+ const response = event.data;
362
+ if (
363
+ !isRecord(response) ||
364
+ response.type !== OPENGENI_SITE_BRIDGE_RESPONSE ||
365
+ response.version !== OPENGENI_SITE_BRIDGE_VERSION ||
366
+ response.requestId !== requestId ||
367
+ typeof response.ok !== "boolean"
368
+ ) {
369
+ return;
370
+ }
371
+ cleanup();
372
+ if (response.ok) {
373
+ resolve(response.value);
374
+ return;
375
+ }
376
+ const error = isRecord(response.error) ? response.error : {};
377
+ reject(
378
+ new OpenGeniSiteBridgeError(
379
+ typeof error.code === "string" ? error.code : "bridge_error",
380
+ typeof error.message === "string" ? error.message : "Site tool request failed",
381
+ error.retryable === true,
382
+ error.outcomeUnknown === true,
383
+ ),
384
+ );
385
+ };
386
+ const cleanup = () => {
387
+ clearTimeout(timeout);
388
+ options.signal?.removeEventListener("abort", abort);
389
+ port.removeEventListener("message", onMessage);
390
+ };
391
+ if (options.signal?.aborted) {
392
+ abort();
393
+ return;
394
+ }
395
+ options.signal?.addEventListener("abort", abort, { once: true });
396
+ port.addEventListener("message", onMessage);
397
+ port.postMessage({
398
+ type: OPENGENI_SITE_BRIDGE_REQUEST,
399
+ version: OPENGENI_SITE_BRIDGE_VERSION,
400
+ requestId,
401
+ ...request,
402
+ } satisfies OpenGeniSiteBridgeRequestMessage);
403
+ });
404
+ }
405
+
406
+ private async connect(): Promise<MessagePort> {
407
+ if (this.closed) throw new OpenGeniSiteBridgeError("closed", "Site bridge is closed");
408
+ if (this.port) return this.port;
409
+ if (this.connecting) return await this.connecting;
410
+ const channel = (this.options.createMessageChannel ?? (() => new MessageChannel()))();
411
+ const timeoutMs = positiveTimeout(this.options.connectTimeoutMs ?? 10_000, "connectTimeoutMs");
412
+ this.connecting = new Promise<MessagePort>((resolve, reject) => {
413
+ let active = true;
414
+ const timeout = setTimeout(() => {
415
+ cleanup();
416
+ channel.port1.close();
417
+ reject(new OpenGeniSiteBridgeError("host_timeout", "Opengeni Site host did not respond"));
418
+ }, timeoutMs);
419
+ const onMessage = (event: MessageEvent<unknown>) => {
420
+ const message = event.data;
421
+ if (
422
+ !isRecord(message) ||
423
+ message.type !== OPENGENI_SITE_BRIDGE_READY ||
424
+ message.version !== OPENGENI_SITE_BRIDGE_VERSION
425
+ ) {
426
+ return;
427
+ }
428
+ cleanup();
429
+ this.port = channel.port1;
430
+ resolve(channel.port1);
431
+ };
432
+ const cleanup = () => {
433
+ active = false;
434
+ clearTimeout(timeout);
435
+ channel.port1.removeEventListener("message", onMessage);
436
+ };
437
+ channel.port1.addEventListener("message", onMessage);
438
+ channel.port1.start();
439
+ void this.bootstrap
440
+ .port()
441
+ .then((bootstrapPort) => {
442
+ if (!active) return;
443
+ if (this.closed) throw new OpenGeniSiteBridgeError("closed", "Site bridge is closed");
444
+ bootstrapPort.postMessage(
445
+ {
446
+ type: OPENGENI_SITE_BRIDGE_CONNECT,
447
+ version: OPENGENI_SITE_BRIDGE_VERSION,
448
+ } satisfies OpenGeniSiteBridgeConnectMessage,
449
+ [channel.port2],
450
+ );
451
+ })
452
+ .catch((error) => {
453
+ cleanup();
454
+ channel.port1.close();
455
+ reject(error);
456
+ });
457
+ }).finally(() => {
458
+ this.connecting = null;
459
+ });
460
+ return await this.connecting;
461
+ }
462
+ }
463
+
464
+ type SiteBridgeBootstrap = {
465
+ port: () => Promise<MessagePort>;
466
+ close: () => void;
467
+ };
468
+
469
+ function createSiteBridgeBootstrap(options: OpenGeniSiteClientOptions): SiteBridgeBootstrap {
470
+ if (options.bootstrapPort) {
471
+ return {
472
+ port: async () => options.bootstrapPort!,
473
+ close: () => options.bootstrapPort?.close(),
474
+ };
475
+ }
476
+ const siteWindow = options.siteWindow ?? globalThis.window;
477
+ const parentWindow = options.parentWindow ?? siteWindow?.parent;
478
+ if (!siteWindow || !parentWindow || parentWindow === siteWindow) {
479
+ return {
480
+ port: async () => {
481
+ throw new OpenGeniSiteBridgeError(
482
+ "host_unavailable",
483
+ "Opengeni Site client must run inside a hosted iframe",
484
+ );
485
+ },
486
+ close: () => undefined,
487
+ };
488
+ }
489
+ const retainedPort = retainedSiteBridgeBootstrapPort(siteWindow);
490
+ if (retainedPort) {
491
+ return {
492
+ port: async () => retainedPort,
493
+ close: () => undefined,
494
+ };
495
+ }
496
+ let settledPort: MessagePort | null = null;
497
+ let rejectBootstrap: ((reason?: unknown) => void) | null = null;
498
+ const onMessage = (event: MessageEvent<unknown>) => {
499
+ if (
500
+ event.source !== parentWindow ||
501
+ !isOpenGeniSiteBridgeReadyMessage(event.data) ||
502
+ event.ports.length !== 1
503
+ ) {
504
+ return;
505
+ }
506
+ cleanup();
507
+ settledPort = event.ports[0]!;
508
+ settledPort.start();
509
+ retainSiteBridgeBootstrapPort(siteWindow, settledPort);
510
+ resolveBootstrap?.(settledPort);
511
+ };
512
+ let resolveBootstrap: ((port: MessagePort) => void) | null = null;
513
+ const cleanup = () => siteWindow.removeEventListener("message", onMessage as EventListener);
514
+ const port = new Promise<MessagePort>((resolve, reject) => {
515
+ resolveBootstrap = resolve;
516
+ rejectBootstrap = reject;
517
+ siteWindow.addEventListener("message", onMessage as EventListener);
518
+ });
519
+ void port.catch(() => undefined);
520
+ return {
521
+ port: async () => await port,
522
+ close: () => {
523
+ cleanup();
524
+ rejectBootstrap?.(new OpenGeniSiteBridgeError("closed", "Site bridge is closed"));
525
+ resolveBootstrap = null;
526
+ rejectBootstrap = null;
527
+ },
528
+ };
529
+ }
530
+
531
+ function retainedSiteBridgeBootstrapPort(
532
+ siteWindow: OpenGeniSiteClientOptions["siteWindow"],
533
+ ): MessagePort | null {
534
+ const state = (siteWindow as unknown as Record<string, unknown>)[
535
+ OPENGENI_SITE_BRIDGE_BOOTSTRAP_GLOBAL
536
+ ];
537
+ if (!isRecord(state)) return null;
538
+ const candidate = state.port as Partial<MessagePort> | undefined;
539
+ return candidate &&
540
+ typeof candidate.postMessage === "function" &&
541
+ typeof candidate.addEventListener === "function" &&
542
+ typeof candidate.start === "function"
543
+ ? (candidate as MessagePort)
544
+ : null;
545
+ }
546
+
547
+ function retainSiteBridgeBootstrapPort(
548
+ siteWindow: OpenGeniSiteClientOptions["siteWindow"],
549
+ port: MessagePort,
550
+ ): void {
551
+ try {
552
+ Object.defineProperty(siteWindow, OPENGENI_SITE_BRIDGE_BOOTSTRAP_GLOBAL, {
553
+ configurable: true,
554
+ value: { port },
555
+ });
556
+ } catch {
557
+ // The bootstrap event still serves the current client when the embedding
558
+ // window refuses extension; only late construction loses this fallback.
559
+ }
560
+ }
561
+
562
+ function isOpenGeniSiteBridgeReadyMessage(value: unknown): value is OpenGeniSiteBridgeReadyMessage {
563
+ return (
564
+ isRecord(value) &&
565
+ value.type === OPENGENI_SITE_BRIDGE_READY &&
566
+ value.version === OPENGENI_SITE_BRIDGE_VERSION
567
+ );
568
+ }
569
+
570
+ function cancel(port: MessagePort, requestId: string): void {
571
+ port.postMessage({
572
+ type: OPENGENI_SITE_BRIDGE_CANCEL,
573
+ version: OPENGENI_SITE_BRIDGE_VERSION,
574
+ requestId,
575
+ } satisfies OpenGeniSiteBridgeCancelMessage);
576
+ }
577
+
578
+ function positiveTimeout(value: number, label: string): number {
579
+ if (!Number.isFinite(value) || value <= 0) throw new RangeError(`${label} must be positive`);
580
+ return value;
581
+ }
582
+
583
+ function isRecord(value: unknown): value is Record<string, any> {
584
+ return typeof value === "object" && value !== null && !Array.isArray(value);
585
+ }
package/src/skills.ts ADDED
@@ -0,0 +1,69 @@
1
+ /** Public shared Skill folder/history shapes; no runtime contracts dependency. */
2
+ export type SkillFile = { path: string; content: string };
3
+ export type SkillScope = "workspace" | "organization" | "user";
4
+ export type SkillRecord = {
5
+ removalOperationId?: string | null;
6
+ activationMode: "workspace_managed" | "session_selected";
7
+ pendingRevisionIds: string[];
8
+ id: string;
9
+ stableKey: string;
10
+ scope: SkillScope;
11
+ scopeVersion: number;
12
+ status: string;
13
+ activeRevisionId: string | null;
14
+ revisionId: string | null;
15
+ title: string | null;
16
+ description: string | null;
17
+ contentHash: string | null;
18
+ files: SkillFile[];
19
+ source: { pluginId: string; facetKey: string; skillFacetId: string } | null;
20
+ };
21
+ export type SkillSummary = Omit<SkillRecord, "files">;
22
+ export type SkillWriteReceipt = {
23
+ removed?: boolean | undefined;
24
+ operationId: string;
25
+ skillId: string;
26
+ revisionId: string;
27
+ outcome: "applied" | "pending" | "preserved";
28
+ pendingReason?: "approval" | "source_finalization" | undefined;
29
+ replayed: boolean;
30
+ decision?: "rejected" | undefined;
31
+ skillReview?: import("./types").SkillReviewReference | undefined;
32
+ };
33
+ export type SkillPublicationReceipt = SkillWriteReceipt & {
34
+ sourceOperationId: string;
35
+ activationEventId: string | null;
36
+ };
37
+ export type SkillSourceReleaseReceipt = {
38
+ skillId: string;
39
+ revisionId: string | null;
40
+ disposition: "deactivated" | "preserved" | "inactive";
41
+ eventId: string | null;
42
+ warning: string | null;
43
+ };
44
+ export type SaveWorkspaceSkillRequest = {
45
+ operationId: string;
46
+ skillId: string;
47
+ expectedRevisionId: string | null;
48
+ expectedScopeVersion: number;
49
+ scope?: SkillScope;
50
+ stableKey: string;
51
+ files: SkillFile[];
52
+ deletions?: string[];
53
+ reason: string;
54
+ };
55
+ export type ApplyWorkspaceSkillRevisionRequest = {
56
+ removalOperationId?: string;
57
+ operationId: string;
58
+ revisionId: string;
59
+ expectedRevisionId: string | null;
60
+ expectedScopeVersion: number;
61
+ reason: string;
62
+ };
63
+
64
+ export type RemoveWorkspaceSkillRequest = {
65
+ operationId: string;
66
+ expectedRevisionId: string | null;
67
+ expectedScopeVersion: number;
68
+ reason: string;
69
+ };
package/src/sse.ts CHANGED
@@ -87,7 +87,13 @@ export async function* parseSseStream(
87
87
  // still pending at end-of-stream came from a truncated connection and is
88
88
  // discarded — the streaming layer replays from its cursor on reconnect.
89
89
  } finally {
90
- await reader.cancel().catch(() => {});
91
- reader.releaseLock();
90
+ // Never await cancel(): some fetch bodies settle it only once their request
91
+ // aborts, which would deadlock the consumer's unwinding.
92
+ void reader.cancel().catch(() => {});
93
+ try {
94
+ reader.releaseLock();
95
+ } catch {
96
+ // A pending read (older stream implementations) keeps the lock; cancel releases it.
97
+ }
92
98
  }
93
99
  }