@agentorg/cli 0.0.5 → 0.0.7

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 (260) hide show
  1. package/README.md +23 -104
  2. package/dist/node_modules/@agentorg/computer/LICENSE +201 -0
  3. package/dist/node_modules/@agentorg/computer/NOTICE +2 -0
  4. package/dist/node_modules/@agentorg/computer/dist/THIRD_PARTY_LICENSES.txt +1321 -0
  5. package/dist/node_modules/@agentorg/computer/dist/sdk.js +24909 -0
  6. package/dist/node_modules/@agentorg/computer/dist/types/generated/schema.d.ts +860 -0
  7. package/dist/node_modules/@agentorg/computer/dist/types/sdk.d.ts +242 -0
  8. package/dist/node_modules/@agentorg/computer/package.json +12 -0
  9. package/dist/node_modules/@agentorg/computer-connector/dist/src/index.d.ts +1 -0
  10. package/dist/node_modules/@agentorg/computer-connector/dist/src/index.js +1 -0
  11. package/dist/node_modules/@agentorg/computer-connector/dist/src/provider.d.ts +24 -0
  12. package/dist/node_modules/@agentorg/computer-connector/dist/src/provider.js +482 -0
  13. package/dist/node_modules/@agentorg/computer-connector/dist/src/unit.d.ts +19 -0
  14. package/dist/node_modules/@agentorg/computer-connector/dist/src/unit.js +149 -0
  15. package/dist/node_modules/@agentorg/computer-connector/package.json +33 -0
  16. package/dist/node_modules/@agentorg/computer-connector/skills/browser/SKILL.md +31 -0
  17. package/dist/node_modules/@agentorg/computer-connector/skills/computer/SKILL.md +30 -0
  18. package/dist/node_modules/@agentorg/computer-connector/skills/files/SKILL.md +28 -0
  19. package/dist/node_modules/@agentorg/computer-connector/skills/terminal/SKILL.md +39 -0
  20. package/dist/node_modules/@agentorg/computer-connector/skills/web-research/SKILL.md +29 -0
  21. package/dist/node_modules/@agentorg/hub/dist/src/hub-actor.d.ts +2 -7
  22. package/dist/node_modules/@agentorg/hub/dist/src/hub-actor.js +4 -144
  23. package/dist/node_modules/@agentorg/hub/dist/src/index.d.ts +1 -3
  24. package/dist/node_modules/@agentorg/hub/dist/src/index.js +1 -3
  25. package/dist/node_modules/@agentorg/hub/dist/src/router.d.ts +9 -58
  26. package/dist/node_modules/@agentorg/hub/dist/src/router.js +41 -414
  27. package/dist/node_modules/@agentorg/hub/dist/src/state.d.ts +17 -317
  28. package/dist/node_modules/@agentorg/hub/dist/src/state.js +42 -536
  29. package/dist/node_modules/@agentorg/hub/dist/src/validate.d.ts +1 -3
  30. package/dist/node_modules/@agentorg/hub/dist/src/validate.js +19 -17
  31. package/dist/node_modules/@agentorg/hub/package.json +0 -3
  32. package/dist/node_modules/@agentorg/interfaces/dist/src/agent-provider.d.ts +119 -0
  33. package/dist/node_modules/@agentorg/interfaces/dist/src/agent-provider.js +96 -0
  34. package/dist/node_modules/@agentorg/interfaces/dist/src/agent-settings.d.ts +42 -0
  35. package/dist/node_modules/@agentorg/interfaces/dist/src/agent-settings.js +53 -0
  36. package/dist/node_modules/@agentorg/interfaces/dist/src/chat.d.ts +93 -38
  37. package/dist/node_modules/@agentorg/interfaces/dist/src/chat.js +71 -22
  38. package/dist/node_modules/@agentorg/interfaces/dist/src/connection.d.ts +36 -0
  39. package/dist/node_modules/@agentorg/interfaces/dist/src/connection.js +31 -0
  40. package/dist/node_modules/@agentorg/interfaces/dist/src/folders.d.ts +19 -0
  41. package/dist/node_modules/@agentorg/interfaces/dist/src/folders.js +25 -0
  42. package/dist/node_modules/@agentorg/interfaces/dist/src/hub.d.ts +16 -286
  43. package/dist/node_modules/@agentorg/interfaces/dist/src/hub.js +17 -159
  44. package/dist/node_modules/@agentorg/interfaces/dist/src/index.d.ts +9 -9
  45. package/dist/node_modules/@agentorg/interfaces/dist/src/index.js +9 -9
  46. package/dist/node_modules/@agentorg/interfaces/dist/src/kv.d.ts +2 -2
  47. package/dist/node_modules/@agentorg/interfaces/dist/src/kv.js +2 -2
  48. package/dist/node_modules/@agentorg/interfaces/dist/src/llm-session.d.ts +2 -0
  49. package/dist/node_modules/@agentorg/interfaces/dist/src/llm-session.js +2 -1
  50. package/dist/node_modules/@agentorg/interfaces/dist/src/manager.d.ts +626 -0
  51. package/dist/node_modules/@agentorg/interfaces/dist/src/manager.js +349 -0
  52. package/dist/node_modules/@agentorg/interfaces/dist/src/tools.d.ts +39 -0
  53. package/dist/node_modules/@agentorg/interfaces/dist/src/tools.js +43 -0
  54. package/dist/node_modules/@agentorg/interfaces/dist/src/units.d.ts +460 -0
  55. package/dist/node_modules/@agentorg/interfaces/dist/src/units.js +204 -0
  56. package/dist/node_modules/@agentorg/looper/dist/src/index.d.ts +5 -0
  57. package/dist/node_modules/@agentorg/looper/dist/src/index.js +5 -0
  58. package/dist/node_modules/@agentorg/looper/dist/src/loop.d.ts +75 -0
  59. package/dist/node_modules/@agentorg/looper/dist/src/loop.js +332 -0
  60. package/dist/node_modules/@agentorg/looper/dist/src/looper.d.ts +71 -0
  61. package/dist/node_modules/@agentorg/looper/dist/src/looper.js +282 -0
  62. package/dist/node_modules/@agentorg/looper/dist/src/record.d.ts +99 -0
  63. package/dist/node_modules/@agentorg/looper/dist/src/record.js +278 -0
  64. package/dist/node_modules/@agentorg/looper/dist/src/tools.d.ts +11 -0
  65. package/dist/node_modules/@agentorg/looper/dist/src/tools.js +42 -0
  66. package/dist/node_modules/@agentorg/looper/dist/src/types.d.ts +147 -0
  67. package/dist/node_modules/@agentorg/looper/dist/src/types.js +32 -0
  68. package/dist/node_modules/@agentorg/looper/package.json +24 -0
  69. package/dist/node_modules/@agentorg/manager/dist/src/activity.d.ts +18 -0
  70. package/dist/node_modules/@agentorg/manager/dist/src/activity.js +65 -0
  71. package/dist/node_modules/@agentorg/manager/dist/src/control.d.ts +134 -0
  72. package/dist/node_modules/@agentorg/manager/dist/src/control.js +1115 -0
  73. package/dist/node_modules/@agentorg/manager/dist/src/form.d.ts +40 -0
  74. package/dist/node_modules/@agentorg/manager/dist/src/form.js +191 -0
  75. package/dist/node_modules/@agentorg/manager/dist/src/index.d.ts +1 -0
  76. package/dist/node_modules/@agentorg/manager/dist/src/index.js +1 -0
  77. package/dist/node_modules/@agentorg/manager/dist/src/manager.d.ts +25 -0
  78. package/dist/node_modules/@agentorg/manager/dist/src/manager.js +680 -0
  79. package/dist/node_modules/@agentorg/manager/dist/src/skills.d.ts +27 -0
  80. package/dist/node_modules/@agentorg/manager/dist/src/skills.js +152 -0
  81. package/dist/node_modules/@agentorg/manager/dist/src/stack.d.ts +454 -0
  82. package/dist/node_modules/@agentorg/manager/dist/src/stack.js +917 -0
  83. package/dist/node_modules/@agentorg/manager/package.json +30 -0
  84. package/dist/node_modules/@agentorg/mcp/dist/src/connection.d.ts +34 -0
  85. package/dist/node_modules/@agentorg/mcp/dist/src/connection.js +296 -0
  86. package/dist/node_modules/@agentorg/mcp/dist/src/index.d.ts +4 -0
  87. package/dist/node_modules/@agentorg/mcp/dist/src/index.js +4 -0
  88. package/dist/node_modules/@agentorg/mcp/dist/src/kinds.d.ts +158 -0
  89. package/dist/node_modules/@agentorg/mcp/dist/src/kinds.js +164 -0
  90. package/dist/node_modules/@agentorg/mcp/dist/src/provider.d.ts +22 -0
  91. package/dist/node_modules/@agentorg/mcp/dist/src/provider.js +197 -0
  92. package/dist/node_modules/@agentorg/mcp/dist/src/public.d.ts +6 -0
  93. package/dist/node_modules/@agentorg/mcp/dist/src/public.js +72 -0
  94. package/dist/node_modules/@agentorg/mcp/package.json +31 -0
  95. package/dist/node_modules/@agentorg/sdk/dist/src/cli.js +3 -23
  96. package/dist/node_modules/@agentorg/sdk/dist/src/client.d.ts +4 -25
  97. package/dist/node_modules/@agentorg/sdk/dist/src/client.js +5 -55
  98. package/dist/node_modules/@agentorg/sdk/dist/src/errors.d.ts +1 -1
  99. package/dist/node_modules/@agentorg/sdk/dist/src/errors.js +3 -3
  100. package/dist/node_modules/@agentorg/sdk/dist/src/filled.d.ts +21 -0
  101. package/dist/node_modules/@agentorg/sdk/dist/src/filled.js +24 -0
  102. package/dist/node_modules/@agentorg/sdk/dist/src/index.d.ts +3 -2
  103. package/dist/node_modules/@agentorg/sdk/dist/src/index.js +2 -1
  104. package/dist/node_modules/@agentorg/sdk/dist/src/interface.d.ts +6 -34
  105. package/dist/node_modules/@agentorg/sdk/dist/src/interface.js +3 -24
  106. package/dist/node_modules/@agentorg/sdk/dist/src/module-host.d.ts +8 -17
  107. package/dist/node_modules/@agentorg/sdk/dist/src/module-host.js +15 -87
  108. package/dist/node_modules/@agentorg/sdk/dist/src/module.d.ts +10 -76
  109. package/dist/node_modules/@agentorg/sdk/dist/src/module.js +3 -23
  110. package/dist/node_modules/@agentorg/sdk/dist/src/person-commands.js +0 -5
  111. package/dist/node_modules/@agentorg/sdk/dist/src/runtime.d.ts +3 -27
  112. package/dist/node_modules/@agentorg/sdk/dist/src/runtime.js +5 -100
  113. package/dist/node_modules/@agentorg/sdk/dist/src/testing.d.ts +7 -8
  114. package/dist/node_modules/@agentorg/sdk/dist/src/testing.js +12 -24
  115. package/dist/node_modules/@agentorg/sdk/package.json +4 -37
  116. package/dist/node_modules/@agentorg/shell/dist/app.css +4624 -739
  117. package/dist/node_modules/@agentorg/shell/dist/app.js +245 -202
  118. package/dist/node_modules/@agentorg/shell/package.json +23 -10
  119. package/dist/node_modules/@agentorg/wire/dist/src/frames.d.ts +2 -3
  120. package/dist/node_modules/@agentorg/wire/dist/src/frames.js +2 -3
  121. package/dist/node_modules/@agentorg/wire/dist/src/ops.d.ts +5 -34
  122. package/dist/node_modules/@agentorg/wire/dist/src/ops.js +2 -17
  123. package/dist/node_modules/assistant/dist/src/chats.d.ts +92 -0
  124. package/dist/node_modules/assistant/dist/src/chats.js +357 -0
  125. package/dist/node_modules/assistant/dist/src/engine.d.ts +42 -0
  126. package/dist/node_modules/assistant/dist/src/engine.js +160 -0
  127. package/dist/node_modules/assistant/dist/src/local-store.d.ts +3 -0
  128. package/dist/node_modules/assistant/dist/src/local-store.js +58 -0
  129. package/dist/node_modules/assistant/dist/src/provider.d.ts +21 -0
  130. package/dist/node_modules/assistant/dist/src/provider.js +259 -0
  131. package/dist/node_modules/assistant/dist/src/settings.d.ts +17 -0
  132. package/dist/node_modules/assistant/dist/src/settings.js +43 -0
  133. package/dist/node_modules/assistant/dist/src/tools.d.ts +57 -0
  134. package/dist/node_modules/assistant/dist/src/tools.js +102 -0
  135. package/dist/node_modules/assistant/package.json +30 -0
  136. package/dist/node_modules/chatgpt/dist/src/account.d.ts +52 -0
  137. package/dist/node_modules/chatgpt/dist/src/account.js +270 -0
  138. package/dist/node_modules/chatgpt/dist/src/encoding.d.ts +7 -0
  139. package/dist/node_modules/chatgpt/dist/src/encoding.js +20 -0
  140. package/dist/node_modules/chatgpt/dist/src/file-store.d.ts +9 -0
  141. package/dist/node_modules/chatgpt/dist/src/file-store.js +68 -0
  142. package/dist/node_modules/chatgpt/dist/src/index.d.ts +1 -0
  143. package/dist/node_modules/chatgpt/dist/src/index.js +1 -0
  144. package/dist/node_modules/chatgpt/dist/src/jwt.d.ts +15 -0
  145. package/dist/node_modules/chatgpt/dist/src/jwt.js +37 -0
  146. package/dist/node_modules/chatgpt/dist/src/oauth.d.ts +43 -0
  147. package/dist/node_modules/chatgpt/dist/src/oauth.js +104 -0
  148. package/dist/node_modules/chatgpt/dist/src/program.d.ts +23 -0
  149. package/dist/node_modules/chatgpt/dist/src/program.js +41 -0
  150. package/dist/node_modules/chatgpt/dist/src/responses.d.ts +54 -0
  151. package/dist/node_modules/chatgpt/dist/src/responses.js +300 -0
  152. package/dist/node_modules/chatgpt/dist/src/serve.d.ts +65 -0
  153. package/dist/node_modules/chatgpt/dist/src/serve.js +46 -0
  154. package/dist/node_modules/chatgpt/package.json +33 -0
  155. package/dist/src/api.d.ts +5 -34
  156. package/dist/src/api.js +10 -68
  157. package/dist/src/cli.js +3 -7
  158. package/dist/src/folders.d.ts +2 -0
  159. package/dist/src/folders.js +45 -0
  160. package/dist/src/gateway.d.ts +13 -8
  161. package/dist/src/gateway.js +119 -296
  162. package/dist/src/index.d.ts +4 -5
  163. package/dist/src/index.js +3 -4
  164. package/dist/src/live.d.ts +17 -0
  165. package/dist/src/live.js +109 -0
  166. package/dist/src/notes.d.ts +11 -0
  167. package/dist/src/notes.js +64 -0
  168. package/dist/src/oauth.d.ts +16 -0
  169. package/dist/src/oauth.js +46 -0
  170. package/dist/src/programs.d.ts +36 -0
  171. package/dist/src/programs.js +198 -0
  172. package/dist/src/signin.d.ts +12 -3
  173. package/dist/src/signin.js +30 -6
  174. package/package.json +4 -11
  175. package/dist/bundled/index.json +0 -6
  176. package/dist/bundled/sha256-0e91cc3d0e9762b81abc2427b5496b20f383abcd6fb97d928a8d50e956b54d1f.agentorg +0 -0
  177. package/dist/bundled/sha256-1f64ca62a0209d767d6aa6c4feb50b0653d60f10bebbc301f79bd3a37e0153c1.agentorg +0 -0
  178. package/dist/bundled/sha256-4055f8fddf6b90f3d356543f554b2a9e9a2c4a8827a8774f8f87952dc1692331.agentorg +0 -0
  179. package/dist/bundled/sha256-e356ea3c1899138a8494baf521556831006f38534fa9e92ae873e7e6956c3a46.agentorg +0 -0
  180. package/dist/node_modules/@agentorg/hub/dist/src/build.d.ts +0 -17
  181. package/dist/node_modules/@agentorg/hub/dist/src/build.js +0 -120
  182. package/dist/node_modules/@agentorg/hub/dist/src/logs.d.ts +0 -33
  183. package/dist/node_modules/@agentorg/hub/dist/src/logs.js +0 -162
  184. package/dist/node_modules/@agentorg/hub/dist/src/net.d.ts +0 -41
  185. package/dist/node_modules/@agentorg/hub/dist/src/net.js +0 -265
  186. package/dist/node_modules/@agentorg/hub/dist/src/processes.d.ts +0 -78
  187. package/dist/node_modules/@agentorg/hub/dist/src/processes.js +0 -485
  188. package/dist/node_modules/@agentorg/hub/dist/src/storage.d.ts +0 -38
  189. package/dist/node_modules/@agentorg/hub/dist/src/storage.js +0 -194
  190. package/dist/node_modules/@agentorg/interfaces/dist/src/http-egress.d.ts +0 -6
  191. package/dist/node_modules/@agentorg/interfaces/dist/src/http-egress.js +0 -7
  192. package/dist/node_modules/@agentorg/interfaces/dist/src/installer.d.ts +0 -191
  193. package/dist/node_modules/@agentorg/interfaces/dist/src/installer.js +0 -136
  194. package/dist/node_modules/@agentorg/interfaces/dist/src/layout.d.ts +0 -47
  195. package/dist/node_modules/@agentorg/interfaces/dist/src/layout.js +0 -52
  196. package/dist/node_modules/@agentorg/interfaces/dist/src/rules.d.ts +0 -35
  197. package/dist/node_modules/@agentorg/interfaces/dist/src/rules.js +0 -37
  198. package/dist/node_modules/@agentorg/interfaces/dist/src/storage-admin.d.ts +0 -23
  199. package/dist/node_modules/@agentorg/interfaces/dist/src/storage-admin.js +0 -31
  200. package/dist/node_modules/@agentorg/interfaces/dist/src/ui-shell.d.ts +0 -14
  201. package/dist/node_modules/@agentorg/interfaces/dist/src/ui-shell.js +0 -26
  202. package/dist/node_modules/@agentorg/interfaces/dist/src/ui-view.d.ts +0 -27
  203. package/dist/node_modules/@agentorg/interfaces/dist/src/ui-view.js +0 -26
  204. package/dist/node_modules/@agentorg/kit/dist/src/chat.d.ts +0 -37
  205. package/dist/node_modules/@agentorg/kit/dist/src/chat.js +0 -131
  206. package/dist/node_modules/@agentorg/kit/dist/src/components.d.ts +0 -94
  207. package/dist/node_modules/@agentorg/kit/dist/src/components.js +0 -66
  208. package/dist/node_modules/@agentorg/kit/dist/src/icons.d.ts +0 -17
  209. package/dist/node_modules/@agentorg/kit/dist/src/icons.js +0 -30
  210. package/dist/node_modules/@agentorg/kit/dist/src/index.d.ts +0 -6
  211. package/dist/node_modules/@agentorg/kit/dist/src/index.js +0 -10
  212. package/dist/node_modules/@agentorg/kit/dist/src/markdown.d.ts +0 -9
  213. package/dist/node_modules/@agentorg/kit/dist/src/markdown.js +0 -14
  214. package/dist/node_modules/@agentorg/kit/dist/src/resizable.d.ts +0 -5
  215. package/dist/node_modules/@agentorg/kit/dist/src/resizable.js +0 -8
  216. package/dist/node_modules/@agentorg/kit/dist/src/styles.d.ts +0 -11
  217. package/dist/node_modules/@agentorg/kit/dist/src/styles.js +0 -166
  218. package/dist/node_modules/@agentorg/kit/package.json +0 -44
  219. package/dist/node_modules/@agentorg/sdk/dist/frame/runtime.js +0 -753
  220. package/dist/node_modules/@agentorg/sdk/dist/host/runner.js +0 -21963
  221. package/dist/node_modules/@agentorg/sdk/dist/src/build.d.ts +0 -2
  222. package/dist/node_modules/@agentorg/sdk/dist/src/build.js +0 -2
  223. package/dist/node_modules/@agentorg/sdk/dist/src/client-http.d.ts +0 -24
  224. package/dist/node_modules/@agentorg/sdk/dist/src/client-http.js +0 -247
  225. package/dist/node_modules/@agentorg/sdk/dist/src/describe.d.ts +0 -13
  226. package/dist/node_modules/@agentorg/sdk/dist/src/describe.js +0 -16
  227. package/dist/node_modules/@agentorg/sdk/dist/src/frame-base.d.ts +0 -8
  228. package/dist/node_modules/@agentorg/sdk/dist/src/frame-base.js +0 -64
  229. package/dist/node_modules/@agentorg/sdk/dist/src/frame-entry.d.ts +0 -1
  230. package/dist/node_modules/@agentorg/sdk/dist/src/frame-entry.js +0 -35
  231. package/dist/node_modules/@agentorg/sdk/dist/src/frame-host.d.ts +0 -57
  232. package/dist/node_modules/@agentorg/sdk/dist/src/frame-host.js +0 -293
  233. package/dist/node_modules/@agentorg/sdk/dist/src/frame-protocol.d.ts +0 -124
  234. package/dist/node_modules/@agentorg/sdk/dist/src/frame-protocol.js +0 -16
  235. package/dist/node_modules/@agentorg/sdk/dist/src/frame.d.ts +0 -25
  236. package/dist/node_modules/@agentorg/sdk/dist/src/frame.js +0 -248
  237. package/dist/node_modules/@agentorg/sdk/dist/src/host-main.d.ts +0 -1
  238. package/dist/node_modules/@agentorg/sdk/dist/src/host-main.js +0 -60
  239. package/dist/node_modules/@agentorg/sdk/dist/src/host.d.ts +0 -25
  240. package/dist/node_modules/@agentorg/sdk/dist/src/host.js +0 -92
  241. package/dist/node_modules/@agentorg/sdk/dist/src/manifest-api.d.ts +0 -2
  242. package/dist/node_modules/@agentorg/sdk/dist/src/manifest-api.js +0 -2
  243. package/dist/node_modules/@agentorg/sdk/dist/src/manifest.d.ts +0 -56
  244. package/dist/node_modules/@agentorg/sdk/dist/src/manifest.js +0 -165
  245. package/dist/node_modules/@agentorg/sdk/dist/src/package.d.ts +0 -60
  246. package/dist/node_modules/@agentorg/sdk/dist/src/package.js +0 -538
  247. package/dist/node_modules/@agentorg/sdk/dist/src/tar.d.ts +0 -7
  248. package/dist/node_modules/@agentorg/sdk/dist/src/tar.js +0 -71
  249. package/dist/node_modules/@agentorg/shell/dist/agent-bindings.js +0 -59
  250. package/dist/node_modules/@agentorg/shell/src/agent-bindings.ts +0 -107
  251. package/dist/src/frames.d.ts +0 -23
  252. package/dist/src/frames.js +0 -78
  253. package/dist/src/layout.d.ts +0 -44
  254. package/dist/src/layout.js +0 -90
  255. package/dist/src/model.d.ts +0 -54
  256. package/dist/src/model.js +0 -299
  257. package/dist/src/rules.d.ts +0 -71
  258. package/dist/src/rules.js +0 -157
  259. package/dist/src/transfer.d.ts +0 -30
  260. package/dist/src/transfer.js +0 -110
@@ -0,0 +1,102 @@
1
+ /**
2
+ * The assistant's tools, gathered afresh for each model request. A `tools@1` slot gives whatever
3
+ * it lists now, with its server's own input schemas. Each is offered as
4
+ * `<slot>__<name>`, and a call runs through the slot, so the Hub checks and audits it like any
5
+ * other.
6
+ */
7
+ import { tools as toolsInterface } from "@agentorg/interfaces";
8
+ import { Refusal } from "@agentorg/looper";
9
+ import { describeInterface, NotConnected, OutcomeUnknown, Refused, } from "@agentorg/sdk";
10
+ /** What a request can carry: its tools count, and, with the record and instructions, one frame. */
11
+ export const MAX_TOOLS = 128;
12
+ export const TOOLS_BUDGET = 256 * 1024;
13
+ const MAX_NAME = 64;
14
+ const MAX_DESCRIPTION = 1024;
15
+ const encoder = new TextEncoder();
16
+ const TOOLS_ID = describeInterface(toolsInterface).id;
17
+ /** The first `length` UTF-16 units of `text`, never ending inside a surrogate pair. */
18
+ export function head(text, length) {
19
+ const cut = text.slice(0, length);
20
+ return /[\uD800-\uDBFF]$/.test(cut) ? cut.slice(0, -1) : cut;
21
+ }
22
+ /** The code and message of what a call through a slot threw. */
23
+ export function codeOf(error) {
24
+ if (error instanceof Refused)
25
+ return { code: error.code, message: error.message };
26
+ if (error instanceof NotConnected)
27
+ return { code: "not_connected", message: `${error.target} is not connected.` };
28
+ if (error instanceof OutcomeUnknown)
29
+ return { code: "outcome_unknown", message: error.message };
30
+ return { code: "failed", message: "The call failed." };
31
+ }
32
+ /**
33
+ * A call through a slot, as the looper is told how it went: what the slot refuses is the looper's
34
+ * `Refusal`, with the code to show and the slot's own error as its cause.
35
+ */
36
+ export const relayed = (call) => call.catch((error) => {
37
+ const { code, message } = codeOf(error);
38
+ throw code === "failed" && !(error instanceof Refused)
39
+ ? error
40
+ : new Refusal(code, message, { cause: error });
41
+ });
42
+ /** Whether a slot is a `tools@1`, whose tools are whatever it lists. */
43
+ export const listsTools = (described) => described.id === TOOLS_ID;
44
+ /**
45
+ * What a `tools@1` slot lists now. A slot that can't answer gives no tools and says why, and is
46
+ * asked again at the next request.
47
+ */
48
+ export async function listedBy(name, slot) {
49
+ const list = slot.call.list;
50
+ const call = slot.call.call;
51
+ let entries;
52
+ try {
53
+ ({ tools: entries } = (await list({})));
54
+ }
55
+ catch (error) {
56
+ return { candidates: [], leftOut: [{ slot: name, reason: codeOf(error).code }] };
57
+ }
58
+ const candidates = entries.map((entry) => ({
59
+ slot: name,
60
+ name: entry.name,
61
+ ...(entry.description ? { description: entry.description } : {}),
62
+ parameters: entry.inputSchema,
63
+ run: async (args) => {
64
+ const { output, failed } = (await call({ name: entry.name, arguments: args }));
65
+ return failed ? { output, ok: false, code: "failed" } : { output, ok: true };
66
+ },
67
+ }));
68
+ return { candidates, leftOut: [] };
69
+ }
70
+ /**
71
+ * The tools one request offers, by function name, and what it can't. A character a function name
72
+ * can't have becomes `_`. Candidates are taken in order, so the first ones given are the ones kept
73
+ * when a request is full; what doesn't fit is reported, never sent.
74
+ */
75
+ export function offered(candidates) {
76
+ const tools = new Map();
77
+ const leftOut = [];
78
+ let bytes = 0;
79
+ for (const { slot, name, description, parameters, run } of candidates) {
80
+ const toolName = `${slot}__${name}`.replace(/[^A-Za-z0-9_-]/g, "_");
81
+ const tool = {
82
+ name: toolName,
83
+ ...(description ? { description: head(description, MAX_DESCRIPTION) } : {}),
84
+ parameters,
85
+ };
86
+ const size = encoder.encode(JSON.stringify(tool)).byteLength;
87
+ const reason = toolName.length > MAX_NAME
88
+ ? "name"
89
+ : tools.has(toolName)
90
+ ? "duplicate"
91
+ : tools.size >= MAX_TOOLS || bytes + size > TOOLS_BUDGET
92
+ ? "limit"
93
+ : undefined;
94
+ if (reason) {
95
+ leftOut.push({ slot, tool: name, reason });
96
+ continue;
97
+ }
98
+ bytes += size;
99
+ tools.set(toolName, { ...tool, run: (input) => relayed(run(input)) });
100
+ }
101
+ return { tools: [...tools.values()], leftOut };
102
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "assistant",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "description": "The agent engine, and the bundled provider that runs it",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "exports": {
9
+ "./provider": {
10
+ "types": "./dist/src/provider.d.ts",
11
+ "default": "./dist/src/provider.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist/src"
16
+ ],
17
+ "scripts": {
18
+ "build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.json",
19
+ "test": "node --test \"dist/test/**/*.test.js\""
20
+ },
21
+ "dependencies": {
22
+ "@agentorg/interfaces": "0.0.0",
23
+ "@agentorg/looper": "0.0.0",
24
+ "@agentorg/sdk": "0.0.0",
25
+ "zod": "^4.6.7"
26
+ },
27
+ "devDependencies": {
28
+ "@agentorg/hub": "0.0.0"
29
+ }
30
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * The ChatGPT sign-in this Actor owns: its registration, its tokens and their refresh. The tokens
3
+ * stay inside, apart from where they are kept: nothing here returns, emits or logs one.
4
+ */
5
+ import type { kv, LoginState } from "@agentorg/interfaces";
6
+ import { Refused, type Slot } from "@agentorg/sdk";
7
+ import type { z } from "zod";
8
+ import { type Fetch } from "./oauth.js";
9
+ type State = z.output<typeof LoginState>;
10
+ /** Where the sign-in is kept: the program's own file. */
11
+ export type Store = Pick<Slot<typeof kv>["call"], "get" | "set" | "delete">;
12
+ export declare const notSignedIn: () => Refused;
13
+ export declare const notEligible: () => Refused;
14
+ export declare function createAccount(options: {
15
+ fetch: Fetch;
16
+ store: Store;
17
+ changed(state: State): void;
18
+ now?: () => number;
19
+ }): {
20
+ status(): Promise<{
21
+ state: "ineligible" | "signed_in" | "signed_out";
22
+ account: {
23
+ email?: string | undefined;
24
+ plan?: string | undefined;
25
+ };
26
+ } | {
27
+ account?: undefined;
28
+ state: "ineligible" | "signed_in" | "signed_out";
29
+ }>;
30
+ start({ redirectUri }: {
31
+ redirectUri: string;
32
+ }): Promise<{
33
+ authorizeUrl: string;
34
+ }>;
35
+ complete({ callbackUrl }: {
36
+ callbackUrl: string;
37
+ }): Promise<{
38
+ account: {
39
+ email?: string | undefined;
40
+ plan?: string | undefined;
41
+ };
42
+ }>;
43
+ logout(): Promise<{
44
+ revoked: boolean;
45
+ }>;
46
+ /** A usable access token, refreshed when it's near expiry or when `stale`. */
47
+ token(stale?: boolean): Promise<string>;
48
+ /** OpenAI said the account isn't eligible: say so until the next sign-in. */
49
+ ineligible(): Promise<void>;
50
+ };
51
+ export type Account = ReturnType<typeof createAccount>;
52
+ export {};
@@ -0,0 +1,270 @@
1
+ import { Refused } from "@agentorg/sdk";
2
+ import { challengeOf, random } from "./encoding.js";
3
+ import { verifyIdToken } from "./jwt.js";
4
+ import { AGENT_NAME, AUTHORIZE, DYNAMIC_CLIENT, discover, GrantError, grant, ISSUER, PLAN_SCOPE, RESOURCE, revoke, SCOPES, TERMINAL, } from "./oauth.js";
5
+ /** How long a started sign-in can be completed, how many can wait, and how early to refresh. */
6
+ const PENDING_FOR = 10 * 60_000;
7
+ const MAX_PENDING = 16;
8
+ const REFRESH_BEFORE = 5 * 60_000;
9
+ export const notSignedIn = () => new Refused("not_signed_in", "Not signed in to ChatGPT. Continue with ChatGPT to sign in.");
10
+ export const notEligible = () => new Refused("ineligible", "This ChatGPT account isn't eligible to use its plan in this app. Signing in again won't change that.");
11
+ const unreachable = () => new Refused("unavailable", "OpenAI couldn't be reached. Try again later.");
12
+ const address = (url) => `${url.origin}${url.pathname}`;
13
+ /** Who signed in, from verified id_token claims; the plan claim isn't documented, so optional. */
14
+ function identity(claims) {
15
+ const auth = claims["https://api.openai.com/auth"];
16
+ return {
17
+ ...(typeof claims.sub === "string" ? { sub: claims.sub } : {}),
18
+ ...(typeof claims.email === "string" ? { email: claims.email.slice(0, 320) } : {}),
19
+ ...(typeof auth?.chatgpt_plan_type === "string"
20
+ ? { plan: auth.chatgpt_plan_type.slice(0, 64) }
21
+ : {}),
22
+ };
23
+ }
24
+ const tokensOf = ({ accessToken, refreshToken, expiresAt, scopes }) => ({
25
+ accessToken,
26
+ refreshToken,
27
+ expiresAt,
28
+ scopes,
29
+ });
30
+ export function createAccount(options) {
31
+ const { fetch, store, changed } = options;
32
+ const now = options.now ?? Date.now;
33
+ const pending = new Map();
34
+ let issuer;
35
+ let refreshing;
36
+ /** Bumped by every sign-in and sign-out, so a refresh that lands after one is dropped. */
37
+ let generation = 0;
38
+ const issuerOf = () => {
39
+ issuer ??= discover(fetch).catch((error) => {
40
+ issuer = undefined;
41
+ throw error;
42
+ });
43
+ return issuer;
44
+ };
45
+ /** Verify an id_token; on a key the issuer no longer has, read its keys once more. */
46
+ const verify = async (token, expect) => {
47
+ const check = async () => verifyIdToken(token, (await issuerOf()).keys, { issuer: ISSUER, ...expect, now: now() });
48
+ try {
49
+ return await check();
50
+ }
51
+ catch (error) {
52
+ if (!(error instanceof Error && error.message === "no matching signing key"))
53
+ throw error;
54
+ issuer = undefined;
55
+ return check();
56
+ }
57
+ };
58
+ const read = async (key) => (await store.get({ key })).value;
59
+ const write = (key, value) => store.set({ key, value: value });
60
+ const credential = () => read("credential");
61
+ const registration = async () => {
62
+ const kept = await read("registration");
63
+ if (kept)
64
+ return kept;
65
+ const fresh = { hostId: `urn:uuid:${crypto.randomUUID()}` };
66
+ await write("registration", fresh);
67
+ return fresh;
68
+ };
69
+ const stateOf = (held) => !held ? "signed_out" : held.ineligible ? "ineligible" : "signed_in";
70
+ const accountOf = (held) => ({
71
+ ...(held.email === undefined ? {} : { email: held.email }),
72
+ ...(held.plan === undefined ? {} : { plan: held.plan }),
73
+ });
74
+ const clear = async () => {
75
+ generation++;
76
+ await store.delete({ key: "credential" });
77
+ changed("signed_out");
78
+ };
79
+ /** Revoke tokens that won't be kept, as well as we can; nothing waits for it. */
80
+ const discard = (clientId, refreshToken) => void issuerOf()
81
+ .then((found) => revoke(fetch, found, clientId, refreshToken))
82
+ .catch(() => false);
83
+ /** Refresh the tokens, one refresh at a time; the refresh token rotates each time. */
84
+ const refresh = () => {
85
+ refreshing ??= (async () => {
86
+ const started = generation;
87
+ try {
88
+ const held = await credential();
89
+ if (!held)
90
+ throw notSignedIn();
91
+ const next = await grant(fetch, {
92
+ grant_type: "refresh_token",
93
+ client_id: held.clientId,
94
+ refresh_token: held.refreshToken,
95
+ }, now());
96
+ let kept = { ...held, ...tokensOf(next) };
97
+ if (next.idToken) {
98
+ const claims = await verify(next.idToken, { audience: held.clientId }).catch(() => undefined);
99
+ if (claims)
100
+ kept = { ...kept, ...identity(claims) };
101
+ }
102
+ // Signed out or in again meanwhile: these tokens belong to nothing now.
103
+ if (started !== generation) {
104
+ discard(held.clientId, next.refreshToken);
105
+ throw notSignedIn();
106
+ }
107
+ await write("credential", kept);
108
+ return kept;
109
+ }
110
+ catch (error) {
111
+ if (error instanceof GrantError) {
112
+ if (!TERMINAL.has(error.code))
113
+ throw new Refused("failed", `OpenAI refused to refresh the sign-in (${error.code}).`);
114
+ if (started === generation)
115
+ await clear();
116
+ throw notSignedIn();
117
+ }
118
+ if (error instanceof Refused)
119
+ throw error;
120
+ throw unreachable();
121
+ }
122
+ finally {
123
+ refreshing = undefined;
124
+ }
125
+ })();
126
+ return refreshing;
127
+ };
128
+ return {
129
+ async status() {
130
+ const held = await credential();
131
+ return held ? { state: stateOf(held), account: accountOf(held) } : { state: stateOf(held) };
132
+ },
133
+ async start({ redirectUri }) {
134
+ const { hostId, clientId = DYNAMIC_CLIENT } = await registration();
135
+ for (const [state, attempt] of pending)
136
+ if (now() - attempt.at > PENDING_FOR || pending.size >= MAX_PENDING)
137
+ pending.delete(state);
138
+ const verifier = random(48);
139
+ const state = random();
140
+ const nonce = random();
141
+ const redirect = address(new URL(redirectUri));
142
+ pending.set(state, { verifier, nonce, redirectUri, redirect, clientId, at: now() });
143
+ const url = new URL(AUTHORIZE);
144
+ url.search = new URLSearchParams({
145
+ response_type: "code",
146
+ client_id: clientId,
147
+ redirect_uri: redirectUri,
148
+ scope: SCOPES,
149
+ resource: RESOURCE,
150
+ code_challenge: await challengeOf(verifier),
151
+ code_challenge_method: "S256",
152
+ state,
153
+ nonce,
154
+ ext_agent_host_id: hostId,
155
+ ...(clientId === DYNAMIC_CLIENT ? { agent_name_hint: AGENT_NAME } : {}),
156
+ }).toString();
157
+ return { authorizeUrl: url.toString() };
158
+ },
159
+ async complete({ callbackUrl }) {
160
+ let url;
161
+ try {
162
+ url = new URL(callbackUrl);
163
+ }
164
+ catch {
165
+ throw new Refused("invalid", "callbackUrl isn't an address.");
166
+ }
167
+ const params = url.searchParams;
168
+ const state = params.get("state");
169
+ const attempt = state === null ? undefined : pending.get(state);
170
+ if (state === null || !attempt || now() - attempt.at > PENDING_FOR)
171
+ throw new Refused("expired", "This sign-in wasn't started here, or it expired. Start again.");
172
+ if (address(url) !== attempt.redirect)
173
+ throw new Refused("invalid", "The callback isn't the address this sign-in redirects to.");
174
+ pending.delete(state);
175
+ const error = params.get("error");
176
+ if (error === "access_denied")
177
+ throw new Refused("denied", "Sign-in was declined.");
178
+ if (error !== null)
179
+ throw new Refused("failed", "OpenAI returned an error to the sign-in.");
180
+ const code = params.get("code");
181
+ if (!code)
182
+ throw new Refused("failed", "The callback carries no code.");
183
+ const issued = params.get("client_id");
184
+ let clientId = attempt.clientId;
185
+ if (clientId === DYNAMIC_CLIENT) {
186
+ if (!issued || issued === DYNAMIC_CLIENT)
187
+ throw new Refused("failed", "OpenAI didn't issue a client id; registration isn't complete.");
188
+ clientId = issued;
189
+ }
190
+ else if (issued !== null && issued !== clientId)
191
+ throw new Refused("failed", "The callback names another client, so it was refused.");
192
+ let granted;
193
+ try {
194
+ granted = await grant(fetch, {
195
+ grant_type: "authorization_code",
196
+ client_id: clientId,
197
+ code,
198
+ code_verifier: attempt.verifier,
199
+ redirect_uri: attempt.redirectUri,
200
+ }, now());
201
+ }
202
+ catch (error) {
203
+ if (error instanceof GrantError)
204
+ throw new Refused("failed", `OpenAI refused the sign-in (${error.code}). Start again.`);
205
+ throw unreachable();
206
+ }
207
+ if (!granted.scopes.includes(PLAN_SCOPE)) {
208
+ discard(clientId, granted.refreshToken);
209
+ throw new Refused("failed", "The sign-in wasn't granted ChatGPT plan usage.");
210
+ }
211
+ try {
212
+ await issuerOf();
213
+ }
214
+ catch {
215
+ discard(clientId, granted.refreshToken);
216
+ throw unreachable();
217
+ }
218
+ let claims;
219
+ try {
220
+ if (!granted.idToken)
221
+ throw new Error("no id_token");
222
+ claims = await verify(granted.idToken, { audience: clientId, nonce: attempt.nonce });
223
+ }
224
+ catch {
225
+ discard(clientId, granted.refreshToken);
226
+ throw new Refused("failed", "OpenAI's identity token didn't verify.");
227
+ }
228
+ // A refresh still running belongs to the sign-in this one replaces, which is revoked.
229
+ await refreshing?.catch(() => { });
230
+ generation++;
231
+ const replaced = await credential();
232
+ if (replaced)
233
+ discard(replaced.clientId, replaced.refreshToken);
234
+ const held = { clientId, ...tokensOf(granted), ...identity(claims) };
235
+ await write("registration", { ...(await registration()), clientId });
236
+ await write("credential", held);
237
+ changed("signed_in");
238
+ return { account: accountOf(held) };
239
+ },
240
+ async logout() {
241
+ // A refresh still running would write its tokens back after the sign-out.
242
+ await refreshing?.catch(() => { });
243
+ const held = await credential();
244
+ if (!held)
245
+ return { revoked: true };
246
+ await clear();
247
+ const revoked = await issuerOf().then((found) => revoke(fetch, found, held.clientId, held.refreshToken), () => false);
248
+ return { revoked };
249
+ },
250
+ /** A usable access token, refreshed when it's near expiry or when `stale`. */
251
+ async token(stale = false) {
252
+ const held = await credential();
253
+ if (!held)
254
+ throw notSignedIn();
255
+ if (held.ineligible)
256
+ throw notEligible();
257
+ if (!stale && held.expiresAt - REFRESH_BEFORE > now())
258
+ return held.accessToken;
259
+ return (await refresh()).accessToken;
260
+ },
261
+ /** OpenAI said the account isn't eligible: say so until the next sign-in. */
262
+ async ineligible() {
263
+ const held = await credential();
264
+ if (!held || held.ineligible)
265
+ return;
266
+ await write("credential", { ...held, ineligible: true });
267
+ changed("ineligible");
268
+ },
269
+ };
270
+ }
@@ -0,0 +1,7 @@
1
+ /** Base64url without padding, as PKCE and JWTs use it. */
2
+ export declare function base64url(bytes: Uint8Array): string;
3
+ export declare function fromBase64url(text: string): Uint8Array<ArrayBuffer>;
4
+ /** A fresh random value, base64url: `bytes` of entropy. */
5
+ export declare function random(bytes?: number): string;
6
+ /** The PKCE S256 challenge of a verifier. */
7
+ export declare function challengeOf(verifier: string): Promise<string>;
@@ -0,0 +1,20 @@
1
+ /** Base64url without padding, as PKCE and JWTs use it. */
2
+ export function base64url(bytes) {
3
+ let binary = "";
4
+ for (const byte of bytes)
5
+ binary += String.fromCharCode(byte);
6
+ return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
7
+ }
8
+ export function fromBase64url(text) {
9
+ const binary = atob(text.replaceAll("-", "+").replaceAll("_", "/"));
10
+ return Uint8Array.from(binary, (char) => char.charCodeAt(0));
11
+ }
12
+ /** A fresh random value, base64url: `bytes` of entropy. */
13
+ export function random(bytes = 32) {
14
+ return base64url(crypto.getRandomValues(new Uint8Array(bytes)));
15
+ }
16
+ /** The PKCE S256 challenge of a verifier. */
17
+ export async function challengeOf(verifier) {
18
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier));
19
+ return base64url(new Uint8Array(digest));
20
+ }
@@ -0,0 +1,9 @@
1
+ import type { Log } from "@agentorg/sdk";
2
+ import type { Store } from "./account.js";
3
+ /**
4
+ * The sign-in, in one private file, read each time so nothing is held that the file no longer says.
5
+ * Each change is on disk before it is acknowledged, since a refresh token that rotated can't be had
6
+ * again. A file that can't be read is removed, and the person signs in again; nothing of it is ever
7
+ * logged, a parse error's text included.
8
+ */
9
+ export declare function fileStore(dir: string, log: Log): Store;
@@ -0,0 +1,68 @@
1
+ import { chmodSync, closeSync, fsyncSync, mkdirSync, openSync, readFileSync, renameSync, rmSync, writeFileSync, } from "node:fs";
2
+ import { join } from "node:path";
3
+ /**
4
+ * The sign-in, in one private file, read each time so nothing is held that the file no longer says.
5
+ * Each change is on disk before it is acknowledged, since a refresh token that rotated can't be had
6
+ * again. A file that can't be read is removed, and the person signs in again; nothing of it is ever
7
+ * logged, a parse error's text included.
8
+ */
9
+ export function fileStore(dir, log) {
10
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
11
+ chmodSync(dir, 0o700);
12
+ const path = join(dir, "sign-in.json");
13
+ const read = () => {
14
+ const values = new Map();
15
+ let raw;
16
+ try {
17
+ raw = readFileSync(path, "utf8");
18
+ }
19
+ catch (error) {
20
+ if (error.code === "ENOENT")
21
+ return values;
22
+ throw error;
23
+ }
24
+ try {
25
+ for (const [key, value] of Object.entries(JSON.parse(raw)))
26
+ values.set(key, value);
27
+ }
28
+ catch {
29
+ rmSync(path);
30
+ log.error("The sign-in file couldn't be read, so it was removed: sign in again.");
31
+ }
32
+ return values;
33
+ };
34
+ const save = (values) => {
35
+ const temporary = `${path}.tmp`;
36
+ writeFileSync(temporary, JSON.stringify(Object.fromEntries(values)), {
37
+ mode: 0o600,
38
+ flush: true,
39
+ });
40
+ renameSync(temporary, path);
41
+ const folder = openSync(dir, "r");
42
+ try {
43
+ fsyncSync(folder);
44
+ }
45
+ finally {
46
+ closeSync(folder);
47
+ }
48
+ };
49
+ return {
50
+ get: async ({ key }) => {
51
+ const values = read();
52
+ return values.has(key) ? { value: values.get(key) } : {};
53
+ },
54
+ set: async ({ key, value }) => {
55
+ const values = read();
56
+ values.set(key, value);
57
+ save(values);
58
+ return {};
59
+ },
60
+ delete: async ({ key }) => {
61
+ const values = read();
62
+ const deleted = values.delete(key);
63
+ if (deleted)
64
+ save(values);
65
+ return { deleted };
66
+ },
67
+ };
68
+ }
@@ -0,0 +1 @@
1
+ export { type ChatGPT, type ChatGPTOptions, startChatGPT } from "./program.js";
@@ -0,0 +1 @@
1
+ export { startChatGPT } from "./program.js";
@@ -0,0 +1,15 @@
1
+ import type { webcrypto } from "node:crypto";
2
+ export type Claims = Record<string, unknown>;
3
+ export type Jwk = webcrypto.JsonWebKey & {
4
+ kid?: string;
5
+ };
6
+ /**
7
+ * An id_token's claims, once its RS256 signature checks against one of the issuer's keys and its
8
+ * issuer, audience, expiry and (when given) nonce are right. Anything else throws.
9
+ */
10
+ export declare function verifyIdToken(token: string, keys: Jwk[], expect: {
11
+ issuer: string;
12
+ audience: string;
13
+ nonce?: string;
14
+ now: number;
15
+ }): Promise<Claims>;
@@ -0,0 +1,37 @@
1
+ import { fromBase64url } from "./encoding.js";
2
+ function part(text) {
3
+ if (!text)
4
+ throw new Error("malformed token");
5
+ const value = JSON.parse(new TextDecoder().decode(fromBase64url(text)));
6
+ if (typeof value !== "object" || value === null)
7
+ throw new Error("malformed token");
8
+ return value;
9
+ }
10
+ /**
11
+ * An id_token's claims, once its RS256 signature checks against one of the issuer's keys and its
12
+ * issuer, audience, expiry and (when given) nonce are right. Anything else throws.
13
+ */
14
+ export async function verifyIdToken(token, keys, expect) {
15
+ const [header, payload, signature] = token.split(".");
16
+ const head = part(header);
17
+ if (head.alg !== "RS256")
18
+ throw new Error("unexpected signing algorithm");
19
+ const jwk = keys.find((key) => key.kty === "RSA" && (head.kid === undefined || key.kid === head.kid));
20
+ if (!jwk || signature === undefined)
21
+ throw new Error("no matching signing key");
22
+ const key = await crypto.subtle.importKey("jwk", { kty: jwk.kty, n: jwk.n, e: jwk.e, alg: "RS256", ext: true }, { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }, false, ["verify"]);
23
+ const signed = new TextEncoder().encode(`${header}.${payload}`);
24
+ if (!(await crypto.subtle.verify("RSASSA-PKCS1-v1_5", key, fromBase64url(signature), signed)))
25
+ throw new Error("bad signature");
26
+ const claims = part(payload);
27
+ const audience = Array.isArray(claims.aud) ? claims.aud : [claims.aud];
28
+ if (claims.iss !== expect.issuer)
29
+ throw new Error("unexpected issuer");
30
+ if (!audience.includes(expect.audience))
31
+ throw new Error("unexpected audience");
32
+ if (typeof claims.exp !== "number" || claims.exp * 1000 < expect.now - 60_000)
33
+ throw new Error("expired");
34
+ if (expect.nonce !== undefined && claims.nonce !== expect.nonce)
35
+ throw new Error("unexpected nonce");
36
+ return claims;
37
+ }
@@ -0,0 +1,43 @@
1
+ /** OpenAI's Sign in with ChatGPT endpoints and grants, for plan usage by an open-source app. */
2
+ import type { Jwk } from "./jwt.js";
3
+ export declare const ISSUER = "https://auth.openai.com";
4
+ export declare const AUTHORIZE = "https://auth.openai.com/api/accounts/authorize";
5
+ export declare const TOKEN = "https://auth.openai.com/api/accounts/oauth/token";
6
+ /** The audience of the tokens: the Responses API. */
7
+ export declare const RESOURCE = "https://api.openai.com/v1";
8
+ /** The scope that lets the tokens draw on the person's ChatGPT plan. */
9
+ export declare const PLAN_SCOPE = "chatgpt.tokens.use.direct";
10
+ export declare const SCOPES = "openid profile email offline_access resource.invoke chatgpt.tokens.use.direct";
11
+ /** The client id of a first sign-in; OpenAI then issues this app's own `oaiapp_…` id. */
12
+ export declare const DYNAMIC_CLIENT = "dynamic_agent_client";
13
+ export declare const AGENT_NAME = "AgentOrg";
14
+ export type Fetch = (request: Request) => Promise<Response>;
15
+ /** What a grant gives. `expiresAt` is in milliseconds. */
16
+ export interface Grant {
17
+ accessToken: string;
18
+ refreshToken: string;
19
+ idToken?: string;
20
+ expiresAt: number;
21
+ scopes: string[];
22
+ }
23
+ /** A word from a server, fit to show: at most 64 characters of letters, digits and `_.-[]`. */
24
+ export declare const word: (value: unknown) => string;
25
+ /** The token endpoint refused a grant, with OAuth's error code. */
26
+ export declare class GrantError extends Error {
27
+ readonly code: string;
28
+ readonly status: number;
29
+ constructor(code: string, status: number);
30
+ }
31
+ /** Refresh errors after which the refresh token can't be used again. */
32
+ export declare const TERMINAL: Set<string>;
33
+ /** An authorization-code or refresh-token grant, at the token endpoint. */
34
+ export declare function grant(fetch: Fetch, params: Record<string, string>, now: number): Promise<Grant>;
35
+ /** The issuer's signing keys and revocation endpoint, from its OpenID configuration. */
36
+ export interface Issuer {
37
+ keys: Jwk[];
38
+ revocation?: string;
39
+ }
40
+ /** Read the issuer's configuration and keys; anything short of a usable key set throws. */
41
+ export declare function discover(fetch: Fetch): Promise<Issuer>;
42
+ /** Revoke a refresh token: true when the issuer confirmed it. Retried on 5xx and network errors. */
43
+ export declare function revoke(fetch: Fetch, issuer: Issuer, clientId: string, refreshToken: string): Promise<boolean>;