openclaw-openagent 1.0.1 โ†’ 1.0.3

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 (188) hide show
  1. package/dist/index.d.ts +25 -0
  2. package/dist/index.js +105 -0
  3. package/dist/src/app/channel-tools.d.ts +28 -0
  4. package/dist/src/app/channel-tools.js +251 -0
  5. package/dist/src/app/discovery-tools.d.ts +35 -0
  6. package/dist/src/app/discovery-tools.js +243 -0
  7. package/dist/src/app/download-file-tool.d.ts +10 -0
  8. package/dist/src/app/download-file-tool.js +104 -0
  9. package/dist/src/app/hooks.d.ts +14 -0
  10. package/dist/src/app/hooks.js +118 -0
  11. package/dist/src/app/index.d.ts +13 -0
  12. package/dist/src/app/index.js +44 -0
  13. package/dist/src/app/messaging-tools.d.ts +11 -0
  14. package/dist/src/app/messaging-tools.js +79 -0
  15. package/dist/src/app/ops-tools.d.ts +21 -0
  16. package/dist/src/app/ops-tools.js +158 -0
  17. package/dist/src/app/remote-agent-tool.d.ts +27 -0
  18. package/dist/src/app/remote-agent-tool.js +461 -0
  19. package/dist/src/app/types.d.ts +61 -0
  20. package/dist/src/app/types.js +11 -0
  21. package/dist/src/app/upload-file-tool.d.ts +16 -0
  22. package/dist/src/app/upload-file-tool.js +353 -0
  23. package/dist/src/app/verbose-preflight.d.ts +2 -0
  24. package/dist/src/app/verbose-preflight.js +145 -0
  25. package/dist/src/auth/config.d.ts +79 -0
  26. package/dist/src/auth/config.js +133 -0
  27. package/dist/src/auth/credential-manager.d.ts +65 -0
  28. package/dist/src/auth/credential-manager.js +122 -0
  29. package/dist/src/auth/index.d.ts +6 -0
  30. package/dist/src/auth/index.js +6 -0
  31. package/dist/src/auth/verify.d.ts +42 -0
  32. package/dist/src/auth/verify.js +60 -0
  33. package/dist/src/channel.d.ts +269 -0
  34. package/dist/src/channel.js +488 -0
  35. package/dist/src/compat.d.ts +37 -0
  36. package/dist/src/compat.js +70 -0
  37. package/dist/src/config/config-schema.d.ts +56 -0
  38. package/dist/src/config/config-schema.js +34 -0
  39. package/dist/src/messaging/aggregator.d.ts +25 -0
  40. package/dist/src/messaging/aggregator.js +90 -0
  41. package/dist/src/messaging/collector.d.ts +27 -0
  42. package/dist/src/messaging/collector.js +76 -0
  43. package/dist/src/messaging/executor.d.ts +14 -0
  44. package/dist/src/messaging/executor.js +59 -0
  45. package/dist/src/messaging/inbound.d.ts +97 -0
  46. package/dist/src/messaging/inbound.js +63 -0
  47. package/dist/src/messaging/index.d.ts +10 -0
  48. package/dist/src/messaging/index.js +9 -0
  49. package/dist/src/messaging/mention-protocol.d.ts +42 -0
  50. package/dist/src/messaging/mention-protocol.js +74 -0
  51. package/dist/src/messaging/process-c2c-request.d.ts +55 -0
  52. package/dist/src/messaging/process-c2c-request.js +445 -0
  53. package/dist/src/messaging/process-message.d.ts +62 -0
  54. package/dist/src/messaging/process-message.js +282 -0
  55. package/dist/src/messaging/scheduler.d.ts +17 -0
  56. package/dist/src/messaging/scheduler.js +47 -0
  57. package/dist/src/messaging/types.d.ts +34 -0
  58. package/dist/src/messaging/types.js +4 -0
  59. package/dist/src/plugin-ui/assets/openagent-override.js +9278 -0
  60. package/dist/src/plugin-ui/index.d.ts +13 -0
  61. package/dist/src/plugin-ui/index.js +16 -0
  62. package/dist/src/plugin-ui/ui-extension-loader/backup.d.ts +23 -0
  63. package/dist/src/plugin-ui/ui-extension-loader/backup.js +82 -0
  64. package/dist/src/plugin-ui/ui-extension-loader/index.d.ts +28 -0
  65. package/dist/src/plugin-ui/ui-extension-loader/index.js +240 -0
  66. package/dist/src/plugin-ui/ui-extension-loader/locator.d.ts +35 -0
  67. package/dist/src/plugin-ui/ui-extension-loader/locator.js +129 -0
  68. package/dist/src/plugin-ui/ui-extension-loader/manifest.d.ts +26 -0
  69. package/dist/src/plugin-ui/ui-extension-loader/manifest.js +45 -0
  70. package/dist/src/plugin-ui/ui-extension-loader/registry-regex.d.ts +9 -0
  71. package/dist/src/plugin-ui/ui-extension-loader/registry-regex.js +724 -0
  72. package/dist/src/plugin-ui/ui-extension-loader/removed-extensions.d.ts +8 -0
  73. package/dist/src/plugin-ui/ui-extension-loader/removed-extensions.js +58 -0
  74. package/dist/src/plugin-ui/ui-extension-loader/types.d.ts +55 -0
  75. package/dist/src/plugin-ui/ui-extension-loader/types.js +23 -0
  76. package/dist/src/proxy/auth-proxy.d.ts +20 -0
  77. package/dist/src/proxy/auth-proxy.js +337 -0
  78. package/dist/src/runtime/account.d.ts +156 -0
  79. package/dist/src/runtime/account.js +491 -0
  80. package/dist/src/runtime/index.d.ts +5 -0
  81. package/dist/src/runtime/index.js +6 -0
  82. package/dist/src/runtime/plugin-runtime.d.ts +40 -0
  83. package/dist/src/runtime/plugin-runtime.js +72 -0
  84. package/dist/src/runtime/registry.d.ts +41 -0
  85. package/dist/src/runtime/registry.js +60 -0
  86. package/dist/src/sdk/CLASS_MAP.md +143 -0
  87. package/dist/src/sdk/index.d.ts +126 -0
  88. package/dist/src/sdk/index.js +23990 -0
  89. package/dist/src/sdk/modules/cloud-search-module.js +1117 -0
  90. package/dist/src/sdk/modules/follow-module.js +1069 -0
  91. package/dist/src/sdk/modules/group-module.js +7397 -0
  92. package/dist/src/sdk/modules/relationship-module.js +2269 -0
  93. package/dist/src/sdk/modules/signaling-module.js +1468 -0
  94. package/dist/src/sdk/modules/tim-upload-plugin.js +730 -0
  95. package/dist/src/sdk/node-env/http-request.js +90 -0
  96. package/dist/src/sdk/node-env/index.js +57 -0
  97. package/dist/src/sdk/node-env/storage.js +114 -0
  98. package/dist/src/sdk/package.json +10 -0
  99. package/dist/src/sdk/sdk/CLASS_MAP.md +143 -0
  100. package/dist/src/sdk/sdk/index.d.ts +126 -0
  101. package/dist/src/sdk/sdk/index.js +23990 -0
  102. package/dist/src/sdk/sdk/modules/cloud-search-module.js +1117 -0
  103. package/dist/src/sdk/sdk/modules/follow-module.js +1069 -0
  104. package/dist/src/sdk/sdk/modules/group-module.js +7397 -0
  105. package/dist/src/sdk/sdk/modules/relationship-module.js +2269 -0
  106. package/dist/src/sdk/sdk/modules/signaling-module.js +1468 -0
  107. package/dist/src/sdk/sdk/modules/tim-upload-plugin.js +730 -0
  108. package/dist/src/sdk/sdk/node-env/http-request.js +90 -0
  109. package/dist/src/sdk/sdk/node-env/index.js +57 -0
  110. package/dist/src/sdk/sdk/node-env/storage.js +114 -0
  111. package/dist/src/sdk/sdk/package.json +10 -0
  112. package/dist/src/sdk/sdk/tsconfig.json +16 -0
  113. package/dist/src/sdk/tsconfig.json +16 -0
  114. package/dist/src/state/pending-invocation-store.d.ts +26 -0
  115. package/dist/src/state/pending-invocation-store.js +39 -0
  116. package/dist/src/state/store.d.ts +165 -0
  117. package/dist/src/state/store.js +535 -0
  118. package/dist/src/tim/c2c.d.ts +83 -0
  119. package/dist/src/tim/c2c.js +318 -0
  120. package/dist/src/tim/channels.d.ts +95 -0
  121. package/dist/src/tim/channels.js +279 -0
  122. package/dist/src/tim/client.d.ts +54 -0
  123. package/dist/src/tim/client.js +268 -0
  124. package/dist/src/tim/index.d.ts +6 -0
  125. package/dist/src/tim/index.js +6 -0
  126. package/dist/src/tim/messages.d.ts +50 -0
  127. package/dist/src/tim/messages.js +104 -0
  128. package/dist/src/tim/sdk-logger-init.d.ts +13 -0
  129. package/dist/src/tim/sdk-logger-init.js +46 -0
  130. package/dist/src/tools.d.ts +9 -0
  131. package/dist/src/tools.js +8 -0
  132. package/dist/src/transport/factory.d.ts +63 -0
  133. package/dist/src/transport/factory.js +54 -0
  134. package/dist/src/transport/oasn/index.d.ts +12 -0
  135. package/dist/src/transport/oasn/index.js +9 -0
  136. package/dist/src/transport/oasn/oasn-agent-card.d.ts +38 -0
  137. package/dist/src/transport/oasn/oasn-agent-card.js +102 -0
  138. package/dist/src/transport/oasn/oasn-discovery.d.ts +33 -0
  139. package/dist/src/transport/oasn/oasn-discovery.js +97 -0
  140. package/dist/src/transport/oasn/oasn-files.d.ts +64 -0
  141. package/dist/src/transport/oasn/oasn-files.js +174 -0
  142. package/dist/src/transport/oasn/oasn-http.d.ts +98 -0
  143. package/dist/src/transport/oasn/oasn-http.js +362 -0
  144. package/dist/src/transport/oasn/oasn-invocation.d.ts +154 -0
  145. package/dist/src/transport/oasn/oasn-invocation.js +432 -0
  146. package/dist/src/transport/oasn/oasn-normalize.d.ts +6 -0
  147. package/dist/src/transport/oasn/oasn-normalize.js +112 -0
  148. package/dist/src/transport/oasn/oasn-register.d.ts +19 -0
  149. package/dist/src/transport/oasn/oasn-register.js +24 -0
  150. package/dist/src/transport/oasn/oasn-transport.d.ts +114 -0
  151. package/dist/src/transport/oasn/oasn-transport.js +230 -0
  152. package/dist/src/transport/oasn/oasn-types.d.ts +331 -0
  153. package/dist/src/transport/oasn/oasn-types.js +44 -0
  154. package/dist/src/transport/tim/index.d.ts +7 -0
  155. package/dist/src/transport/tim/index.js +6 -0
  156. package/dist/src/transport/tim/tim-transport.d.ts +122 -0
  157. package/dist/src/transport/tim/tim-transport.js +402 -0
  158. package/dist/src/transport/types.d.ts +450 -0
  159. package/dist/src/transport/types.js +38 -0
  160. package/dist/src/util/http.d.ts +21 -0
  161. package/dist/src/util/http.js +93 -0
  162. package/dist/src/util/logger.d.ts +20 -0
  163. package/dist/src/util/logger.js +100 -0
  164. package/dist/src/util/url-resolver.d.ts +7 -0
  165. package/dist/src/util/url-resolver.js +20 -0
  166. package/index.ts +11 -0
  167. package/openclaw.plugin.json +9 -0
  168. package/package.json +7 -4
  169. package/src/app/download-file-tool.ts +133 -0
  170. package/src/app/hooks.ts +89 -5
  171. package/src/app/index.ts +6 -0
  172. package/src/app/remote-agent-tool.ts +46 -0
  173. package/src/app/types.ts +1 -0
  174. package/src/app/upload-file-tool.ts +411 -0
  175. package/src/plugin-ui/assets/openagent-override.js +15 -66
  176. package/src/plugin-ui/modules/agent-book/panel/agent-book.js +0 -61
  177. package/src/plugin-ui/modules/agent-book/panel/agent-data.js +0 -1
  178. package/src/plugin-ui/modules/agent-book/panel/inject-ui.js +14 -3
  179. package/src/plugin-ui/ui-extension-loader/registry-regex.ts +102 -63
  180. package/src/runtime/account.ts +0 -23
  181. package/src/transport/oasn/oasn-files.ts +5 -5
  182. package/src/transport/oasn/oasn-invocation.ts +44 -2
  183. package/src/transport/oasn/oasn-normalize.ts +0 -26
  184. package/src/transport/oasn/oasn-register.ts +8 -81
  185. package/src/transport/oasn/oasn-transport.ts +9 -32
  186. package/src/transport/oasn/oasn-types.ts +53 -6
  187. package/src/transport/types.ts +33 -36
  188. package/src/util/url-resolver.ts +17 -0
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Transport ๅทฅๅŽ‚ โ€”โ€” ๆŒ‰้…็ฝฎๅˆ›ๅปบ AgentTransport ๅฎžไพ‹
3
+ *
4
+ * ่ฎพ่ฎกไพๆฎ๏ผšdocs/specs/2026-06-16-oasn-transport-abstraction-design.md ยง3.1
5
+ *
6
+ * ่ฐƒ็”จๆ–น๏ผˆAccountRuntime๏ผ‰้€š่ฟ‡ transportType ๅญ—ๆฎตๅ†ณๅฎš่ตฐ OASN ่ฟ˜ๆ˜ฏ TIM ่ทฏๅพ„๏ผŒ
7
+ * ๅทฅๅŽ‚ๅ†…้ƒจ lazy-import ๅ„่‡ช็š„ๅฎž็Žฐๆจกๅ—๏ผŒ็กฎไฟใ€Œๆœชๅฏ็”จ็š„ transport ไธ่ฟ›ๅ…ฅ่ฟ่กŒๆ—ถใ€ใ€‚
8
+ * - ้€‰ OASN ๆ—ถไธๅŠ ่ฝฝ TIM SDK๏ผˆ่Š‚็œๅฏๅŠจๅ†…ๅญ˜ & ้ฟๅ…ๆ— ๆ„ไน‰็š„ WebSocket ๆŽขๆต‹๏ผ‰
9
+ * - ้€‰ TIM ๆ—ถไธๅŠ ่ฝฝ OASN HTTP ๅฎขๆˆท็ซฏ๏ผˆๆ›ดๅฐ็š„ๆ”ปๅ‡ป้ข๏ผ‰
10
+ *
11
+ * ๆณจๆ„๏ผštransport ๅฎžไพ‹ๅˆ›ๅปบๅŽๅฟ…้กปๆ˜พๅผ่ฐƒ็”จ ready(credentials) ๆ‰่ƒฝไฝฟ็”จ๏ผŒ
12
+ * ๅทฅๅŽ‚ๅช่ดŸ่ดฃๅฎžไพ‹ๅŒ–๏ผŒไธ่ดŸ่ดฃๅ‡ญ่ฏๆ ก้ชŒๅ’Œ่ฟžๆŽฅใ€‚
13
+ */
14
+ /**
15
+ * ๅˆ›ๅปบ transport ๅฎžไพ‹ใ€‚
16
+ *
17
+ * ๅ…ณ้”ฎ่ฎพ่ฎก๏ผš่ฟ”ๅ›ž็ฑปๅž‹ๆ˜ฏ union `AgentTransport`๏ผŒ่ฐƒ็”จๆ–น้œ€็”จ `transportType` ๅญ—ๆฎต narrow๏ผš
18
+ *
19
+ * ```ts
20
+ * const t = await createTransport({ transportType: 'oasn', apiBase, agentId });
21
+ * if (t.transportType === 'oasn') {
22
+ * // ่ฟ™้‡Œ TypeScript ็Ÿฅ้“ t ๆ˜ฏ OasnTransport โ€”โ€” ๅฏไปฅ่ฐƒ t.registerAgent()
23
+ * await t.registerAgent('openclaw');
24
+ * }
25
+ * ```
26
+ *
27
+ * @throws ๅฝ“ OASN ่ทฏๅพ„ไฝ†็ผบๅฐ‘ apiBase ๆ—ถ
28
+ */
29
+ export async function createTransport(options) {
30
+ if (options.transportType === 'oasn') {
31
+ if (!options.apiBase) {
32
+ throw new Error('createTransport: apiBase is required for OASN transport');
33
+ }
34
+ // lazy import๏ผš้€‰ OASN ๆ—ถๆ‰ๅŠ ่ฝฝ OASN ๆจกๅ—๏ผˆOASN HTTP ๅฎขๆˆท็ซฏไธไพ่ต– TIM SDK๏ผ‰
35
+ const { OasnTransportImpl } = await import('./oasn/oasn-transport.js');
36
+ return new OasnTransportImpl({
37
+ apiBase: options.apiBase,
38
+ accessApiBase: options.accessApiBase,
39
+ agentId: options.agentId ?? '',
40
+ accountId: options.accountId ?? options.agentId ?? 'default',
41
+ // ยง11.1 ๆŒไน…ๅŒ–ๆŒ‚่ฝฝ็‚น๏ผšไป…ๅฝ“ไธŠๅฑ‚ๆไพ› pendingStore ๆ—ถๅฏ็”จ
42
+ ...(options.pendingStore ? { pendingStore: options.pendingStore } : {}),
43
+ });
44
+ }
45
+ if (options.transportType === 'tim') {
46
+ // lazy import๏ผš้€‰ TIM ๆ—ถๆ‰ๅŠ ่ฝฝ TIM SDK๏ผˆ้ฟๅ… OASN ่ทฏๅพ„ไธ‹ๅŠ ่ฝฝ ~2MB ็š„ SDK๏ผ‰
47
+ const { TimTransportImpl } = await import('./tim/tim-transport.js');
48
+ return new TimTransportImpl({
49
+ accountId: options.accountId ?? 'default',
50
+ });
51
+ }
52
+ // ็ผ–่ฏ‘ๆœŸๅทฒๆ˜ฏ 'oasn' | 'tim' ็š„ union๏ผŒ่ฟ่กŒๆœŸ่ฟ˜่ƒฝๅˆฐ่ฟ™้‡Œ่ฏดๆ˜Ž้…็ฝฎๅผ‚ๅธธ
53
+ throw new Error(`createTransport: unknown transportType "${options.transportType}"`);
54
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * OASN transport ๅญๆจกๅ—็ปŸไธ€ๅ‡บๅฃใ€‚
3
+ *
4
+ * ่ฎพ่ฎกไพๆฎ๏ผšdocs/specs/2026-06-16-oasn-transport-abstraction-design.md ยง3.1
5
+ *
6
+ * ไป… re-export ๅฎž็Žฐ็ฑปไธŽ่ทจๆจกๅ—ๅ…ฑ็”จ็ฑปๅž‹ใ€‚OASN ๅ†…้ƒจ API ็ฑปๅž‹๏ผˆsnake_case ๅ่ฎฎๅญ—ๆฎต๏ผ‰
7
+ * ไธๅฏผๅ‡บๅˆฐๅค–ๅฑ‚ โ€”โ€” ไธŠๅฑ‚ๅบ”้ขๅ‘ src/transport/types.ts ็š„้€š็”จ็ฑปๅž‹็ผ–็จ‹ใ€‚
8
+ */
9
+ export { OasnTransportImpl } from './oasn-transport.js';
10
+ export type { OasnTransportInitOptions } from './oasn-transport.js';
11
+ export type { PendingInvocationStore } from './oasn-invocation.js';
12
+ export type { OasnErrorBody } from './oasn-types.js';
@@ -0,0 +1,9 @@
1
+ /**
2
+ * OASN transport ๅญๆจกๅ—็ปŸไธ€ๅ‡บๅฃใ€‚
3
+ *
4
+ * ่ฎพ่ฎกไพๆฎ๏ผšdocs/specs/2026-06-16-oasn-transport-abstraction-design.md ยง3.1
5
+ *
6
+ * ไป… re-export ๅฎž็Žฐ็ฑปไธŽ่ทจๆจกๅ—ๅ…ฑ็”จ็ฑปๅž‹ใ€‚OASN ๅ†…้ƒจ API ็ฑปๅž‹๏ผˆsnake_case ๅ่ฎฎๅญ—ๆฎต๏ผ‰
7
+ * ไธๅฏผๅ‡บๅˆฐๅค–ๅฑ‚ โ€”โ€” ไธŠๅฑ‚ๅบ”้ขๅ‘ src/transport/types.ts ็š„้€š็”จ็ฑปๅž‹็ผ–็จ‹ใ€‚
8
+ */
9
+ export { OasnTransportImpl } from './oasn-transport.js';
@@ -0,0 +1,38 @@
1
+ /**
2
+ * OASN AgentCard CRUD + Owner ๆŸฅ่ฏข
3
+ *
4
+ * ่ฎพ่ฎกไพๆฎ๏ผš
5
+ * - docs/specs/2026-06-16-oasn-api-module-mapping.md ยง2.7 / ยง2.8 / ยง2.9
6
+ *
7
+ * ็ซฏ็‚น๏ผš
8
+ * - GET /api/agent-cards/{agent_id} ๅ…ฌๅผ€ๆŸฅ่ฏข๏ผˆclaimed+active+public ๆ‰ 200๏ผ‰
9
+ * - PATCH /api/agent-cards/{agent_id} Owner ๆˆ– Agent ๆ›ดๆ–ฐ
10
+ * - GET /api/users/me ๅฝ“ๅ‰ Owner๏ผˆOwner access token ๅœบๆ™ฏ๏ผ‰
11
+ */
12
+ import type { AgentCard, AgentCardPatch, OwnerInfo } from '../types.js';
13
+ import type { OasnHttpClient } from './oasn-http.js';
14
+ export declare class OasnAgentCard {
15
+ private readonly _http;
16
+ constructor(_http: OasnHttpClient);
17
+ /**
18
+ * ๆŸฅ่ฏข AgentCard ๅ…ฌๅผ€ไฟกๆฏใ€‚
19
+ *
20
+ * ็”จ้€”๏ผš
21
+ * 1. `connect()` ๆ—ถ้ชŒ่ฏ api_key ๆœ‰ๆ•ˆๆ€ง๏ผˆๅณไฝฟ่ฟ”ๅ›ž 404 ไนŸ่ƒฝ็กฎ่ฎค Bearer ๆฒก่ขซ 401๏ผ‰
22
+ * 2. UI ๅฑ•็คบๅ…ถไป– Agent ็š„่ฏฆๆƒ…
23
+ *
24
+ * 404 ๆ—ถ่ฟ”ๅ›ž null๏ผˆagent ไธๅญ˜ๅœจใ€ๆœช่ฎค้ข†ใ€ๆˆ– private๏ผ‰ใ€‚
25
+ */
26
+ get(agentId: string): Promise<AgentCard | null>;
27
+ /**
28
+ * ๆ›ดๆ–ฐ AgentCardใ€‚
29
+ * PATCH ่ฏญไน‰๏ผš็œ็•ฅๅญ—ๆฎตไธๅ˜๏ผŒๆ˜พๅผ null ๆธ…็ฉบใ€‚
30
+ */
31
+ update(agentId: string, patch: AgentCardPatch): Promise<AgentCard>;
32
+ /**
33
+ * ๆŸฅ่ฏขๅฝ“ๅ‰ Owner๏ผˆไป…ๅฝ“ Bearer ๆ˜ฏ Owner access token ๆ—ถๅฏ็”จ๏ผ‰ใ€‚
34
+ * Agent api_key ่ฐƒ็”จๆญคๆŽฅๅฃๅฏ่ƒฝ่ฟ”ๅ›ž 403ใ€‚
35
+ */
36
+ getCurrentOwner(): Promise<OwnerInfo | null>;
37
+ private _toAgentCard;
38
+ }
@@ -0,0 +1,102 @@
1
+ /**
2
+ * OASN AgentCard CRUD + Owner ๆŸฅ่ฏข
3
+ *
4
+ * ่ฎพ่ฎกไพๆฎ๏ผš
5
+ * - docs/specs/2026-06-16-oasn-api-module-mapping.md ยง2.7 / ยง2.8 / ยง2.9
6
+ *
7
+ * ็ซฏ็‚น๏ผš
8
+ * - GET /api/agent-cards/{agent_id} ๅ…ฌๅผ€ๆŸฅ่ฏข๏ผˆclaimed+active+public ๆ‰ 200๏ผ‰
9
+ * - PATCH /api/agent-cards/{agent_id} Owner ๆˆ– Agent ๆ›ดๆ–ฐ
10
+ * - GET /api/users/me ๅฝ“ๅ‰ Owner๏ผˆOwner access token ๅœบๆ™ฏ๏ผ‰
11
+ */
12
+ import { logger } from '../../util/logger.js';
13
+ import { OASN_ENDPOINTS, } from './oasn-types.js';
14
+ import { normalizeAgentCard } from './oasn-normalize.js';
15
+ export class OasnAgentCard {
16
+ _http;
17
+ constructor(_http) {
18
+ this._http = _http;
19
+ }
20
+ /**
21
+ * ๆŸฅ่ฏข AgentCard ๅ…ฌๅผ€ไฟกๆฏใ€‚
22
+ *
23
+ * ็”จ้€”๏ผš
24
+ * 1. `connect()` ๆ—ถ้ชŒ่ฏ api_key ๆœ‰ๆ•ˆๆ€ง๏ผˆๅณไฝฟ่ฟ”ๅ›ž 404 ไนŸ่ƒฝ็กฎ่ฎค Bearer ๆฒก่ขซ 401๏ผ‰
25
+ * 2. UI ๅฑ•็คบๅ…ถไป– Agent ็š„่ฏฆๆƒ…
26
+ *
27
+ * 404 ๆ—ถ่ฟ”ๅ›ž null๏ผˆagent ไธๅญ˜ๅœจใ€ๆœช่ฎค้ข†ใ€ๆˆ– private๏ผ‰ใ€‚
28
+ */
29
+ async get(agentId) {
30
+ try {
31
+ const resp = await this._http.get(OASN_ENDPOINTS.AGENT_CARD(agentId));
32
+ return this._toAgentCard(resp);
33
+ }
34
+ catch (err) {
35
+ const te = err;
36
+ if (te.code === 'HTTP_404' || te.code === 'AGENT_CARD_NOT_FOUND') {
37
+ logger.info(`[transport/oasn/agent-card] get(${agentId}) โ†’ 404 not found`);
38
+ return null;
39
+ }
40
+ throw err;
41
+ }
42
+ }
43
+ /**
44
+ * ๆ›ดๆ–ฐ AgentCardใ€‚
45
+ * PATCH ่ฏญไน‰๏ผš็œ็•ฅๅญ—ๆฎตไธๅ˜๏ผŒๆ˜พๅผ null ๆธ…็ฉบใ€‚
46
+ */
47
+ async update(agentId, patch) {
48
+ const body = {};
49
+ // ๅชๅคๅˆถๅญ˜ๅœจ็š„ๅญ—ๆฎต๏ผˆundefined ไธๅ‘๏ผŒnull ๆ˜พๅผๅ‘ๅ‡บ๏ผ‰
50
+ if ('name' in patch)
51
+ body.name = patch.name;
52
+ if ('description' in patch)
53
+ body.description = patch.description;
54
+ if ('MOM' in patch)
55
+ body.MOM = patch.MOM;
56
+ if ('tags' in patch)
57
+ body.tags = patch.tags;
58
+ if ('category' in patch)
59
+ body.category = patch.category;
60
+ if ('avatar_ref' in patch)
61
+ body.avatarRef = patch.avatar_ref;
62
+ if ('visibility' in patch)
63
+ body.visibility = patch.visibility;
64
+ if ('public_metadata' in patch)
65
+ body.publicMetadata = patch.public_metadata;
66
+ logger.info(`[transport/oasn/agent-card] update agent=${agentId} fields=${Object.keys(body).join(',')}`);
67
+ const resp = await this._http.patch(OASN_ENDPOINTS.AGENT_CARD(agentId), body);
68
+ return this._toAgentCard(resp);
69
+ }
70
+ /**
71
+ * ๆŸฅ่ฏขๅฝ“ๅ‰ Owner๏ผˆไป…ๅฝ“ Bearer ๆ˜ฏ Owner access token ๆ—ถๅฏ็”จ๏ผ‰ใ€‚
72
+ * Agent api_key ่ฐƒ็”จๆญคๆŽฅๅฃๅฏ่ƒฝ่ฟ”ๅ›ž 403ใ€‚
73
+ */
74
+ async getCurrentOwner() {
75
+ try {
76
+ const resp = await this._http.get(OASN_ENDPOINTS.USERS_ME);
77
+ return {
78
+ owner_id: resp.ownerId ?? resp.owner_id ?? '',
79
+ owner_type: resp.ownerType ?? resp.owner_type ?? '',
80
+ display_name: resp.displayName ?? resp.display_name ?? '',
81
+ email_masked: resp.emailMasked ?? resp.email_masked ?? '',
82
+ ...((resp.emailVerifiedAt ?? resp.email_verified_at)
83
+ ? { email_verified_at: resp.emailVerifiedAt ?? resp.email_verified_at }
84
+ : {}),
85
+ status: resp.status,
86
+ };
87
+ }
88
+ catch (err) {
89
+ const te = err;
90
+ if (te.code === 'HTTP_401' || te.code === 'HTTP_403' || te.code === 'UNAUTHENTICATED') {
91
+ return null;
92
+ }
93
+ throw err;
94
+ }
95
+ }
96
+ // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
97
+ // ๅทฅๅ…ท
98
+ // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
99
+ _toAgentCard(resp) {
100
+ return normalizeAgentCard(resp);
101
+ }
102
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * OASN Discovery โ€”โ€” Agent ๆœ็ดข + Category ๆ ‘
3
+ *
4
+ * ่ฎพ่ฎกไพๆฎ๏ผšdocs/specs/2026-06-16-oasn-api-module-mapping.md ยง2.10 ~ ยง2.13
5
+ *
6
+ * ไธ‰็งๆœ็ดขๆ–นๅผ๏ผŒๆŒ‰้ž็ฉบๅญ—ๆฎต่ทฏ็”ฑๅˆฐๅฏนๅบ”็ซฏ็‚น๏ผš
7
+ * - query โ†’ POST /api/agent-cards/search/by-query ๏ผˆ่‡ช็„ถ่ฏญ่จ€๏ผ‰
8
+ * - categoryโ†’ POST /api/agent-cards/search/by-category ๏ผˆๅˆ†็ฑปๆต่งˆ๏ผ‰
9
+ * - tags โ†’ POST /api/agent-cards/search/by-tags ๏ผˆๆ ‡็ญพ็ญ›้€‰๏ผ‰
10
+ *
11
+ * ๅฝ“ๅ‰ OASN search ไป…ๆ”ฏๆŒ agent_types=['service']๏ผˆ่ฏฆ่ง่ฎพ่ฎกๆ–‡ๆกฃ ยงไน ้ฃŽ้™ฉ่กจ๏ผ‰ใ€‚
12
+ */
13
+ import type { CategoryTree, SearchQuery, SearchResult } from '../types.js';
14
+ import type { OasnHttpClient } from './oasn-http.js';
15
+ export declare class OasnDiscovery {
16
+ private readonly _http;
17
+ constructor(_http: OasnHttpClient);
18
+ /**
19
+ * ่ทฏ็”ฑๅˆฐๅฏนๅบ”ๆœ็ดข็ซฏ็‚นใ€‚
20
+ *
21
+ * ไผ˜ๅ…ˆ็บง๏ผˆไบ’ๆ–ฅไฝฟ็”จ๏ผ‰๏ผšquery > category > tagsใ€‚
22
+ * ๅฝ“ๅคšไธชๅญ—ๆฎต้ƒฝไผ ๅ…ฅๆ—ถ๏ผŒไปฅ query ไธบๅ‡†ๅนถ logger.warn ๆ็คบใ€‚
23
+ */
24
+ search(query: SearchQuery): Promise<SearchResult>;
25
+ private _searchByQuery;
26
+ private _searchByCategory;
27
+ private _searchByTags;
28
+ /** ่Žทๅ– category ๆ ‘๏ผˆ็”จไบŽ Agent Book UI ็š„ๅˆ†็ฑปๆต่งˆ้ขๆฟ๏ผ‰ */
29
+ getCategories(params?: {
30
+ agentType?: string;
31
+ }): Promise<CategoryTree>;
32
+ private _toSearchResult;
33
+ }
@@ -0,0 +1,97 @@
1
+ /**
2
+ * OASN Discovery โ€”โ€” Agent ๆœ็ดข + Category ๆ ‘
3
+ *
4
+ * ่ฎพ่ฎกไพๆฎ๏ผšdocs/specs/2026-06-16-oasn-api-module-mapping.md ยง2.10 ~ ยง2.13
5
+ *
6
+ * ไธ‰็งๆœ็ดขๆ–นๅผ๏ผŒๆŒ‰้ž็ฉบๅญ—ๆฎต่ทฏ็”ฑๅˆฐๅฏนๅบ”็ซฏ็‚น๏ผš
7
+ * - query โ†’ POST /api/agent-cards/search/by-query ๏ผˆ่‡ช็„ถ่ฏญ่จ€๏ผ‰
8
+ * - categoryโ†’ POST /api/agent-cards/search/by-category ๏ผˆๅˆ†็ฑปๆต่งˆ๏ผ‰
9
+ * - tags โ†’ POST /api/agent-cards/search/by-tags ๏ผˆๆ ‡็ญพ็ญ›้€‰๏ผ‰
10
+ *
11
+ * ๅฝ“ๅ‰ OASN search ไป…ๆ”ฏๆŒ agent_types=['service']๏ผˆ่ฏฆ่ง่ฎพ่ฎกๆ–‡ๆกฃ ยงไน ้ฃŽ้™ฉ่กจ๏ผ‰ใ€‚
12
+ */
13
+ import { logger } from '../../util/logger.js';
14
+ import { OASN_ENDPOINTS, } from './oasn-types.js';
15
+ import { normalizeCategoryTree, normalizeSearchResponse } from './oasn-normalize.js';
16
+ export class OasnDiscovery {
17
+ _http;
18
+ constructor(_http) {
19
+ this._http = _http;
20
+ }
21
+ /**
22
+ * ่ทฏ็”ฑๅˆฐๅฏนๅบ”ๆœ็ดข็ซฏ็‚นใ€‚
23
+ *
24
+ * ไผ˜ๅ…ˆ็บง๏ผˆไบ’ๆ–ฅไฝฟ็”จ๏ผ‰๏ผšquery > category > tagsใ€‚
25
+ * ๅฝ“ๅคšไธชๅญ—ๆฎต้ƒฝไผ ๅ…ฅๆ—ถ๏ผŒไปฅ query ไธบๅ‡†ๅนถ logger.warn ๆ็คบใ€‚
26
+ */
27
+ async search(query) {
28
+ const hasQuery = !!query.query && query.query.trim().length > 0;
29
+ const hasCategory = !!query.category && query.category.length > 0;
30
+ const hasTags = !!query.tags && query.tags.length > 0;
31
+ if ([hasQuery, hasCategory, hasTags].filter(Boolean).length > 1) {
32
+ logger.warn('[transport/oasn/discovery] multiple search criteria provided, prioritising query > category > tags');
33
+ }
34
+ if (hasQuery)
35
+ return this._searchByQuery(query);
36
+ if (hasCategory)
37
+ return this._searchByCategory(query);
38
+ if (hasTags)
39
+ return this._searchByTags(query);
40
+ // ้ƒฝไธบ็ฉบ๏ผš้ป˜่ฎค่ตฐ query=""๏ผˆๆœๅŠก็ซฏๅฏ่ƒฝๆ‹’็ป๏ผŒไฝ† transport ไธไธปๅŠจๆŽจๆ–ญ๏ผ‰
41
+ throw new Error('OasnDiscovery.search: at least one of query/category/tags must be provided');
42
+ }
43
+ async _searchByQuery(q) {
44
+ const body = {
45
+ query: q.query.trim(),
46
+ agentTypes: q.agentTypes ?? ['service'],
47
+ };
48
+ if (q.sort)
49
+ body.sort = q.sort;
50
+ if (q.pageSize !== undefined)
51
+ body.pageSize = q.pageSize;
52
+ if (q.pageNum !== undefined)
53
+ body.pageNum = q.pageNum;
54
+ const resp = await this._http.post(OASN_ENDPOINTS.SEARCH_BY_QUERY, body);
55
+ return this._toSearchResult(resp);
56
+ }
57
+ async _searchByCategory(q) {
58
+ const body = {
59
+ category: q.category,
60
+ agentTypes: q.agentTypes ?? ['service'],
61
+ };
62
+ if (q.sort)
63
+ body.sort = q.sort;
64
+ if (q.pageSize !== undefined)
65
+ body.pageSize = q.pageSize;
66
+ if (q.pageNum !== undefined)
67
+ body.pageNum = q.pageNum;
68
+ const resp = await this._http.post(OASN_ENDPOINTS.SEARCH_BY_CATEGORY, body);
69
+ return this._toSearchResult(resp);
70
+ }
71
+ async _searchByTags(q) {
72
+ const body = {
73
+ tags: q.tags,
74
+ agentTypes: q.agentTypes ?? ['service'],
75
+ };
76
+ if (q.sort)
77
+ body.sort = q.sort;
78
+ if (q.pageSize !== undefined)
79
+ body.pageSize = q.pageSize;
80
+ if (q.pageNum !== undefined)
81
+ body.pageNum = q.pageNum;
82
+ const resp = await this._http.post(OASN_ENDPOINTS.SEARCH_BY_TAGS, body);
83
+ return this._toSearchResult(resp);
84
+ }
85
+ /** ่Žทๅ– category ๆ ‘๏ผˆ็”จไบŽ Agent Book UI ็š„ๅˆ†็ฑปๆต่งˆ้ขๆฟ๏ผ‰ */
86
+ async getCategories(params) {
87
+ const qs = params?.agentType ? `?agent_type=${encodeURIComponent(params.agentType)}` : '';
88
+ const resp = await this._http.get(`${OASN_ENDPOINTS.CATEGORIES}${qs}`);
89
+ return normalizeCategoryTree(resp);
90
+ }
91
+ // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
92
+ // ๅทฅๅ…ท
93
+ // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
94
+ _toSearchResult(resp) {
95
+ return normalizeSearchResponse(resp);
96
+ }
97
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * OASN ๆ–‡ไปถไธŠไผ  + Artifact ไธ‹่ฝฝ
3
+ *
4
+ * ่ฎพ่ฎกไพๆฎ๏ผš
5
+ * - docs/specs/2026-06-16-oasn-api-module-mapping.md ยง2.16 / ยง2.17
6
+ * - docs/specs/2026-06-16-oasn-transport-abstraction-design.md ยง11.4๏ผˆfile_ref LRU๏ผ‰
7
+ *
8
+ * ็ซฏ็‚น๏ผš
9
+ * - POST /api/files multipart ไธŠไผ  โ†’ file_ref
10
+ * - GET /api/artifacts/{id}/content ไบŒ่ฟ›ๅˆถไธ‹่ฝฝ๏ผˆๅธฆ Content-Disposition๏ผ‰
11
+ *
12
+ * ยง11.4 file_ref ่ฟ‡ๆœŸๅˆทๆ–ฐ๏ผš
13
+ * - ็ปดๆŠคๅ†…ๅญ˜ LRU๏ผšsha256(content) โ†’ { fileRef, expiresAt, mimeType, displayName }
14
+ * - ไธŠไผ ๅ‰่ฐƒ็”จ ensureFileRef(file)๏ผšๅ‘ฝไธญไธ”ๆœช่ฟ‡ๆœŸ โ†’ ๅค็”จ๏ผ›ๅฆๅˆ™้‡ไผ 
15
+ * - ๆก็›ฎๆ•ฐไธŠ้™ 100๏ผŒๆท˜ๆฑฐ็”จ LRU
16
+ * - expires_at ไธด่ฟ‘ 60s ่ง†ไธบๅทฒ่ฟ‡ๆœŸ๏ผˆ้ฟๅ…่พน็ผ˜็ซžๆ€๏ผ‰
17
+ *
18
+ * ๆณจๆ„๏ผš
19
+ * - LRU ไป…ๅœจๅ•่ฟ›็จ‹ๅ†…ๆœ‰ๆ•ˆ๏ผ›่ฟ›็จ‹้‡ๅฏๅŽไธขๅคฑ๏ผŒไผš่งฆๅ‘ไธ€ๆฌก้‡ไผ ๏ผˆๅฏๆŽฅๅ—๏ผ‰
20
+ * - sha256 ๆ˜ฏ Node ๅ†…็ฝฎ๏ผŒๆ— ๅค–้ƒจไพ่ต–
21
+ */
22
+ import type { DownloadArtifactResult, UploadFileParams, UploadFileResult } from '../types.js';
23
+ import type { OasnHttpClient } from './oasn-http.js';
24
+ export declare class OasnFiles {
25
+ private readonly _http;
26
+ /**
27
+ * ยง11.4 LRU ็ผ“ๅญ˜ใ€‚
28
+ * ๅˆฉ็”จ Map ็š„ๆ’ๅ…ฅ้กบๅบๅคฉ็„ถ = ่ฎฟ้—ฎ้กบๅบ๏ผšๆฏๆฌก่ฎฟ้—ฎๅŽ delete + set ้‡ๆ–ฐๆ’ๅ…ฅๅˆฐๅฐพ้ƒจใ€‚
29
+ */
30
+ private _refCache;
31
+ constructor(_http: OasnHttpClient);
32
+ /**
33
+ * ไธŠไผ ๆ–‡ไปถ๏ผŒ่ฟ”ๅ›ž file_refใ€‚
34
+ *
35
+ * ่ฐƒ็”จๆ–นๅบ”ไผ˜ๅ…ˆ็”จ ensureFileRef() ๅค็”จ๏ผ›ๆœฌๆ–นๆณ•ๆ˜ฏ"ๆ— ่„‘้‡ไผ "่ทฏๅพ„ใ€‚
36
+ */
37
+ uploadFile(file: UploadFileParams): Promise<UploadFileResult>;
38
+ /**
39
+ * ยง11.4 ๅ…ฅๅฃ๏ผšๆ นๆฎๅ†…ๅฎน hash ๅ‘ฝไธญ็ผ“ๅญ˜ๅฐฑๅค็”จ๏ผŒๅฆๅˆ™้‡ไผ ใ€‚
40
+ * sendTask ๅ‰ๅบ”่ฐƒ็”จๆญคๆ–นๆณ•๏ผŒ้ฟๅ… file_ref ่ฟ‡ๆœŸๅฏผ่‡ด invocation 400ใ€‚
41
+ */
42
+ ensureFileRef(file: UploadFileParams): Promise<UploadFileResult>;
43
+ /**
44
+ * ไธ‹่ฝฝ Artifact ๅ†…ๅฎนใ€‚
45
+ *
46
+ * ๆณจๆ„๏ผšไธ็ผ“ๅญ˜๏ผˆartifact ไธ€่ˆฌๆ˜ฏๅคงๆ–‡ไปถ / ไธ€ๆฌกๆ€งๆถˆ่ดน๏ผ‰๏ผŒ้œ€่ฆ็ผ“ๅญ˜็š„่ฏทไธŠๅฑ‚ๅŒ…่ฃ…ใ€‚
47
+ */
48
+ downloadArtifact(artifactIdOrContentUrl: string): Promise<DownloadArtifactResult>;
49
+ /**
50
+ * ๅฎž้™…ไธŠไผ ้€ป่พ‘ใ€‚multipart/form-data๏ผš
51
+ * - file ๆ–‡ไปถไบŒ่ฟ›ๅˆถ
52
+ * - display_name / purpose / expires_in_seconds ๅญ—ๆฎต๏ผˆๆŒ‰้œ€๏ผ‰
53
+ */
54
+ private _doUpload;
55
+ /** Map LRU put๏ผšๆปกไบ†ๅฐฑๆท˜ๆฑฐๆœ€ๆ—ง */
56
+ private _cachePut;
57
+ private _artifactContentPath;
58
+ /** Blob | Buffer โ†’ Buffer */
59
+ private _toBuffer;
60
+ /** sha256 hex โ€”โ€” ๆ ‡่ฏ†ๆ–‡ไปถๅ”ฏไธ€ๆ€ง */
61
+ private _hashBuffer;
62
+ /** ISO 8601 โ†’ epoch ms๏ผˆ่งฃๆžๅคฑ่ดฅๆ—ถ็ป™ 0๏ผŒ่ฎฉ็ผ“ๅญ˜ไธ‹ๆฌก miss๏ผ‰ */
63
+ private _parseExpiresAt;
64
+ }
@@ -0,0 +1,174 @@
1
+ /**
2
+ * OASN ๆ–‡ไปถไธŠไผ  + Artifact ไธ‹่ฝฝ
3
+ *
4
+ * ่ฎพ่ฎกไพๆฎ๏ผš
5
+ * - docs/specs/2026-06-16-oasn-api-module-mapping.md ยง2.16 / ยง2.17
6
+ * - docs/specs/2026-06-16-oasn-transport-abstraction-design.md ยง11.4๏ผˆfile_ref LRU๏ผ‰
7
+ *
8
+ * ็ซฏ็‚น๏ผš
9
+ * - POST /api/files multipart ไธŠไผ  โ†’ file_ref
10
+ * - GET /api/artifacts/{id}/content ไบŒ่ฟ›ๅˆถไธ‹่ฝฝ๏ผˆๅธฆ Content-Disposition๏ผ‰
11
+ *
12
+ * ยง11.4 file_ref ่ฟ‡ๆœŸๅˆทๆ–ฐ๏ผš
13
+ * - ็ปดๆŠคๅ†…ๅญ˜ LRU๏ผšsha256(content) โ†’ { fileRef, expiresAt, mimeType, displayName }
14
+ * - ไธŠไผ ๅ‰่ฐƒ็”จ ensureFileRef(file)๏ผšๅ‘ฝไธญไธ”ๆœช่ฟ‡ๆœŸ โ†’ ๅค็”จ๏ผ›ๅฆๅˆ™้‡ไผ 
15
+ * - ๆก็›ฎๆ•ฐไธŠ้™ 100๏ผŒๆท˜ๆฑฐ็”จ LRU
16
+ * - expires_at ไธด่ฟ‘ 60s ่ง†ไธบๅทฒ่ฟ‡ๆœŸ๏ผˆ้ฟๅ…่พน็ผ˜็ซžๆ€๏ผ‰
17
+ *
18
+ * ๆณจๆ„๏ผš
19
+ * - LRU ไป…ๅœจๅ•่ฟ›็จ‹ๅ†…ๆœ‰ๆ•ˆ๏ผ›่ฟ›็จ‹้‡ๅฏๅŽไธขๅคฑ๏ผŒไผš่งฆๅ‘ไธ€ๆฌก้‡ไผ ๏ผˆๅฏๆŽฅๅ—๏ผ‰
20
+ * - sha256 ๆ˜ฏ Node ๅ†…็ฝฎ๏ผŒๆ— ๅค–้ƒจไพ่ต–
21
+ */
22
+ import { createHash } from 'node:crypto';
23
+ import { logger } from '../../util/logger.js';
24
+ import { OASN_ENDPOINTS } from './oasn-types.js';
25
+ /** LRU ไธŠ้™ */
26
+ const FILE_REF_LRU_MAX = 100;
27
+ /** expires_at ไธด่ฟ‘ๅคšๅฐ‘ ms ่ง†ไธบๅทฒ่ฟ‡ๆœŸ */
28
+ const EXPIRY_MARGIN_MS = 60_000;
29
+ export class OasnFiles {
30
+ _http;
31
+ /**
32
+ * ยง11.4 LRU ็ผ“ๅญ˜ใ€‚
33
+ * ๅˆฉ็”จ Map ็š„ๆ’ๅ…ฅ้กบๅบๅคฉ็„ถ = ่ฎฟ้—ฎ้กบๅบ๏ผšๆฏๆฌก่ฎฟ้—ฎๅŽ delete + set ้‡ๆ–ฐๆ’ๅ…ฅๅˆฐๅฐพ้ƒจใ€‚
34
+ */
35
+ _refCache = new Map();
36
+ constructor(_http) {
37
+ this._http = _http;
38
+ }
39
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
40
+ // ไธŠไผ 
41
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
42
+ /**
43
+ * ไธŠไผ ๆ–‡ไปถ๏ผŒ่ฟ”ๅ›ž file_refใ€‚
44
+ *
45
+ * ่ฐƒ็”จๆ–นๅบ”ไผ˜ๅ…ˆ็”จ ensureFileRef() ๅค็”จ๏ผ›ๆœฌๆ–นๆณ•ๆ˜ฏ"ๆ— ่„‘้‡ไผ "่ทฏๅพ„ใ€‚
46
+ */
47
+ async uploadFile(file) {
48
+ const buffer = await this._toBuffer(file.content);
49
+ return this._doUpload(buffer, file);
50
+ }
51
+ /**
52
+ * ยง11.4 ๅ…ฅๅฃ๏ผšๆ นๆฎๅ†…ๅฎน hash ๅ‘ฝไธญ็ผ“ๅญ˜ๅฐฑๅค็”จ๏ผŒๅฆๅˆ™้‡ไผ ใ€‚
53
+ * sendTask ๅ‰ๅบ”่ฐƒ็”จๆญคๆ–นๆณ•๏ผŒ้ฟๅ… file_ref ่ฟ‡ๆœŸๅฏผ่‡ด invocation 400ใ€‚
54
+ */
55
+ async ensureFileRef(file) {
56
+ const buffer = await this._toBuffer(file.content);
57
+ const hash = this._hashBuffer(buffer);
58
+ const cached = this._refCache.get(hash);
59
+ if (cached && cached.expiresAt - EXPIRY_MARGIN_MS > Date.now()) {
60
+ // LRU touch๏ผš็งปๅˆฐๅฐพ้ƒจ
61
+ this._refCache.delete(hash);
62
+ this._refCache.set(hash, cached);
63
+ logger.info(`[transport/oasn/files] file_ref cache HIT hash=${hash.slice(0, 8)} ref=${cached.fileRef}`);
64
+ return {
65
+ fileRef: cached.fileRef,
66
+ displayName: cached.displayName,
67
+ mimeType: cached.mimeType,
68
+ sizeBytes: cached.sizeBytes,
69
+ expiresAt: cached.expiresAt,
70
+ };
71
+ }
72
+ // ๆœชๅ‘ฝไธญๆˆ–ๅทฒ่ฟ‡ๆœŸ โ†’ ้‡ไผ 
73
+ if (cached) {
74
+ logger.info(`[transport/oasn/files] file_ref cache STALE hash=${hash.slice(0, 8)}, will re-upload`);
75
+ this._refCache.delete(hash);
76
+ }
77
+ const result = await this._doUpload(buffer, file);
78
+ this._cachePut(hash, result);
79
+ return result;
80
+ }
81
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
82
+ // ไธ‹่ฝฝ๏ผˆArtifact ไบŒ่ฟ›ๅˆถๅ†…ๅฎน๏ผ‰
83
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
84
+ /**
85
+ * ไธ‹่ฝฝ Artifact ๅ†…ๅฎนใ€‚
86
+ *
87
+ * ๆณจๆ„๏ผšไธ็ผ“ๅญ˜๏ผˆartifact ไธ€่ˆฌๆ˜ฏๅคงๆ–‡ไปถ / ไธ€ๆฌกๆ€งๆถˆ่ดน๏ผ‰๏ผŒ้œ€่ฆ็ผ“ๅญ˜็š„่ฏทไธŠๅฑ‚ๅŒ…่ฃ…ใ€‚
88
+ */
89
+ async downloadArtifact(artifactIdOrContentUrl) {
90
+ logger.info(`[transport/oasn/files] downloadArtifact ref=${artifactIdOrContentUrl}`);
91
+ const path = this._artifactContentPath(artifactIdOrContentUrl);
92
+ const resp = await this._http.getBinary(path);
93
+ return {
94
+ content: resp.content,
95
+ mimeType: resp.mimeType,
96
+ displayName: resp.displayName,
97
+ };
98
+ }
99
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
100
+ // ๅ†…้ƒจ
101
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
102
+ /**
103
+ * ๅฎž้™…ไธŠไผ ้€ป่พ‘ใ€‚multipart/form-data๏ผš
104
+ * - file ๆ–‡ไปถไบŒ่ฟ›ๅˆถ
105
+ * - display_name / purpose / expires_in_seconds ๅญ—ๆฎต๏ผˆๆŒ‰้œ€๏ผ‰
106
+ */
107
+ async _doUpload(buffer, file) {
108
+ const fields = {
109
+ display_name: file.displayName,
110
+ };
111
+ if (file.purpose)
112
+ fields.purpose = file.purpose;
113
+ if (file.expiresInSeconds !== undefined)
114
+ fields.expires_in_seconds = String(file.expiresInSeconds);
115
+ logger.info(`[transport/oasn/files] upload name=${file.displayName} size=${buffer.byteLength} `
116
+ + `mime=${file.mimeType ?? 'auto'} purpose=${file.purpose ?? 'none'}`);
117
+ const resp = await this._http.postMultipart(OASN_ENDPOINTS.FILES, {
118
+ file: {
119
+ content: buffer,
120
+ filename: file.displayName,
121
+ mimeType: file.mimeType,
122
+ },
123
+ fields,
124
+ });
125
+ return {
126
+ fileRef: resp.fileRef ?? resp.file_ref ?? '',
127
+ displayName: resp.displayName ?? resp.display_name ?? 'unknown',
128
+ mimeType: resp.mimeType ?? resp.mime_type ?? 'application/octet-stream',
129
+ sizeBytes: resp.sizeBytes ?? resp.size_bytes ?? 0,
130
+ expiresAt: this._parseExpiresAt(resp.expiresAt ?? resp.expires_at ?? ''),
131
+ };
132
+ }
133
+ /** Map LRU put๏ผšๆปกไบ†ๅฐฑๆท˜ๆฑฐๆœ€ๆ—ง */
134
+ _cachePut(hash, result) {
135
+ if (this._refCache.size >= FILE_REF_LRU_MAX) {
136
+ // ๆท˜ๆฑฐ็ฌฌไธ€ไธช key๏ผˆMap ่ฟญไปฃ้กบๅบ = ๆ’ๅ…ฅ/touch ้กบๅบ๏ผ‰
137
+ const firstKey = this._refCache.keys().next().value;
138
+ if (firstKey !== undefined) {
139
+ this._refCache.delete(firstKey);
140
+ logger.info(`[transport/oasn/files] LRU evict hash=${firstKey.slice(0, 8)}`);
141
+ }
142
+ }
143
+ this._refCache.set(hash, {
144
+ fileRef: result.fileRef,
145
+ expiresAt: result.expiresAt,
146
+ mimeType: result.mimeType,
147
+ displayName: result.displayName,
148
+ sizeBytes: result.sizeBytes,
149
+ });
150
+ }
151
+ _artifactContentPath(artifactIdOrContentUrl) {
152
+ if (/^https?:\/\//i.test(artifactIdOrContentUrl) || artifactIdOrContentUrl.startsWith('/')) {
153
+ return artifactIdOrContentUrl;
154
+ }
155
+ return OASN_ENDPOINTS.ARTIFACT_CONTENT(artifactIdOrContentUrl);
156
+ }
157
+ /** Blob | Buffer โ†’ Buffer */
158
+ async _toBuffer(content) {
159
+ if (Buffer.isBuffer(content))
160
+ return content;
161
+ // Browser Blob path๏ผˆNode 18+ ๅ†…็ฝฎ Blob๏ผ‰
162
+ const ab = await content.arrayBuffer();
163
+ return Buffer.from(ab);
164
+ }
165
+ /** sha256 hex โ€”โ€” ๆ ‡่ฏ†ๆ–‡ไปถๅ”ฏไธ€ๆ€ง */
166
+ _hashBuffer(buf) {
167
+ return createHash('sha256').update(buf).digest('hex');
168
+ }
169
+ /** ISO 8601 โ†’ epoch ms๏ผˆ่งฃๆžๅคฑ่ดฅๆ—ถ็ป™ 0๏ผŒ่ฎฉ็ผ“ๅญ˜ไธ‹ๆฌก miss๏ผ‰ */
170
+ _parseExpiresAt(iso) {
171
+ const ms = Date.parse(iso);
172
+ return Number.isNaN(ms) ? 0 : ms;
173
+ }
174
+ }