effect 4.1.0 → 4.1.2

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 (445) hide show
  1. package/README.md +30 -0
  2. package/THIRD_PARTY_NOTICES.md +62 -0
  3. package/ai-docs/package.json +2 -2
  4. package/dist/BigDecimal.d.ts +139 -7
  5. package/dist/BigDecimal.d.ts.map +1 -1
  6. package/dist/BigDecimal.js +83 -14
  7. package/dist/BigDecimal.js.map +1 -1
  8. package/dist/ByteSize.d.ts.map +1 -1
  9. package/dist/ByteSize.js +27 -14
  10. package/dist/ByteSize.js.map +1 -1
  11. package/dist/Equal.d.ts +2 -2
  12. package/dist/Equal.d.ts.map +1 -1
  13. package/dist/Equal.js +3 -3
  14. package/dist/Equal.js.map +1 -1
  15. package/dist/Hash.d.ts +3 -2
  16. package/dist/Hash.d.ts.map +1 -1
  17. package/dist/Hash.js +5 -4
  18. package/dist/Hash.js.map +1 -1
  19. package/dist/Iterable.d.ts.map +1 -1
  20. package/dist/Iterable.js +38 -32
  21. package/dist/Iterable.js.map +1 -1
  22. package/dist/JsonSchema.d.ts.map +1 -1
  23. package/dist/JsonSchema.js +27 -6
  24. package/dist/JsonSchema.js.map +1 -1
  25. package/dist/MutableRef.d.ts.map +1 -1
  26. package/dist/MutableRef.js +0 -7
  27. package/dist/MutableRef.js.map +1 -1
  28. package/dist/Path.d.ts.map +1 -1
  29. package/dist/Path.js +5 -1
  30. package/dist/Path.js.map +1 -1
  31. package/dist/Pool.d.ts.map +1 -1
  32. package/dist/Pool.js +2 -1
  33. package/dist/Pool.js.map +1 -1
  34. package/dist/Ref.d.ts.map +1 -1
  35. package/dist/Ref.js +0 -8
  36. package/dist/Ref.js.map +1 -1
  37. package/dist/Schedule.d.ts.map +1 -1
  38. package/dist/Schedule.js +8 -3
  39. package/dist/Schedule.js.map +1 -1
  40. package/dist/Schema.d.ts +2 -1
  41. package/dist/Schema.d.ts.map +1 -1
  42. package/dist/Schema.js +2 -1
  43. package/dist/Schema.js.map +1 -1
  44. package/dist/SchemaRepresentation.d.ts +4 -2
  45. package/dist/SchemaRepresentation.d.ts.map +1 -1
  46. package/dist/SchemaRepresentation.js +4 -2
  47. package/dist/SchemaRepresentation.js.map +1 -1
  48. package/dist/SchemaTransformation.d.ts +2 -2
  49. package/dist/SchemaTransformation.js +2 -2
  50. package/dist/Stream.d.ts.map +1 -1
  51. package/dist/Stream.js +6 -5
  52. package/dist/Stream.js.map +1 -1
  53. package/dist/ai/McpClient.d.ts +171 -19
  54. package/dist/ai/McpClient.d.ts.map +1 -1
  55. package/dist/ai/McpClient.js +277 -66
  56. package/dist/ai/McpClient.js.map +1 -1
  57. package/dist/ai/McpSchema.d.ts +108 -0
  58. package/dist/ai/McpSchema.d.ts.map +1 -1
  59. package/dist/ai/McpSchema.js +99 -0
  60. package/dist/ai/McpSchema.js.map +1 -1
  61. package/dist/ai/McpServer.d.ts +120 -6
  62. package/dist/ai/McpServer.d.ts.map +1 -1
  63. package/dist/ai/McpServer.js +258 -49
  64. package/dist/ai/McpServer.js.map +1 -1
  65. package/dist/ai/Prompt.d.ts.map +1 -1
  66. package/dist/ai/Prompt.js +20 -11
  67. package/dist/ai/Prompt.js.map +1 -1
  68. package/dist/ai/Tool.d.ts.map +1 -1
  69. package/dist/ai/Tool.js +5 -7
  70. package/dist/ai/Tool.js.map +1 -1
  71. package/dist/ai/internal/mcpCore.js +72 -3
  72. package/dist/ai/internal/mcpCore.js.map +1 -1
  73. package/dist/ai/internal/mcpProtocol/v2024_11_05.js +3 -1
  74. package/dist/ai/internal/mcpProtocol/v2024_11_05.js.map +1 -1
  75. package/dist/ai/internal/mcpProtocol/v2025_03_26.js +3 -1
  76. package/dist/ai/internal/mcpProtocol/v2025_03_26.js.map +1 -1
  77. package/dist/ai/internal/mcpProtocol/v2025_06_18.js +3 -1
  78. package/dist/ai/internal/mcpProtocol/v2025_06_18.js.map +1 -1
  79. package/dist/ai/internal/mcpProtocol/v2025_11_25.js +3 -1
  80. package/dist/ai/internal/mcpProtocol/v2025_11_25.js.map +1 -1
  81. package/dist/ai/internal/mcpProtocol/v2026_07_28.js +44 -8
  82. package/dist/ai/internal/mcpProtocol/v2026_07_28.js.map +1 -1
  83. package/dist/ai/internal/mcpProtocol.js +12 -0
  84. package/dist/ai/internal/mcpProtocol.js.map +1 -1
  85. package/dist/ai/internal/mcpRuntime.js +3 -3
  86. package/dist/ai/internal/mcpRuntime.js.map +1 -1
  87. package/dist/ai/internal/mcpSkills.d.ts +2 -0
  88. package/dist/ai/internal/mcpSkills.d.ts.map +1 -0
  89. package/dist/ai/internal/mcpSkills.js +428 -0
  90. package/dist/ai/internal/mcpSkills.js.map +1 -0
  91. package/dist/ai/internal/structured-output.js +11 -2
  92. package/dist/ai/internal/structured-output.js.map +1 -1
  93. package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
  94. package/dist/cluster/ClusterWorkflowEngine.js +30 -11
  95. package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
  96. package/dist/cluster/Entity.d.ts +26 -0
  97. package/dist/cluster/Entity.d.ts.map +1 -1
  98. package/dist/cluster/Entity.js.map +1 -1
  99. package/dist/cluster/MessageStorage.d.ts +6 -6
  100. package/dist/cluster/MessageStorage.d.ts.map +1 -1
  101. package/dist/cluster/MessageStorage.js +1 -3
  102. package/dist/cluster/MessageStorage.js.map +1 -1
  103. package/dist/cluster/Reply.d.ts +1 -1
  104. package/dist/cluster/Reply.d.ts.map +1 -1
  105. package/dist/cluster/Reply.js.map +1 -1
  106. package/dist/cluster/Runners.d.ts.map +1 -1
  107. package/dist/cluster/Runners.js +13 -2
  108. package/dist/cluster/Runners.js.map +1 -1
  109. package/dist/cluster/Sharding.d.ts +13 -0
  110. package/dist/cluster/Sharding.d.ts.map +1 -1
  111. package/dist/cluster/Sharding.js +4 -1
  112. package/dist/cluster/Sharding.js.map +1 -1
  113. package/dist/cluster/internal/clusterAbandon.d.ts.map +1 -1
  114. package/dist/cluster/internal/clusterAbandon.js +6 -4
  115. package/dist/cluster/internal/clusterAbandon.js.map +1 -1
  116. package/dist/cluster/internal/entityManager.js +63 -11
  117. package/dist/cluster/internal/entityManager.js.map +1 -1
  118. package/dist/cluster/internal/transactionNotifications.d.ts +5 -0
  119. package/dist/cluster/internal/transactionNotifications.d.ts.map +1 -0
  120. package/dist/cluster/internal/transactionNotifications.js +5 -0
  121. package/dist/cluster/internal/transactionNotifications.js.map +1 -0
  122. package/dist/crypto/Aead.d.ts +2 -1
  123. package/dist/crypto/Aead.d.ts.map +1 -1
  124. package/dist/crypto/Aead.js +2 -2
  125. package/dist/crypto/Aead.js.map +1 -1
  126. package/dist/crypto/Cipher.d.ts +2 -1
  127. package/dist/crypto/Cipher.d.ts.map +1 -1
  128. package/dist/crypto/Cipher.js +2 -2
  129. package/dist/crypto/Cipher.js.map +1 -1
  130. package/dist/crypto/KeyAgreement.d.ts +3 -2
  131. package/dist/crypto/KeyAgreement.d.ts.map +1 -1
  132. package/dist/crypto/KeyAgreement.js +2 -2
  133. package/dist/crypto/KeyAgreement.js.map +1 -1
  134. package/dist/crypto/KeyFormat.d.ts +33 -1
  135. package/dist/crypto/KeyFormat.d.ts.map +1 -1
  136. package/dist/crypto/KeyFormat.js.map +1 -1
  137. package/dist/crypto/KeyWrap.d.ts +4 -3
  138. package/dist/crypto/KeyWrap.d.ts.map +1 -1
  139. package/dist/crypto/KeyWrap.js +2 -2
  140. package/dist/crypto/KeyWrap.js.map +1 -1
  141. package/dist/crypto/Mac.d.ts +2 -1
  142. package/dist/crypto/Mac.d.ts.map +1 -1
  143. package/dist/crypto/Mac.js +2 -2
  144. package/dist/crypto/Mac.js.map +1 -1
  145. package/dist/crypto/Signature.d.ts +3 -2
  146. package/dist/crypto/Signature.d.ts.map +1 -1
  147. package/dist/crypto/Signature.js +2 -2
  148. package/dist/crypto/Signature.js.map +1 -1
  149. package/dist/crypto/WebCrypto.d.ts +19 -0
  150. package/dist/crypto/WebCrypto.d.ts.map +1 -1
  151. package/dist/crypto/WebCrypto.js.map +1 -1
  152. package/dist/crypto/internal/asymmetric.js.map +1 -1
  153. package/dist/crypto/internal/key.js +3 -2
  154. package/dist/crypto/internal/key.js.map +1 -1
  155. package/dist/encoding/Base64Url.d.ts.map +1 -1
  156. package/dist/encoding/Base64Url.js +26 -3
  157. package/dist/encoding/Base64Url.js.map +1 -1
  158. package/dist/encoding/Json5.d.ts +44 -0
  159. package/dist/encoding/Json5.d.ts.map +1 -0
  160. package/dist/encoding/Json5.js +56 -0
  161. package/dist/encoding/Json5.js.map +1 -0
  162. package/dist/encoding/Jsonc.d.ts +47 -0
  163. package/dist/encoding/Jsonc.d.ts.map +1 -0
  164. package/dist/encoding/Jsonc.js +120 -0
  165. package/dist/encoding/Jsonc.js.map +1 -0
  166. package/dist/encoding/Ndjson.d.ts +5 -4
  167. package/dist/encoding/Ndjson.d.ts.map +1 -1
  168. package/dist/encoding/Ndjson.js +6 -5
  169. package/dist/encoding/Ndjson.js.map +1 -1
  170. package/dist/encoding/SchemaBinary.d.ts +94 -0
  171. package/dist/encoding/SchemaBinary.d.ts.map +1 -1
  172. package/dist/encoding/SchemaBinary.js +219 -6
  173. package/dist/encoding/SchemaBinary.js.map +1 -1
  174. package/dist/encoding/Sse.d.ts +3 -1
  175. package/dist/encoding/Sse.d.ts.map +1 -1
  176. package/dist/encoding/Sse.js +5 -3
  177. package/dist/encoding/Sse.js.map +1 -1
  178. package/dist/encoding/index.d.ts +10 -0
  179. package/dist/encoding/index.d.ts.map +1 -1
  180. package/dist/encoding/index.js +10 -0
  181. package/dist/encoding/index.js.map +1 -1
  182. package/dist/eventlog/EventLog.d.ts +7 -0
  183. package/dist/eventlog/EventLog.d.ts.map +1 -1
  184. package/dist/eventlog/EventLog.js +7 -0
  185. package/dist/eventlog/EventLog.js.map +1 -1
  186. package/dist/eventlog/EventLogServer.d.ts +7 -1
  187. package/dist/eventlog/EventLogServer.d.ts.map +1 -1
  188. package/dist/eventlog/EventLogServer.js +55 -24
  189. package/dist/eventlog/EventLogServer.js.map +1 -1
  190. package/dist/eventlog/EventLogServerEncrypted.d.ts +10 -0
  191. package/dist/eventlog/EventLogServerEncrypted.d.ts.map +1 -1
  192. package/dist/eventlog/EventLogServerEncrypted.js.map +1 -1
  193. package/dist/eventlog/EventLogServerUnencrypted.d.ts +17 -0
  194. package/dist/eventlog/EventLogServerUnencrypted.d.ts.map +1 -1
  195. package/dist/eventlog/EventLogServerUnencrypted.js +14 -2
  196. package/dist/eventlog/EventLogServerUnencrypted.js.map +1 -1
  197. package/dist/eventlog/EventLogSessionAuth.d.ts +21 -0
  198. package/dist/eventlog/EventLogSessionAuth.d.ts.map +1 -1
  199. package/dist/eventlog/EventLogSessionAuth.js +22 -0
  200. package/dist/eventlog/EventLogSessionAuth.js.map +1 -1
  201. package/dist/graphql/GraphQLClient.d.ts +3 -1
  202. package/dist/graphql/GraphQLClient.d.ts.map +1 -1
  203. package/dist/graphql/GraphQLClient.js.map +1 -1
  204. package/dist/graphql/GraphQLClientError.d.ts +14 -9
  205. package/dist/graphql/GraphQLClientError.d.ts.map +1 -1
  206. package/dist/graphql/GraphQLClientError.js +14 -21
  207. package/dist/graphql/GraphQLClientError.js.map +1 -1
  208. package/dist/graphql/GraphQLProtocol.d.ts +12 -3
  209. package/dist/graphql/GraphQLProtocol.d.ts.map +1 -1
  210. package/dist/graphql/GraphQLProtocol.js +4 -1
  211. package/dist/graphql/GraphQLProtocol.js.map +1 -1
  212. package/dist/http/HttpClient.d.ts +204 -16
  213. package/dist/http/HttpClient.d.ts.map +1 -1
  214. package/dist/http/HttpClient.js +93 -13
  215. package/dist/http/HttpClient.js.map +1 -1
  216. package/dist/http/HttpServerRequest.d.ts.map +1 -1
  217. package/dist/http/HttpServerRequest.js +38 -22
  218. package/dist/http/HttpServerRequest.js.map +1 -1
  219. package/dist/http/internal/mimeTypes.d.ts +4 -1
  220. package/dist/http/internal/mimeTypes.d.ts.map +1 -1
  221. package/dist/http/internal/mimeTypes.js +4 -1
  222. package/dist/http/internal/mimeTypes.js.map +1 -1
  223. package/dist/http-api/HttpApiSchema.js +1 -1
  224. package/dist/http-api/HttpApiSchema.js.map +1 -1
  225. package/dist/internal/dateTime.js +66 -27
  226. package/dist/internal/dateTime.js.map +1 -1
  227. package/dist/internal/effect.js +10 -0
  228. package/dist/internal/effect.js.map +1 -1
  229. package/dist/internal/glob.js +234 -56
  230. package/dist/internal/glob.js.map +1 -1
  231. package/dist/internal/graphql.js +21 -7
  232. package/dist/internal/graphql.js.map +1 -1
  233. package/dist/internal/graphqlHeaders.d.ts +7 -0
  234. package/dist/internal/graphqlHeaders.d.ts.map +1 -1
  235. package/dist/internal/graphqlHeaders.js +11 -0
  236. package/dist/internal/graphqlHeaders.js.map +1 -1
  237. package/dist/internal/jsonParser.d.ts +5 -0
  238. package/dist/internal/jsonParser.d.ts.map +1 -0
  239. package/dist/internal/jsonParser.js +280 -0
  240. package/dist/internal/jsonParser.js.map +1 -0
  241. package/dist/internal/persistence.js +8 -1
  242. package/dist/internal/persistence.js.map +1 -1
  243. package/dist/internal/request.js +29 -42
  244. package/dist/internal/request.js.map +1 -1
  245. package/dist/internal/schema/fromJsonSchemaDocument.js +7 -8
  246. package/dist/internal/schema/fromJsonSchemaDocument.js.map +1 -1
  247. package/dist/internal/sql.js +16 -0
  248. package/dist/internal/sql.js.map +1 -1
  249. package/dist/internal/version.js +1 -1
  250. package/dist/jose/JoseError.d.ts +285 -0
  251. package/dist/jose/JoseError.d.ts.map +1 -0
  252. package/dist/jose/JoseError.js +269 -0
  253. package/dist/jose/JoseError.js.map +1 -0
  254. package/dist/jose/Jwe.d.ts +128 -0
  255. package/dist/jose/Jwe.d.ts.map +1 -0
  256. package/dist/jose/Jwe.js +134 -0
  257. package/dist/jose/Jwe.js.map +1 -0
  258. package/dist/jose/Jwk.d.ts +597 -0
  259. package/dist/jose/Jwk.d.ts.map +1 -0
  260. package/dist/jose/Jwk.js +503 -0
  261. package/dist/jose/Jwk.js.map +1 -0
  262. package/dist/jose/Jwks.d.ts +236 -0
  263. package/dist/jose/Jwks.d.ts.map +1 -0
  264. package/dist/jose/Jwks.js +306 -0
  265. package/dist/jose/Jwks.js.map +1 -0
  266. package/dist/jose/Jws.d.ts +177 -0
  267. package/dist/jose/Jws.d.ts.map +1 -0
  268. package/dist/jose/Jws.js +183 -0
  269. package/dist/jose/Jws.js.map +1 -0
  270. package/dist/jose/Jwt.d.ts +270 -0
  271. package/dist/jose/Jwt.d.ts.map +1 -0
  272. package/dist/jose/Jwt.js +293 -0
  273. package/dist/jose/Jwt.js.map +1 -0
  274. package/dist/jose/index.d.ts +51 -0
  275. package/dist/jose/index.d.ts.map +1 -0
  276. package/dist/jose/index.js +52 -0
  277. package/dist/jose/index.js.map +1 -0
  278. package/dist/jose/internal/compact.d.ts +2 -0
  279. package/dist/jose/internal/compact.d.ts.map +1 -0
  280. package/dist/jose/internal/compact.js +179 -0
  281. package/dist/jose/internal/compact.js.map +1 -0
  282. package/dist/net/Host.d.ts.map +1 -1
  283. package/dist/net/Host.js +5 -10
  284. package/dist/net/Host.js.map +1 -1
  285. package/dist/observability/OtlpExporter.d.ts +4 -0
  286. package/dist/observability/OtlpExporter.d.ts.map +1 -1
  287. package/dist/observability/OtlpExporter.js +40 -12
  288. package/dist/observability/OtlpExporter.js.map +1 -1
  289. package/dist/observability/OtlpSerialization.d.ts +1 -1
  290. package/dist/observability/OtlpSerialization.d.ts.map +1 -1
  291. package/dist/observability/OtlpSerialization.js +10 -4
  292. package/dist/observability/OtlpSerialization.js.map +1 -1
  293. package/dist/observability/internal/otlpProtobuf.js +3 -3
  294. package/dist/observability/internal/otlpProtobuf.js.map +1 -1
  295. package/dist/observability/internal/protobuf.js +6 -0
  296. package/dist/observability/internal/protobuf.js.map +1 -1
  297. package/dist/persistence/CircuitBreaker.d.ts +98 -38
  298. package/dist/persistence/CircuitBreaker.d.ts.map +1 -1
  299. package/dist/persistence/CircuitBreaker.js +67 -29
  300. package/dist/persistence/CircuitBreaker.js.map +1 -1
  301. package/dist/persistence/RateLimiter.d.ts +15 -0
  302. package/dist/persistence/RateLimiter.d.ts.map +1 -1
  303. package/dist/persistence/RateLimiter.js +76 -16
  304. package/dist/persistence/RateLimiter.js.map +1 -1
  305. package/dist/persistence/index.d.ts +1 -1
  306. package/dist/persistence/index.js +1 -1
  307. package/dist/reactivity/AtomRegistry.js +17 -7
  308. package/dist/reactivity/AtomRegistry.js.map +1 -1
  309. package/dist/rpc/Rpc.d.ts +1 -1
  310. package/dist/rpc/Rpc.d.ts.map +1 -1
  311. package/dist/rpc/Rpc.js.map +1 -1
  312. package/dist/rpc/RpcClient.d.ts +14 -2
  313. package/dist/rpc/RpcClient.d.ts.map +1 -1
  314. package/dist/rpc/RpcClient.js +38 -21
  315. package/dist/rpc/RpcClient.js.map +1 -1
  316. package/dist/rpc/RpcMessage.d.ts +3 -2
  317. package/dist/rpc/RpcMessage.d.ts.map +1 -1
  318. package/dist/rpc/RpcMessage.js.map +1 -1
  319. package/dist/rpc/RpcServer.d.ts.map +1 -1
  320. package/dist/rpc/RpcServer.js +10 -1
  321. package/dist/rpc/RpcServer.js.map +1 -1
  322. package/dist/sql/Migrator.d.ts +9 -1
  323. package/dist/sql/Migrator.d.ts.map +1 -1
  324. package/dist/sql/Migrator.js +18 -6
  325. package/dist/sql/Migrator.js.map +1 -1
  326. package/dist/sql/SqlClient.d.ts +46 -3
  327. package/dist/sql/SqlClient.d.ts.map +1 -1
  328. package/dist/sql/SqlClient.js +40 -15
  329. package/dist/sql/SqlClient.js.map +1 -1
  330. package/dist/sql/Statement.d.ts +46 -3
  331. package/dist/sql/Statement.d.ts.map +1 -1
  332. package/dist/sql/Statement.js +32 -26
  333. package/dist/sql/Statement.js.map +1 -1
  334. package/dist/workflow/Workflow.d.ts +4 -0
  335. package/dist/workflow/Workflow.d.ts.map +1 -1
  336. package/dist/workflow/Workflow.js.map +1 -1
  337. package/dist/workflow/WorkflowEngine.d.ts.map +1 -1
  338. package/dist/workflow/WorkflowEngine.js +5 -0
  339. package/dist/workflow/WorkflowEngine.js.map +1 -1
  340. package/package.json +7 -3
  341. package/src/BigDecimal.ts +170 -16
  342. package/src/ByteSize.ts +29 -14
  343. package/src/Equal.ts +3 -3
  344. package/src/Hash.ts +5 -4
  345. package/src/Iterable.ts +28 -19
  346. package/src/JsonSchema.ts +45 -7
  347. package/src/MutableRef.ts +1 -8
  348. package/src/Path.ts +6 -1
  349. package/src/Pool.ts +2 -1
  350. package/src/Ref.ts +0 -8
  351. package/src/Schedule.ts +8 -6
  352. package/src/Schema.ts +3 -2
  353. package/src/SchemaRepresentation.ts +4 -2
  354. package/src/SchemaTransformation.ts +2 -2
  355. package/src/Stream.ts +6 -5
  356. package/src/ai/McpClient.ts +488 -91
  357. package/src/ai/McpSchema.ts +119 -0
  358. package/src/ai/McpServer.ts +302 -56
  359. package/src/ai/Prompt.ts +16 -11
  360. package/src/ai/Tool.ts +5 -10
  361. package/src/ai/internal/mcpCore.ts +165 -12
  362. package/src/ai/internal/mcpProtocol/v2024_11_05.ts +3 -1
  363. package/src/ai/internal/mcpProtocol/v2025_03_26.ts +3 -1
  364. package/src/ai/internal/mcpProtocol/v2025_06_18.ts +3 -1
  365. package/src/ai/internal/mcpProtocol/v2025_11_25.ts +3 -1
  366. package/src/ai/internal/mcpProtocol/v2026_07_28.ts +42 -9
  367. package/src/ai/internal/mcpProtocol.ts +15 -0
  368. package/src/ai/internal/mcpRuntime.ts +6 -3
  369. package/src/ai/internal/mcpSkills.ts +480 -0
  370. package/src/ai/internal/structured-output.ts +10 -4
  371. package/src/cluster/ClusterWorkflowEngine.ts +48 -33
  372. package/src/cluster/Entity.ts +52 -0
  373. package/src/cluster/MessageStorage.ts +3 -6
  374. package/src/cluster/Reply.ts +1 -1
  375. package/src/cluster/Runners.ts +16 -2
  376. package/src/cluster/Sharding.ts +17 -1
  377. package/src/cluster/internal/clusterAbandon.ts +7 -7
  378. package/src/cluster/internal/entityManager.ts +89 -15
  379. package/src/cluster/internal/transactionNotifications.ts +7 -0
  380. package/src/crypto/Aead.ts +3 -3
  381. package/src/crypto/Cipher.ts +3 -3
  382. package/src/crypto/KeyAgreement.ts +4 -4
  383. package/src/crypto/KeyFormat.ts +30 -1
  384. package/src/crypto/KeyWrap.ts +6 -6
  385. package/src/crypto/Mac.ts +3 -3
  386. package/src/crypto/Signature.ts +4 -4
  387. package/src/crypto/WebCrypto.ts +20 -0
  388. package/src/crypto/internal/asymmetric.ts +2 -1
  389. package/src/crypto/internal/key.ts +12 -5
  390. package/src/encoding/Base64Url.ts +27 -3
  391. package/src/encoding/Json5.ts +59 -0
  392. package/src/encoding/Jsonc.ts +126 -0
  393. package/src/encoding/Ndjson.ts +6 -5
  394. package/src/encoding/SchemaBinary.ts +228 -7
  395. package/src/encoding/Sse.ts +5 -3
  396. package/src/encoding/index.ts +12 -0
  397. package/src/eventlog/EventLog.ts +7 -0
  398. package/src/eventlog/EventLogServer.ts +67 -24
  399. package/src/eventlog/EventLogServerEncrypted.ts +5 -0
  400. package/src/eventlog/EventLogServerUnencrypted.ts +19 -2
  401. package/src/eventlog/EventLogSessionAuth.ts +26 -0
  402. package/src/graphql/GraphQLClient.ts +3 -1
  403. package/src/graphql/GraphQLClientError.ts +15 -22
  404. package/src/graphql/GraphQLProtocol.ts +12 -3
  405. package/src/http/HttpClient.ts +244 -33
  406. package/src/http/HttpServerRequest.ts +61 -23
  407. package/src/http/internal/mimeTypes.ts +4 -1
  408. package/src/http-api/HttpApiSchema.ts +1 -1
  409. package/src/internal/dateTime.ts +80 -27
  410. package/src/internal/effect.ts +6 -0
  411. package/src/internal/glob.ts +279 -63
  412. package/src/internal/graphql.ts +27 -9
  413. package/src/internal/graphqlHeaders.ts +13 -0
  414. package/src/internal/jsonParser.ts +307 -0
  415. package/src/internal/persistence.ts +9 -1
  416. package/src/internal/request.ts +51 -58
  417. package/src/internal/schema/fromJsonSchemaDocument.ts +11 -10
  418. package/src/internal/sql.ts +25 -0
  419. package/src/internal/version.ts +1 -1
  420. package/src/jose/JoseError.ts +329 -0
  421. package/src/jose/Jwe.ts +196 -0
  422. package/src/jose/Jwk.ts +777 -0
  423. package/src/jose/Jwks.ts +418 -0
  424. package/src/jose/Jws.ts +312 -0
  425. package/src/jose/Jwt.ts +493 -0
  426. package/src/jose/index.ts +58 -0
  427. package/src/jose/internal/compact.ts +195 -0
  428. package/src/net/Host.ts +5 -10
  429. package/src/observability/OtlpExporter.ts +42 -18
  430. package/src/observability/OtlpSerialization.ts +13 -5
  431. package/src/observability/internal/otlpProtobuf.ts +6 -6
  432. package/src/observability/internal/protobuf.ts +10 -0
  433. package/src/persistence/CircuitBreaker.ts +113 -48
  434. package/src/persistence/RateLimiter.ts +97 -19
  435. package/src/persistence/index.ts +1 -1
  436. package/src/reactivity/AtomRegistry.ts +19 -8
  437. package/src/rpc/Rpc.ts +3 -1
  438. package/src/rpc/RpcClient.ts +44 -24
  439. package/src/rpc/RpcMessage.ts +3 -2
  440. package/src/rpc/RpcServer.ts +12 -1
  441. package/src/sql/Migrator.ts +35 -18
  442. package/src/sql/SqlClient.ts +91 -22
  443. package/src/sql/Statement.ts +60 -35
  444. package/src/workflow/Workflow.ts +4 -0
  445. package/src/workflow/WorkflowEngine.ts +5 -0
@@ -1382,6 +1382,125 @@ export class ResourceUpdatedNotification extends Rpc.make("notifications/resourc
1382
1382
  }
1383
1383
  }) {}
1384
1384
 
1385
+ // =============================================================================
1386
+ // Skills
1387
+ // =============================================================================
1388
+
1389
+ /**
1390
+ * Schema for a file of an Agent Skill served under the MCP Skills extension
1391
+ * (SEP-2640), with the digest and size of its content.
1392
+ *
1393
+ * @stability unstable
1394
+ * @category schemas
1395
+ * @since 4.1.1
1396
+ */
1397
+ export class SkillResource extends Schema.Class<SkillResource>(
1398
+ "@effect/ai/McpSchema/SkillResource"
1399
+ )({
1400
+ /**
1401
+ * The resource URI of the file.
1402
+ */
1403
+ uri: Schema.String,
1404
+ /**
1405
+ * The SHA-256 digest of the file's bytes, as `sha256:` followed by 64
1406
+ * lowercase hexadecimal digits.
1407
+ */
1408
+ digest: Schema.String.check(Schema.isPattern(/^sha256:[0-9a-f]{64}$/)),
1409
+ /**
1410
+ * The length of the file's bytes.
1411
+ */
1412
+ size: Schema.Natural
1413
+ }) {}
1414
+
1415
+ /**
1416
+ * Schema for the YAML frontmatter of an Agent Skill's `SKILL.md`, as the
1417
+ * Agent Skills specification defines it (https://agentskills.io/specification).
1418
+ *
1419
+ * **Details**
1420
+ *
1421
+ * Fields the specification does not define are kept unchanged. `McpServer`
1422
+ * checks a skill's frontmatter against this schema before serving it. The
1423
+ * frontmatter of a {@link Skill} received from a server is only checked for
1424
+ * the `name` and `description` that the Skills extension requires; decode it
1425
+ * with this schema for the other fields.
1426
+ *
1427
+ * @stability unstable
1428
+ * @category schemas
1429
+ * @since 4.1.1
1430
+ */
1431
+ export const SkillFrontmatter = Schema.StructWithRest(
1432
+ Schema.Struct({
1433
+ /**
1434
+ * 1 to 64 lowercase letters, digits and hyphens, with no leading, trailing
1435
+ * or consecutive hyphen. It names the directory holding `SKILL.md`.
1436
+ */
1437
+ name: Schema.String.check(Schema.isMaxLength(64), Schema.isPattern(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)),
1438
+ /**
1439
+ * What the skill does and when to use it, in 1 to 1024 characters.
1440
+ */
1441
+ description: Schema.String.check(Schema.isNonEmpty(), Schema.isMaxLength(1024)),
1442
+ /**
1443
+ * The skill's license, or the name of a bundled license file.
1444
+ */
1445
+ license: Schema.optionalKey(Schema.String),
1446
+ /**
1447
+ * Environment requirements, in 1 to 500 characters.
1448
+ */
1449
+ compatibility: Schema.optionalKey(Schema.String.check(Schema.isNonEmpty(), Schema.isMaxLength(500))),
1450
+ /**
1451
+ * Additional properties not defined by the specification.
1452
+ */
1453
+ metadata: Schema.optionalKey(Schema.Record(Schema.String, Schema.String)),
1454
+ /**
1455
+ * Space-separated tools the skill asks to run without approval. Hosts must
1456
+ * ignore it for a skill served over MCP unless the user approved the grant.
1457
+ */
1458
+ "allowed-tools": Schema.optionalKey(Schema.String)
1459
+ }),
1460
+ [UnknownObject]
1461
+ )
1462
+
1463
+ /**
1464
+ * The YAML frontmatter of an Agent Skill's `SKILL.md`.
1465
+ *
1466
+ * @stability unstable
1467
+ * @category models
1468
+ * @since 4.1.1
1469
+ */
1470
+ export type SkillFrontmatter = typeof SkillFrontmatter.Type
1471
+
1472
+ /**
1473
+ * Schema for an Agent Skill served under the MCP Skills extension (SEP-2640),
1474
+ * as `skills/list` and `skills/get` describe it.
1475
+ *
1476
+ * @stability unstable
1477
+ * @category schemas
1478
+ * @since 4.1.1
1479
+ */
1480
+ export class Skill extends Schema.Class<Skill>(
1481
+ "@effect/ai/McpSchema/Skill"
1482
+ )({
1483
+ /**
1484
+ * The resource URI of the skill's `SKILL.md`.
1485
+ */
1486
+ uri: Schema.String,
1487
+ /**
1488
+ * The YAML frontmatter of the skill's `SKILL.md`, as a JSON object, with
1489
+ * every field the author wrote. See {@link SkillFrontmatter} for the fields
1490
+ * the Agent Skills specification defines.
1491
+ */
1492
+ frontmatter: Schema.StructWithRest(
1493
+ Schema.Struct({ name: Schema.String, description: Schema.String }),
1494
+ [UnknownObject]
1495
+ ),
1496
+ /**
1497
+ * Every file of the skill, `SKILL.md` included, or `"dynamic"` when the
1498
+ * server generates the skill's content and publishes no digests.
1499
+ */
1500
+ resources: Schema.Union([Schema.Array(SkillResource), Schema.Literal("dynamic")]),
1501
+ _meta: optional(UnknownObject)
1502
+ }) {}
1503
+
1385
1504
  // =============================================================================
1386
1505
  // Prompts
1387
1506
  // =============================================================================
@@ -14,6 +14,7 @@
14
14
  import * as Arr from "../Array.ts"
15
15
  import * as Cause from "../Cause.ts"
16
16
  import * as Context from "../Context.ts"
17
+ import * as Digest from "../crypto/Digest.ts"
17
18
  import * as Data from "../Data.ts"
18
19
  import * as Deferred from "../Deferred.ts"
19
20
  import * as Duration from "../Duration.ts"
@@ -53,6 +54,7 @@ import * as AiError from "./AiError.ts"
53
54
  import * as McpCore from "./internal/mcpCore.ts"
54
55
  import * as McpProtocolInternal from "./internal/mcpProtocol.ts"
55
56
  import * as McpRuntime from "./internal/mcpRuntime.ts"
57
+ import * as McpSkills from "./internal/mcpSkills.ts"
56
58
  import * as InternalStructuredOutput from "./internal/structured-output.ts"
57
59
  import type * as McpProtocol from "./McpProtocol.ts"
58
60
  import * as McpSchema from "./McpSchema.ts"
@@ -106,6 +108,8 @@ interface QueuedServerNotification {
106
108
 
107
109
  const internalState = new WeakMap<object, {
108
110
  readonly core: McpCore.McpCore
111
+ // Registers a skill's own file, skipping the check that reserves it for the skill.
112
+ readonly addSkillFile: McpServer["Service"]["addResource"]
109
113
  readonly notifications: Queue.Dequeue<QueuedServerNotification>
110
114
  readonly notificationDelivery: { consumers: number; listChangeRevision: number; requestEndpoints: number }
111
115
  readonly globalMiddleware: Array<middleware.Fn<any, any, any>>
@@ -314,6 +318,9 @@ export type MiddlewareMethod =
314
318
  | "resources/list"
315
319
  | "resources/templates/list"
316
320
  | "prompts/list"
321
+ | "skills/list"
322
+ | "skills/get"
323
+ | "resources/directory/read"
317
324
 
318
325
  /**
319
326
  * Request metadata passed to MCP middleware.
@@ -322,12 +329,17 @@ export type MiddlewareMethod =
322
329
  *
323
330
  * `target` is the tool name, the requested resource URI, or the prompt name.
324
331
  * For `completion/complete` it is the prompt name, or the URI template of the
325
- * resource template being completed. `payload` holds the request parameters.
332
+ * resource template being completed. For `skills/get` it is the URI of the
333
+ * skill's `SKILL.md`. `payload` holds the request parameters.
326
334
  *
327
335
  * On list requests, middleware runs only when it wraps a {@link visibility},
328
336
  * once for each registration it wraps. `target` is then the tool name, the
329
337
  * resource URI, the URI template or the prompt name of that registration, and
330
- * `payload` is `undefined`.
338
+ * `payload` is `undefined`. `skills/list` and `resources/directory/read` are
339
+ * list requests whose `target` is the `SKILL.md` URI of each skill; a
340
+ * directory read checks only the skills that have the directory. A skill's
341
+ * files are resources, checked as `resources/list` and `resources/read` with
342
+ * their own URIs.
331
343
  *
332
344
  * `headers` are the HTTP request headers. They are empty on stdio, on custom
333
345
  * transports and for in-process calls. `sessionId` is the `Mcp-Session-Id`
@@ -725,23 +737,48 @@ class MiddlewareImpl {
725
737
  }
726
738
  }
727
739
 
728
- // The innermost middleware comes first.
740
+ // The innermost middleware comes first. Each stack keeps its own order, and
741
+ // where that leaves the order open, stacks provided further outside, which come
742
+ // first in the context, run further outside. Stacks that order the same
743
+ // middleware both ways have no common order, so insertion order decides.
729
744
  const getMiddleware = (context: Context.Context<never>): ReadonlyArray<AnyMiddlewareFn> => {
730
- const stacks: Array<ReadonlyArray<AnyMiddlewareFn>> = []
731
- let maxLength = 0
732
- for (const [key, value] of context.mapUnsafe) {
733
- if (key.startsWith(middlewareKeyPrefix)) {
734
- stacks.push(value)
735
- maxLength = Math.max(maxLength, value.length)
745
+ // The middleware directly inside each middleware, and how many of those
746
+ // directly outside it are still unplaced.
747
+ const inners = new Map<AnyMiddlewareFn, Array<AnyMiddlewareFn>>()
748
+ const unplacedOuters = new Map<AnyMiddlewareFn, number>()
749
+ for (const [key, stack] of context.mapUnsafe) {
750
+ if (!key.startsWith(middlewareKeyPrefix)) continue
751
+ for (let i = stack.length - 1; i >= 0; i--) {
752
+ const fn = stack[i]
753
+ if (!inners.has(fn)) {
754
+ inners.set(fn, [])
755
+ unplacedOuters.set(fn, 0)
756
+ }
757
+ const outer = stack[i + 1]
758
+ if (outer !== undefined && outer !== fn) {
759
+ inners.get(outer)!.push(fn)
760
+ unplacedOuters.set(fn, unplacedOuters.get(fn)! + 1)
761
+ }
736
762
  }
737
763
  }
738
- const unique = new Set<AnyMiddlewareFn>()
739
- for (let i = maxLength - 1; i >= 0; i--) {
740
- for (const stack of stacks) {
741
- if (i < stack.length) unique.add(stack[i])
764
+ // Repeatedly places the first middleware with nothing left to place outside it.
765
+ const outermostFirst: Array<AnyMiddlewareFn> = []
766
+ while (unplacedOuters.size > 0) {
767
+ let next = unplacedOuters.keys().next().value!
768
+ for (const [fn, count] of unplacedOuters) {
769
+ if (count === 0) {
770
+ next = fn
771
+ break
772
+ }
773
+ }
774
+ unplacedOuters.delete(next)
775
+ outermostFirst.push(next)
776
+ for (const fn of inners.get(next)!) {
777
+ const count = unplacedOuters.get(fn)
778
+ if (count !== undefined) unplacedOuters.set(fn, count - 1)
742
779
  }
743
780
  }
744
- return Arr.fromIterable(unique).reverse()
781
+ return outermostFirst.reverse()
745
782
  }
746
783
 
747
784
  const isMcpError = (error: unknown): error is McpErrorBase =>
@@ -759,7 +796,7 @@ const internalError = new InternalError({ message: "Internal error" })
759
796
  const rejectWith = (error: McpErrorBase) =>
760
797
  Effect.fail(new McpCore.RequestRejected({ code: error.code, message: error.message, data: error.data, error }))
761
798
 
762
- type CallMethod = "tools/call" | "resources/read" | "prompts/get" | "completion/complete"
799
+ type CallMethod = "tools/call" | "resources/read" | "prompts/get" | "completion/complete" | "skills/get"
763
800
 
764
801
  type ListMethod = Exclude<MiddlewareMethod, CallMethod>
765
802
 
@@ -768,6 +805,7 @@ interface NotFoundErrors {
768
805
  readonly "resources/read": McpCore.ResourceNotFound
769
806
  readonly "prompts/get": McpCore.PromptNotFound
770
807
  readonly "completion/complete": InvalidParams
808
+ readonly "skills/get": McpCore.SkillNotFound
771
809
  }
772
810
 
773
811
  const notFound = (method: CallMethod, target: string): NotFoundErrors[CallMethod] => {
@@ -780,6 +818,8 @@ const notFound = (method: CallMethod, target: string): NotFoundErrors[CallMethod
780
818
  return new McpCore.PromptNotFound({ name: target })
781
819
  case "completion/complete":
782
820
  return new InvalidParams({ message: "Unknown completion reference or argument" })
821
+ case "skills/get":
822
+ return new McpCore.SkillNotFound({ uri: target })
783
823
  }
784
824
  }
785
825
 
@@ -1127,6 +1167,38 @@ export class McpServer extends Context.Service<McpServer, {
1127
1167
  ))
1128
1168
  })
1129
1169
 
1170
+ // Checking skill ownership and both writes happen in one synchronous step,
1171
+ // so a skill cannot claim the URI in between. Skill files skip the check.
1172
+ const addResource = (
1173
+ options: Parameters<McpServer["Service"]["addResource"]>[0],
1174
+ checkOwnership: boolean
1175
+ ): Effect.Effect<void> =>
1176
+ Effect.suspend(() => {
1177
+ if (checkOwnership && internalCore.skills.ownsFile(options.resource.uri)) {
1178
+ return Effect.die(
1179
+ new Cause.IllegalArgumentError(`Resource ${options.resource.uri} is a file of a registered skill`)
1180
+ )
1181
+ }
1182
+ const existingIndex = resources.findIndex(({ resource }) => resource.uri === options.resource.uri)
1183
+ if (existingIndex === -1) {
1184
+ resources.push(options)
1185
+ } else {
1186
+ resources[existingIndex] = options
1187
+ }
1188
+ const { invoke, visible } = makeInvoke(options.services, globalMiddleware)
1189
+ internalCore.resources.register({
1190
+ descriptor: options.resource,
1191
+ visible: visible("resources/list", options.resource.uri),
1192
+ isVisible: isEnabled(options.annotations),
1193
+ read: (invocation) =>
1194
+ invoke(options.handle, invocation, {
1195
+ method: "resources/read",
1196
+ target: options.resource.uri,
1197
+ payload: { uri: options.resource.uri }
1198
+ })
1199
+ })
1200
+ return notifications.client["notifications/resources/list_changed"]({})
1201
+ })
1130
1202
  const service = McpServer.of({
1131
1203
  notifications: notifications.client,
1132
1204
  notifyElicitationComplete: ({ clientId, elicitationId }) =>
@@ -1222,27 +1294,7 @@ export class McpServer extends Context.Service<McpServer, {
1222
1294
  get resourceTemplates() {
1223
1295
  return resourceTemplates
1224
1296
  },
1225
- addResource: Effect.fnUntraced(function*(options) {
1226
- const existingIndex = resources.findIndex(({ resource }) => resource.uri === options.resource.uri)
1227
- if (existingIndex === -1) {
1228
- resources.push(options)
1229
- } else {
1230
- resources[existingIndex] = options
1231
- }
1232
- const { invoke, visible } = makeInvoke(options.services, globalMiddleware)
1233
- yield* internalCore.resources.register({
1234
- descriptor: options.resource,
1235
- visible: visible("resources/list", options.resource.uri),
1236
- isVisible: isEnabled(options.annotations),
1237
- read: (invocation) =>
1238
- invoke(options.handle, invocation, {
1239
- method: "resources/read",
1240
- target: options.resource.uri,
1241
- payload: { uri: options.resource.uri }
1242
- })
1243
- })
1244
- yield* notifications.client["notifications/resources/list_changed"]({})
1245
- }),
1297
+ addResource: (options) => addResource(options, true),
1246
1298
  addResourceTemplate: Effect.fnUntraced(
1247
1299
  function*({ annotations, completions, handle, routerPath, services, template }) {
1248
1300
  const existingIndex = resourceTemplates.findIndex(({ template: current }) =>
@@ -1400,6 +1452,7 @@ export class McpServer extends Context.Service<McpServer, {
1400
1452
  })
1401
1453
  internalState.set(service, {
1402
1454
  core: internalCore,
1455
+ addSkillFile: (options) => addResource(options, false),
1403
1456
  notifications: notificationsQueue,
1404
1457
  notificationDelivery,
1405
1458
  globalMiddleware
@@ -1467,9 +1520,11 @@ export interface CacheHint {
1467
1520
  *
1468
1521
  * Each entry sets the freshness and `cacheScope` of one result kind:
1469
1522
  * `server/discover`, `tools/list`, `resources/list`,
1470
- * `resources/templates/list` and `prompts/list`. Omitted entries, and
1471
- * `resources/read` results, keep `{ ttlMs: 0, cacheScope: "private" }`.
1472
- * Earlier protocol revisions have no cache hints and ignore this option.
1523
+ * `resources/templates/list` and `prompts/list`. `skills` covers the Skills
1524
+ * extension's `skills/list`, `skills/get` and `resources/directory/read`.
1525
+ * Omitted entries, and `resources/read` results, keep
1526
+ * `{ ttlMs: 0, cacheScope: "private" }`. Earlier protocol revisions have no
1527
+ * cache hints and ignore this option.
1473
1528
  *
1474
1529
  * These are hints for clients. The server does not cache results, and
1475
1530
  * visibility and invocation checks still run on every request.
@@ -1491,6 +1546,7 @@ export interface CacheHints {
1491
1546
  readonly resources?: CacheHint | undefined
1492
1547
  readonly resourceTemplates?: CacheHint | undefined
1493
1548
  readonly prompts?: CacheHint | undefined
1549
+ readonly skills?: CacheHint | undefined
1494
1550
  }
1495
1551
 
1496
1552
  // Converts each hint to the wire's nonnegative integer `ttlMs` once, when the server is built.
@@ -2068,7 +2124,7 @@ const runWithRuntime = Effect.fnUntraced(function*(
2068
2124
  const selectedProtocol = clientState?.protocol ?? runtime.protocols[0]
2069
2125
  const profile = reverseKey?.profile ?? clientState?.profile ?? {
2070
2126
  protocolVersion: selectedProtocol.protocolVersion,
2071
- clientCapabilities: {},
2127
+ clientCapabilities: new McpSchema.ClientCapabilities({}),
2072
2128
  clientInfo: { name: "unknown", version: "unknown" }
2073
2129
  }
2074
2130
  return RcMap.get(
@@ -3050,14 +3106,40 @@ export const registerToolkit: <Tools extends Record<string, Tool.Any>>(
3050
3106
  const annotations = tool.annotations
3051
3107
  const toolMeta = Context.getOrUndefined(annotations, Tool.Meta)
3052
3108
  const isDeclaredFailure = Schema.is(tool.failureSchema)
3053
- const encodeFailure = Schema.encodeUnknownEffect(tool.failureSchema) as (
3054
- error: unknown
3055
- ) => Effect.Effect<unknown, Schema.SchemaError, Tool.HandlerServices<Tools[keyof Tools]>>
3109
+ // MCP content is JSON, so results and declared failures go through their JSON codec.
3110
+ const encodeJson = (schema: Schema.Constraint) => {
3111
+ const encode = Schema.encodeUnknownEffect(Schema.toCodecJson(schema)) as (
3112
+ value: unknown
3113
+ ) => Effect.Effect<unknown, Schema.SchemaError, Tool.HandlerServices<Tools[keyof Tools]>>
3114
+ return (toolResult: unknown) =>
3115
+ Effect.mapError(encode(toolResult), (cause) =>
3116
+ AiError.make({
3117
+ module: "McpServer",
3118
+ method: "registerToolkit",
3119
+ reason: new AiError.ToolResultEncodingError({
3120
+ toolName: tool.name,
3121
+ toolResult,
3122
+ description: cause.message
3123
+ })
3124
+ }))
3125
+ }
3126
+ const encodeFailure = encodeJson(tool.failureSchema)
3127
+ // Successes and "return"-mode failures arrive already encoded by the Toolkit; only their JSON conversion runs here.
3128
+ const encodeReturnedFailure = encodeJson(Schema.toEncoded(tool.failureSchema))
3129
+ const encodeStructured = encodeJson(Schema.toEncoded(tool.successSchema))
3130
+ const failureResult = (encoded: unknown) =>
3131
+ new CallToolResult({ isError: true, content: toolResultContent(encoded) })
3056
3132
  const declaredFailureResult = (error: unknown) =>
3057
3133
  error instanceof Error && error.message !== ""
3058
3134
  ? Effect.succeed(toolErrorResult(error.message))
3059
- : Effect.map(encodeFailure(error), (encoded) =>
3060
- new CallToolResult({ isError: true, content: toolResultContent(encoded) }))
3135
+ : Effect.map(encodeFailure(error), failureResult)
3136
+ const successResult = (result: unknown) =>
3137
+ Effect.map(encodeStructured(result), (structuredContent) =>
3138
+ new CallToolResult({
3139
+ isError: false,
3140
+ structuredContent,
3141
+ content: toolResultContent(structuredContent)
3142
+ }))
3061
3143
  const handleCause = (cause: Cause.Cause<unknown>) => {
3062
3144
  const failure = Cause.findFail(cause)
3063
3145
  if (Result.isSuccess(failure)) {
@@ -3113,21 +3195,25 @@ export const registerToolkit: <Tools extends Record<string, Tool.Any>>(
3113
3195
  Stream.unwrap,
3114
3196
  Stream.runLast,
3115
3197
  Effect.flatMap(Effect.fromOption),
3116
- Effect.flatMap((result) =>
3198
+ Effect.flatMap((result): Effect.Effect<
3199
+ CallToolResult,
3200
+ unknown,
3201
+ Tool.HandlerServices<Tools[keyof Tools]>
3202
+ > => {
3203
+ if (!result.isFailure) {
3204
+ // An absent result, such as `Schema.Void`, has no structured form.
3205
+ return result.encodedResult === undefined
3206
+ ? Effect.succeed(new CallToolResult({ isError: false, content: [] }))
3207
+ : successResult(result.encodedResult)
3208
+ }
3117
3209
  // Declared failures return their encoded payload; anything else is classified by origin.
3118
- result.isFailure && result.failureOrigin !== "handler"
3119
- ? Effect.failCause(Cause.annotate(
3210
+ return result.failureOrigin === "handler"
3211
+ ? Effect.map(encodeReturnedFailure(result.encodedResult), failureResult)
3212
+ : Effect.failCause(Cause.annotate(
3120
3213
  Cause.fail(result.result),
3121
3214
  Context.make(Toolkit.FailureOrigin, result.failureOrigin ?? "result")
3122
3215
  ))
3123
- : Effect.succeed(
3124
- new CallToolResult({
3125
- isError: result.isFailure,
3126
- structuredContent: result.isFailure ? undefined : result.encodedResult,
3127
- content: toolResultContent(result.encodedResult)
3128
- })
3129
- )
3130
- ),
3216
+ }),
3131
3217
  Effect.catchCause(handleCause)
3132
3218
  ) as Effect.Effect<CallToolResult, InvalidParams, never>
3133
3219
  },
@@ -3565,6 +3651,166 @@ export const resource: {
3565
3651
  return (options: any) => Layer.effectDiscard(register(options))
3566
3652
  } as any
3567
3653
 
3654
+ /**
3655
+ * A file of a skill: its text, its bytes, or either with an explicit MIME
3656
+ * type. Without one, the MIME type is inferred from the file extension.
3657
+ *
3658
+ * @stability unstable
3659
+ * @category models
3660
+ * @since 4.1.1
3661
+ */
3662
+ export type SkillFile = string | Uint8Array | {
3663
+ readonly content: string | Uint8Array
3664
+ readonly mimeType?: string | undefined
3665
+ }
3666
+
3667
+ /**
3668
+ * Options for {@link registerSkill} and {@link skill}.
3669
+ *
3670
+ * **Details**
3671
+ *
3672
+ * `uri` addresses the skill's `SKILL.md`, as
3673
+ * `skill://<skill-path>/SKILL.md`. Its last path segment is the skill's name,
3674
+ * which must equal the frontmatter's `name`. Other schemes work the same way.
3675
+ *
3676
+ * `files` maps paths relative to the skill root to the skill's files,
3677
+ * `SKILL.md` included. Files are served verbatim, and the skill's listed
3678
+ * frontmatter is parsed from `SKILL.md`. Quote frontmatter strings that a YAML
3679
+ * 1.1 parser reads as another type, such as `yes` or `1.0`.
3680
+ *
3681
+ * @stability unstable
3682
+ * @category models
3683
+ * @since 4.1.1
3684
+ */
3685
+ export interface SkillOptions {
3686
+ readonly uri: string
3687
+ readonly files: { readonly "SKILL.md": SkillFile } & Readonly<Record<string, SkillFile>>
3688
+ readonly annotations?: Context.Context<never> | undefined
3689
+ }
3690
+
3691
+ const skillFileEncoder = new TextEncoder()
3692
+
3693
+ // Bytes are copied so that later changes by the caller cannot alter what is
3694
+ // served under the listed digest. `Buffer#slice` shares memory, so copy with
3695
+ // the `Uint8Array` constructor.
3696
+ const toSkillSourceFile = (path: string, file: SkillFile): McpSkills.SourceFile => {
3697
+ const { content, mimeType } = typeof file === "string" || file instanceof Uint8Array ? { content: file } : file
3698
+ return {
3699
+ path,
3700
+ content: typeof content === "string" ? skillFileEncoder.encode(content) : new Uint8Array(content),
3701
+ mimeType
3702
+ }
3703
+ }
3704
+
3705
+ /**
3706
+ * Registers an Agent Skill under the MCP Skills extension (SEP-2640).
3707
+ *
3708
+ * **Details**
3709
+ *
3710
+ * Each file is registered as a resource, and the skill is listed by
3711
+ * `skills/list` and `skills/get` with a manifest of every file's SHA-256
3712
+ * digest and size, computed from the bytes served. Every directory of the
3713
+ * skill namespace is readable with `resources/directory/read`. The server
3714
+ * declares the extension once any skill is registered.
3715
+ *
3716
+ * Fails when the skill breaks the extension's rules: a name that does not
3717
+ * match the URI, a `SKILL.md` without YAML frontmatter, frontmatter that is
3718
+ * not valid {@link McpSchema.SkillFrontmatter}, a file path that leaves the
3719
+ * skill, or more than 512 files or 16 MiB in all. It also fails when the
3720
+ * skill's directory contains or lies inside another skill's, or one of its
3721
+ * files is already registered as a resource. Registering a resource at the
3722
+ * URI of a skill's file afterwards is a defect.
3723
+ *
3724
+ * SHA-256 runs on `crypto.subtle`.
3725
+ *
3726
+ * @see {@link skill} for the layer-based skill registration wrapper
3727
+ *
3728
+ * @stability unstable
3729
+ * @category handlers
3730
+ * @since 4.1.1
3731
+ */
3732
+ export const registerSkill: (options: SkillOptions) => Effect.Effect<void, Cause.IllegalArgumentError, McpServer> =
3733
+ Effect.fnUntraced(function*(options: SkillOptions) {
3734
+ const files = Object.entries(options.files).map(([path, file]) => toSkillSourceFile(path, file))
3735
+ const skill = yield* McpSkills.makeStaticSkill({ uri: options.uri, files }).pipe(
3736
+ Effect.provide(Digest.layerWebCrypto)
3737
+ )
3738
+
3739
+ const registry = yield* McpServer
3740
+ const { addSkillFile, core, globalMiddleware } = internalState.get(registry)!
3741
+ const services = yield* Effect.context<never>()
3742
+ const annotations = options.annotations ?? Context.empty()
3743
+ const { invoke, visible } = makeInvoke(services, globalMiddleware)
3744
+ // Claims the skill's file URIs before they are registered as resources.
3745
+ yield* core.skills.register({
3746
+ entry: skill.entry,
3747
+ isVisible: isEnabled(annotations),
3748
+ visible: visible("skills/list", options.uri),
3749
+ visibleInDirectories: visible("resources/directory/read", options.uri),
3750
+ get: (invocation) =>
3751
+ invoke(Effect.succeed(skill.entry), invocation, {
3752
+ method: "skills/get",
3753
+ target: options.uri,
3754
+ payload: { uri: options.uri }
3755
+ }),
3756
+ directory: (uri) => skill.directories.get(uri)
3757
+ })
3758
+ for (const { content, resource, text } of skill.files) {
3759
+ const { uri, mimeType } = resource
3760
+ yield* addSkillFile({
3761
+ resource: new Resource(resource),
3762
+ annotations,
3763
+ services,
3764
+ handle: Effect.succeed({
3765
+ contents: [text === undefined ? { uri, mimeType, blob: content } : { uri, mimeType, text }]
3766
+ })
3767
+ })
3768
+ }
3769
+ })
3770
+
3771
+ /**
3772
+ * Creates a layer that registers an Agent Skill under the MCP Skills extension
3773
+ * (SEP-2640).
3774
+ *
3775
+ * **Example** (Publishing a skill with a supporting file)
3776
+ *
3777
+ * ```ts
3778
+ * import { Layer } from "effect"
3779
+ * import { McpProtocol, McpServer } from "effect/ai"
3780
+ *
3781
+ * const RefundsSkill = McpServer.skill({
3782
+ * uri: "skill://billing/refunds/SKILL.md",
3783
+ * files: {
3784
+ * "SKILL.md": `---
3785
+ * name: refunds
3786
+ * description: Process refunds using the billing tools
3787
+ * ---
3788
+ *
3789
+ * Read references/policy.md before issuing a refund.
3790
+ * `,
3791
+ * "references/policy.md": "Refunds above CHF 500 require manager approval.\n"
3792
+ * }
3793
+ * })
3794
+ *
3795
+ * const ServerLayer = RefundsSkill.pipe(
3796
+ * Layer.provide(McpServer.layerHttp({
3797
+ * name: "billing",
3798
+ * version: "1.0.0",
3799
+ * path: "/mcp",
3800
+ * protocols: [McpProtocol.v2026_07_28, McpProtocol.v2025_11_25]
3801
+ * }))
3802
+ * )
3803
+ * ```
3804
+ *
3805
+ * @see {@link registerSkill} for the Effect-level skill registration API
3806
+ *
3807
+ * @stability unstable
3808
+ * @category layers
3809
+ * @since 4.1.1
3810
+ */
3811
+ export const skill = (options: SkillOptions): Layer.Layer<never, Cause.IllegalArgumentError, McpServer> =>
3812
+ Layer.effectDiscard(registerSkill(options))
3813
+
3568
3814
  /**
3569
3815
  * Registers an MCP prompt from an Effect program.
3570
3816
  *
package/src/ai/Prompt.ts CHANGED
@@ -486,6 +486,16 @@ export interface FilePartEncoded extends BasePartEncoded<"file", FilePartOptions
486
486
  */
487
487
  export interface FilePartOptions extends ProviderOptions {}
488
488
 
489
+ const TaggedURL = Schema.TaggedStruct("URL", { href: Schema.URLFromString })
490
+
491
+ const urlFromTaggedURL = SchemaTransformation.transform<URL, typeof TaggedURL.Type>({
492
+ decode: ({ href }) => href,
493
+ encode: (href) => (({
494
+ _tag: "URL",
495
+ href
496
+ }) as const)
497
+ })
498
+
489
499
  /**
490
500
  * Schema for validation and encoding of file parts.
491
501
  *
@@ -535,18 +545,13 @@ export const FilePart: Schema.Struct<{
535
545
  }) as const)
536
546
  })
537
547
  )),
538
- Schema.TaggedStruct("URL", { href: Schema.URLFromString }).pipe(Schema.decodeTo(
539
- Schema.URL,
540
- SchemaTransformation.transform({
541
- decode: ({ href }) => href,
542
- encode: (href) => (({
543
- _tag: "URL",
544
- href
545
- }) as const)
546
- })
547
- )),
548
+ TaggedURL.pipe(Schema.decodeTo(Schema.URL, urlFromTaggedURL)),
548
549
  Schema.Uint8Array,
549
- Schema.URL
550
+ // Under the JSON and binary codecs a raw `URL` would serialize as a plain
551
+ // string, indistinguishable from the `Schema.String` member. Serialize it
552
+ // through the same `TaggedURL` instance instead, so the codecs see a
553
+ // single `{ _tag: "URL" }` member rather than two
554
+ Schema.URL.annotate({ toCodecJson: () => Schema.link<URL>()(TaggedURL, urlFromTaggedURL) })
550
555
  ])
551
556
  }).annotate({ identifier: "FilePart" })
552
557