effect 4.0.0-rc.118 → 4.0.1

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 (254) hide show
  1. package/README.md +17 -4
  2. package/dist/Array.d.ts +25 -25
  3. package/dist/Array.d.ts.map +1 -1
  4. package/dist/Array.js +16 -16
  5. package/dist/Array.js.map +1 -1
  6. package/dist/Cache.d.ts.map +1 -1
  7. package/dist/Cache.js +20 -16
  8. package/dist/Cache.js.map +1 -1
  9. package/dist/Cause.d.ts.map +1 -1
  10. package/dist/Cause.js +1 -1
  11. package/dist/Cause.js.map +1 -1
  12. package/dist/Chunk.d.ts +26 -26
  13. package/dist/Chunk.d.ts.map +1 -1
  14. package/dist/Chunk.js +15 -15
  15. package/dist/Chunk.js.map +1 -1
  16. package/dist/Effect.d.ts +167 -39
  17. package/dist/Effect.d.ts.map +1 -1
  18. package/dist/Effect.js +16 -10
  19. package/dist/Effect.js.map +1 -1
  20. package/dist/HashRing.d.ts.map +1 -1
  21. package/dist/HashRing.js +13 -5
  22. package/dist/HashRing.js.map +1 -1
  23. package/dist/MutableHashMap.d.ts.map +1 -1
  24. package/dist/MutableHashMap.js +4 -22
  25. package/dist/MutableHashMap.js.map +1 -1
  26. package/dist/Option.d.ts +17 -17
  27. package/dist/Option.d.ts.map +1 -1
  28. package/dist/Option.js +6 -6
  29. package/dist/Option.js.map +1 -1
  30. package/dist/Pool.d.ts +9 -5
  31. package/dist/Pool.d.ts.map +1 -1
  32. package/dist/Pool.js +34 -41
  33. package/dist/Pool.js.map +1 -1
  34. package/dist/Queue.d.ts +19 -2
  35. package/dist/Queue.d.ts.map +1 -1
  36. package/dist/Queue.js +9 -4
  37. package/dist/Queue.js.map +1 -1
  38. package/dist/RcMap.d.ts.map +1 -1
  39. package/dist/RcMap.js +16 -1
  40. package/dist/RcMap.js.map +1 -1
  41. package/dist/Record.d.ts +14 -14
  42. package/dist/Record.d.ts.map +1 -1
  43. package/dist/Record.js +10 -10
  44. package/dist/Record.js.map +1 -1
  45. package/dist/Schema.d.ts +37 -21
  46. package/dist/Schema.d.ts.map +1 -1
  47. package/dist/Schema.js +29 -10
  48. package/dist/Schema.js.map +1 -1
  49. package/dist/SchemaAST.d.ts.map +1 -1
  50. package/dist/SchemaAST.js +116 -97
  51. package/dist/SchemaAST.js.map +1 -1
  52. package/dist/SchemaRepresentation.d.ts +3 -1
  53. package/dist/SchemaRepresentation.d.ts.map +1 -1
  54. package/dist/SchemaRepresentation.js +3 -1
  55. package/dist/SchemaRepresentation.js.map +1 -1
  56. package/dist/ScopedCache.d.ts.map +1 -1
  57. package/dist/ScopedCache.js +24 -16
  58. package/dist/ScopedCache.js.map +1 -1
  59. package/dist/Stream.d.ts +45 -6
  60. package/dist/Stream.d.ts.map +1 -1
  61. package/dist/Stream.js +55 -44
  62. package/dist/Stream.js.map +1 -1
  63. package/dist/ai/LanguageModel.d.ts +8 -0
  64. package/dist/ai/LanguageModel.d.ts.map +1 -1
  65. package/dist/ai/LanguageModel.js +13 -2
  66. package/dist/ai/LanguageModel.js.map +1 -1
  67. package/dist/ai/McpSchema.d.ts +402 -402
  68. package/dist/ai/McpSchema.d.ts.map +1 -1
  69. package/dist/ai/McpSchema.js +1 -1
  70. package/dist/ai/McpSchema.js.map +1 -1
  71. package/dist/ai/McpServer.d.ts.map +1 -1
  72. package/dist/ai/McpServer.js +11 -3
  73. package/dist/ai/McpServer.js.map +1 -1
  74. package/dist/ai/Response.d.ts.map +1 -1
  75. package/dist/ai/Response.js +22 -12
  76. package/dist/ai/Response.js.map +1 -1
  77. package/dist/ai/internal/mcpProtocol/v2024_11_05.js +1 -0
  78. package/dist/ai/internal/mcpProtocol/v2024_11_05.js.map +1 -1
  79. package/dist/ai/internal/mcpProtocol/v2025_03_26.js +1 -0
  80. package/dist/ai/internal/mcpProtocol/v2025_03_26.js.map +1 -1
  81. package/dist/ai/internal/mcpProtocol/v2025_06_18.js +1 -0
  82. package/dist/ai/internal/mcpProtocol/v2025_06_18.js.map +1 -1
  83. package/dist/ai/internal/mcpProtocol/v2025_11_25.js +1 -0
  84. package/dist/ai/internal/mcpProtocol/v2025_11_25.js.map +1 -1
  85. package/dist/ai/internal/mcpSchema/v2024_11_05.js +3 -1
  86. package/dist/ai/internal/mcpSchema/v2024_11_05.js.map +1 -1
  87. package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
  88. package/dist/cluster/ClusterWorkflowEngine.js +16 -3
  89. package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
  90. package/dist/cluster/MessageStorage.d.ts +32 -8
  91. package/dist/cluster/MessageStorage.d.ts.map +1 -1
  92. package/dist/cluster/MessageStorage.js +2 -1
  93. package/dist/cluster/MessageStorage.js.map +1 -1
  94. package/dist/cluster/Sharding.d.ts +5 -2
  95. package/dist/cluster/Sharding.d.ts.map +1 -1
  96. package/dist/cluster/Sharding.js +15 -8
  97. package/dist/cluster/Sharding.js.map +1 -1
  98. package/dist/cluster/SqlMessageStorage.d.ts.map +1 -1
  99. package/dist/cluster/SqlMessageStorage.js +36 -16
  100. package/dist/cluster/SqlMessageStorage.js.map +1 -1
  101. package/dist/cluster/SqlRunnerStorage.d.ts.map +1 -1
  102. package/dist/cluster/SqlRunnerStorage.js +30 -44
  103. package/dist/cluster/SqlRunnerStorage.js.map +1 -1
  104. package/dist/cluster/internal/entityManager.js +63 -62
  105. package/dist/cluster/internal/entityManager.js.map +1 -1
  106. package/dist/cluster/internal/interruptors.js +8 -0
  107. package/dist/cluster/internal/interruptors.js.map +1 -1
  108. package/dist/cluster/internal/resourceMap.js +39 -14
  109. package/dist/cluster/internal/resourceMap.js.map +1 -1
  110. package/dist/cluster/internal/resourceRef.js +168 -87
  111. package/dist/cluster/internal/resourceRef.js.map +1 -1
  112. package/dist/http/HttpEffect.d.ts +1 -0
  113. package/dist/http/HttpEffect.d.ts.map +1 -1
  114. package/dist/http/HttpEffect.js +29 -22
  115. package/dist/http/HttpEffect.js.map +1 -1
  116. package/dist/http/HttpMiddleware.d.ts.map +1 -1
  117. package/dist/http/HttpMiddleware.js +3 -2
  118. package/dist/http/HttpMiddleware.js.map +1 -1
  119. package/dist/http/HttpStaticServer.d.ts.map +1 -1
  120. package/dist/http/HttpStaticServer.js +14 -0
  121. package/dist/http/HttpStaticServer.js.map +1 -1
  122. package/dist/http/HttpTraceContext.d.ts +1 -1
  123. package/dist/http/HttpTraceContext.d.ts.map +1 -1
  124. package/dist/http/HttpTraceContext.js +4 -4
  125. package/dist/http/HttpTraceContext.js.map +1 -1
  126. package/dist/http-api/HttpApiError.d.ts +1 -0
  127. package/dist/http-api/HttpApiError.d.ts.map +1 -1
  128. package/dist/http-api/HttpApiError.js +1 -0
  129. package/dist/http-api/HttpApiError.js.map +1 -1
  130. package/dist/internal/core.js +43 -2
  131. package/dist/internal/core.js.map +1 -1
  132. package/dist/internal/dateTime.js +1 -1
  133. package/dist/internal/dateTime.js.map +1 -1
  134. package/dist/internal/effect.js +138 -165
  135. package/dist/internal/effect.js.map +1 -1
  136. package/dist/internal/rcRef.js +59 -23
  137. package/dist/internal/rcRef.js.map +1 -1
  138. package/dist/internal/schema/annotations.js +1 -7
  139. package/dist/internal/schema/annotations.js.map +1 -1
  140. package/dist/internal/schema/codegen.js +56 -28
  141. package/dist/internal/schema/codegen.js.map +1 -1
  142. package/dist/internal/schema/fromJsonSchemaDocument.js +11 -8
  143. package/dist/internal/schema/fromJsonSchemaDocument.js.map +1 -1
  144. package/dist/internal/schema/toCodeDocument.js +10 -30
  145. package/dist/internal/schema/toCodeDocument.js.map +1 -1
  146. package/dist/internal/schema/toCodec.js +1 -15
  147. package/dist/internal/schema/toCodec.js.map +1 -1
  148. package/dist/internal/schema/toEquivalence.js +4 -3
  149. package/dist/internal/schema/toEquivalence.js.map +1 -1
  150. package/dist/internal/schema/toFormatter.js +4 -4
  151. package/dist/internal/schema/toFormatter.js.map +1 -1
  152. package/dist/reactivity/Atom.d.ts.map +1 -1
  153. package/dist/reactivity/Atom.js +6 -2
  154. package/dist/reactivity/Atom.js.map +1 -1
  155. package/dist/reactivity/AtomRpc.d.ts +3 -3
  156. package/dist/reactivity/AtomRpc.d.ts.map +1 -1
  157. package/dist/rpc/Rpc.d.ts +2 -2
  158. package/dist/rpc/Rpc.d.ts.map +1 -1
  159. package/dist/rpc/RpcClient.d.ts +7 -7
  160. package/dist/rpc/RpcClient.d.ts.map +1 -1
  161. package/dist/rpc/RpcClient.js +21 -16
  162. package/dist/rpc/RpcClient.js.map +1 -1
  163. package/dist/rpc/RpcMessage.d.ts +1 -1
  164. package/dist/rpc/RpcMessage.d.ts.map +1 -1
  165. package/dist/rpc/RpcServer.d.ts.map +1 -1
  166. package/dist/rpc/RpcServer.js +2 -2
  167. package/dist/rpc/RpcServer.js.map +1 -1
  168. package/dist/rpc/Utils.d.ts +2 -3
  169. package/dist/rpc/Utils.d.ts.map +1 -1
  170. package/dist/rpc/Utils.js +3 -4
  171. package/dist/rpc/Utils.js.map +1 -1
  172. package/dist/schema/SchemaCompiler/runtime.js +6 -1
  173. package/dist/schema/SchemaCompiler/runtime.js.map +1 -1
  174. package/dist/testing/TestSchema.d.ts +234 -6
  175. package/dist/testing/TestSchema.d.ts.map +1 -1
  176. package/dist/testing/TestSchema.js +244 -25
  177. package/dist/testing/TestSchema.js.map +1 -1
  178. package/dist/testing/index.d.ts +1 -0
  179. package/dist/testing/index.d.ts.map +1 -1
  180. package/dist/testing/index.js +1 -0
  181. package/dist/testing/index.js.map +1 -1
  182. package/dist/workflow/DurableDeferred.js +1 -1
  183. package/dist/workflow/DurableDeferred.js.map +1 -1
  184. package/dist/workflow/Workflow.js +1 -1
  185. package/dist/workflow/Workflow.js.map +1 -1
  186. package/dist/workflow/WorkflowEngine.d.ts +2 -0
  187. package/dist/workflow/WorkflowEngine.d.ts.map +1 -1
  188. package/dist/workflow/WorkflowEngine.js +1 -0
  189. package/dist/workflow/WorkflowEngine.js.map +1 -1
  190. package/package.json +1 -1
  191. package/src/Array.ts +31 -31
  192. package/src/Cache.ts +22 -16
  193. package/src/Cause.ts +1 -1
  194. package/src/Chunk.ts +29 -29
  195. package/src/Effect.ts +170 -39
  196. package/src/HashRing.ts +14 -5
  197. package/src/MutableHashMap.ts +4 -24
  198. package/src/Option.ts +19 -19
  199. package/src/Pool.ts +28 -36
  200. package/src/Queue.ts +26 -6
  201. package/src/RcMap.ts +26 -2
  202. package/src/Record.ts +20 -20
  203. package/src/Schema.ts +48 -24
  204. package/src/SchemaAST.ts +135 -115
  205. package/src/SchemaRepresentation.ts +3 -1
  206. package/src/ScopedCache.ts +27 -16
  207. package/src/Stream.ts +158 -88
  208. package/src/ai/LanguageModel.ts +27 -2
  209. package/src/ai/McpSchema.ts +3 -3
  210. package/src/ai/McpServer.ts +12 -3
  211. package/src/ai/Response.ts +27 -12
  212. package/src/ai/internal/mcpProtocol/v2024_11_05.ts +1 -0
  213. package/src/ai/internal/mcpProtocol/v2025_03_26.ts +1 -0
  214. package/src/ai/internal/mcpProtocol/v2025_06_18.ts +1 -0
  215. package/src/ai/internal/mcpProtocol/v2025_11_25.ts +1 -0
  216. package/src/ai/internal/mcpSchema/v2024_11_05.ts +4 -2
  217. package/src/cluster/ClusterWorkflowEngine.ts +26 -5
  218. package/src/cluster/MessageStorage.ts +22 -5
  219. package/src/cluster/Sharding.ts +32 -28
  220. package/src/cluster/SqlMessageStorage.ts +45 -21
  221. package/src/cluster/SqlRunnerStorage.ts +85 -113
  222. package/src/cluster/internal/entityManager.ts +68 -80
  223. package/src/cluster/internal/interruptors.ts +13 -0
  224. package/src/cluster/internal/resourceMap.ts +55 -17
  225. package/src/cluster/internal/resourceRef.ts +189 -96
  226. package/src/http/HttpEffect.ts +15 -9
  227. package/src/http/HttpMiddleware.ts +8 -2
  228. package/src/http/HttpStaticServer.ts +16 -0
  229. package/src/http/HttpTraceContext.ts +8 -4
  230. package/src/http-api/HttpApiError.ts +1 -0
  231. package/src/internal/core.ts +56 -2
  232. package/src/internal/dateTime.ts +3 -1
  233. package/src/internal/effect.ts +146 -173
  234. package/src/internal/rcRef.ts +83 -33
  235. package/src/internal/schema/annotations.ts +0 -9
  236. package/src/internal/schema/codegen.ts +90 -43
  237. package/src/internal/schema/fromJsonSchemaDocument.ts +5 -3
  238. package/src/internal/schema/toCodeDocument.ts +10 -47
  239. package/src/internal/schema/toCodec.ts +3 -16
  240. package/src/internal/schema/toEquivalence.ts +4 -5
  241. package/src/internal/schema/toFormatter.ts +4 -6
  242. package/src/reactivity/Atom.ts +6 -2
  243. package/src/reactivity/AtomRpc.ts +5 -5
  244. package/src/rpc/Rpc.ts +2 -2
  245. package/src/rpc/RpcClient.ts +35 -32
  246. package/src/rpc/RpcMessage.ts +1 -1
  247. package/src/rpc/RpcServer.ts +2 -1
  248. package/src/rpc/Utils.ts +4 -10
  249. package/src/schema/SchemaCompiler/runtime.ts +17 -1
  250. package/src/testing/TestSchema.ts +315 -63
  251. package/src/testing/index.ts +1 -0
  252. package/src/workflow/DurableDeferred.ts +1 -1
  253. package/src/workflow/Workflow.ts +1 -1
  254. package/src/workflow/WorkflowEngine.ts +4 -0
package/src/Stream.ts CHANGED
@@ -13861,41 +13861,40 @@ export const scan: {
13861
13861
  f: (s: S, a: A) => S
13862
13862
  ): Stream<S, E, R> =>
13863
13863
  suspend(() => {
13864
- let isFirst = true
13865
- return fromChannel(Channel.mapAccum(self.channel, initial, (state, arr) => {
13866
- const states = Arr.empty</**
13867
- * Accumulates state across the stream, emitting the initial state and each updated state.
13868
- *
13869
- * **Example** (Scanning stream state)
13870
- *
13871
- * ```ts import.meta.vitest
13872
- * import { Effect, Stream } from "effect"
13873
- *
13874
- * const program = Effect.gen(function*() {
13875
- * const values = yield* Stream.make(1, 2, 3).pipe(
13876
- * Stream.scan(() => 0, (acc, n) => acc + n),
13877
- * Stream.runCollect
13878
- * )
13879
- * values // => [ 0, 1, 3, 6 ]
13880
- * })
13881
- *
13882
- * await Effect.runPromise(program)
13883
- * ```
13884
- *
13885
- * @category accumulation
13886
- * @since 2.0.0
13887
- */
13888
- S>() as Arr.NonEmptyArray<S>
13889
- if (isFirst) {
13890
- isFirst = false
13891
- states.push(state)
13892
- }
13893
- for (let index = 0; index < arr.length; index++) {
13894
- state = f(state, arr[index])
13895
- states.push(state)
13896
- }
13897
- return [state, Arr.of(states)]
13898
- }));
13864
+ const seed = initial()
13865
+ return concat(
13866
+ succeed(seed),
13867
+ fromChannel(Channel.mapAccum(self.channel, () => seed, (state, arr) => {
13868
+ const states = Arr.empty</**
13869
+ * Accumulates state across the stream, emitting the initial state and each updated state.
13870
+ *
13871
+ * **Example** (Scanning stream state)
13872
+ *
13873
+ * ```ts import.meta.vitest
13874
+ * import { Effect, Stream } from "effect"
13875
+ *
13876
+ * const program = Effect.gen(function*() {
13877
+ * const values = yield* Stream.make(1, 2, 3).pipe(
13878
+ * Stream.scan(() => 0, (acc, n) => acc + n),
13879
+ * Stream.runCollect
13880
+ * )
13881
+ * values // => [ 0, 1, 3, 6 ]
13882
+ * })
13883
+ *
13884
+ * await Effect.runPromise(program)
13885
+ * ```
13886
+ *
13887
+ * @category accumulation
13888
+ * @since 2.0.0
13889
+ */
13890
+ S>() as Arr.NonEmptyArray<S>
13891
+ for (let index = 0; index < arr.length; index++) {
13892
+ state = f(state, arr[index])
13893
+ states.push(state)
13894
+ }
13895
+ return [state, Arr.of(states)]
13896
+ }))
13897
+ );
13899
13898
  }))
13900
13899
 
13901
13900
  /**
@@ -14329,37 +14328,36 @@ const throttleShapeEffect = <A, E, R, E2, R2>(
14329
14328
  const durationMs = Duration.toMillis(Duration.fromInputUnsafe(duration))
14330
14329
  const max = units + burst < 0 ? Number.POSITIVE_INFINITY : units + burst
14331
14330
  let tokens = units
14332
- let timestampMs = clock.currentTimeMillisUnsafe()
14331
+ let timestampNanos = clock.monotonicTimeNanosUnsafe()
14333
14332
 
14334
14333
  return Effect.succeed(Effect.flatMap(pull, (arr) =>
14335
14334
  Effect.flatMap(cost(arr), (weight) => {
14336
- const currentMs = clock.currentTimeMillisUnsafe()
14337
- const elapsed = currentMs - timestampMs
14335
+ const currentNanos = clock.monotonicTimeNanosUnsafe()
14336
+ const elapsed = Number(currentNanos - timestampNanos) / 1_000_000
14338
14337
  const cycles = elapsed / durationMs
14339
14338
  const sum = tokens + (cycles * units)
14340
- const available = sum < 0 ? max : Math.min(sum, max)
14339
+ const available = Math.min(sum, max)
14341
14340
  const remaining = available - weight
14342
14341
 
14343
14342
  if (remaining >= 0) {
14344
14343
  tokens = remaining
14345
- timestampMs = currentMs
14344
+ timestampNanos = currentNanos
14346
14345
  return Effect.succeed(arr)
14347
14346
  }
14348
14347
 
14349
- // Calculate delay needed
14350
14348
  const waitCycles = -remaining / units
14351
14349
  const delayMs = Math.max(0, waitCycles * durationMs)
14352
14350
 
14353
14351
  if (delayMs > 0) {
14354
14352
  return Effect.flatMap(Effect.sleep(delayMs), () => {
14355
14353
  tokens = remaining
14356
- timestampMs = currentMs
14354
+ timestampNanos = currentNanos
14357
14355
  return Effect.succeed(arr)
14358
14356
  })
14359
14357
  }
14360
14358
 
14361
14359
  tokens = remaining
14362
- timestampMs = currentMs
14360
+ timestampNanos = currentNanos
14363
14361
  return Effect.succeed(arr)
14364
14362
  })))
14365
14363
  }))
@@ -14629,8 +14627,9 @@ export const grouped: {
14629
14627
  *
14630
14628
  * **Details**
14631
14629
  *
14632
- * Finite fractional chunk sizes are rounded down. `NaN` and non-positive sizes
14633
- * are treated as `1`.
14630
+ * The duration starts when the first element of a group arrives, so an idle
14631
+ * stream does not wake up. Finite fractional chunk sizes are rounded down.
14632
+ * `NaN` and non-positive sizes are treated as `1`.
14634
14633
  *
14635
14634
  * **Example** (Grouping elements by size or time)
14636
14635
  *
@@ -14658,8 +14657,9 @@ export const groupedWithin: {
14658
14657
  *
14659
14658
  * **Details**
14660
14659
  *
14661
- * Finite fractional chunk sizes are rounded down. `NaN` and non-positive sizes
14662
- * are treated as `1`.
14660
+ * The duration starts when the first element of a group arrives, so an idle
14661
+ * stream does not wake up. Finite fractional chunk sizes are rounded down.
14662
+ * `NaN` and non-positive sizes are treated as `1`.
14663
14663
  *
14664
14664
  * **Example** (Grouping elements by size or time)
14665
14665
  *
@@ -14687,8 +14687,9 @@ export const groupedWithin: {
14687
14687
  *
14688
14688
  * **Details**
14689
14689
  *
14690
- * Finite fractional chunk sizes are rounded down. `NaN` and non-positive sizes
14691
- * are treated as `1`.
14690
+ * The duration starts when the first element of a group arrives, so an idle
14691
+ * stream does not wake up. Finite fractional chunk sizes are rounded down.
14692
+ * `NaN` and non-positive sizes are treated as `1`.
14692
14693
  *
14693
14694
  * **Example** (Grouping elements by size or time)
14694
14695
  *
@@ -15439,6 +15440,18 @@ export const aggregate: {
15439
15440
  * **Details**
15440
15441
  *
15441
15442
  * The schedule can flush the current aggregation even if the sink has not finished.
15443
+ * It is stepped at most once per aggregation, when the aggregation receives its
15444
+ * first element, with the previous aggregation's output as input. An aggregation
15445
+ * the sink completes immediately, such as one built from leftovers, may finish
15446
+ * without stepping the schedule.
15447
+ *
15448
+ * Time between aggregations is hidden from the schedule, so an idle stream does
15449
+ * not run it. Time-based schedules such as `Schedule.fixed` and
15450
+ * `Schedule.upTo({ duration })` only count time spent aggregating; use
15451
+ * `Schedule.spaced` for a flush timer.
15452
+ *
15453
+ * When the schedule ends, the stream emits the current aggregation and any sink
15454
+ * leftovers, then ends without pulling more from upstream.
15442
15455
  *
15443
15456
  * **Example** (Aggregating with a sink and schedule)
15444
15457
  *
@@ -15468,6 +15481,18 @@ export const aggregateWithin: {
15468
15481
  * **Details**
15469
15482
  *
15470
15483
  * The schedule can flush the current aggregation even if the sink has not finished.
15484
+ * It is stepped at most once per aggregation, when the aggregation receives its
15485
+ * first element, with the previous aggregation's output as input. An aggregation
15486
+ * the sink completes immediately, such as one built from leftovers, may finish
15487
+ * without stepping the schedule.
15488
+ *
15489
+ * Time between aggregations is hidden from the schedule, so an idle stream does
15490
+ * not run it. Time-based schedules such as `Schedule.fixed` and
15491
+ * `Schedule.upTo({ duration })` only count time spent aggregating; use
15492
+ * `Schedule.spaced` for a flush timer.
15493
+ *
15494
+ * When the schedule ends, the stream emits the current aggregation and any sink
15495
+ * leftovers, then ends without pulling more from upstream.
15471
15496
  *
15472
15497
  * **Example** (Aggregating with a sink and schedule)
15473
15498
  *
@@ -15500,6 +15525,18 @@ export const aggregateWithin: {
15500
15525
  * **Details**
15501
15526
  *
15502
15527
  * The schedule can flush the current aggregation even if the sink has not finished.
15528
+ * It is stepped at most once per aggregation, when the aggregation receives its
15529
+ * first element, with the previous aggregation's output as input. An aggregation
15530
+ * the sink completes immediately, such as one built from leftovers, may finish
15531
+ * without stepping the schedule.
15532
+ *
15533
+ * Time between aggregations is hidden from the schedule, so an idle stream does
15534
+ * not run it. Time-based schedules such as `Schedule.fixed` and
15535
+ * `Schedule.upTo({ duration })` only count time spent aggregating; use
15536
+ * `Schedule.spaced` for a flush timer.
15537
+ *
15538
+ * When the schedule ends, the stream emits the current aggregation and any sink
15539
+ * leftovers, then ends without pulling more from upstream.
15503
15540
  *
15504
15541
  * **Example** (Aggregating with a sink and schedule)
15505
15542
  *
@@ -15543,6 +15580,18 @@ export const aggregateWithin: {
15543
15580
  * **Details**
15544
15581
  *
15545
15582
  * The schedule can flush the current aggregation even if the sink has not finished.
15583
+ * It is stepped at most once per aggregation, when the aggregation receives its
15584
+ * first element, with the previous aggregation's output as input. An aggregation
15585
+ * the sink completes immediately, such as one built from leftovers, may finish
15586
+ * without stepping the schedule.
15587
+ *
15588
+ * Time between aggregations is hidden from the schedule, so an idle stream does
15589
+ * not run it. Time-based schedules such as `Schedule.fixed` and
15590
+ * `Schedule.upTo({ duration })` only count time spent aggregating; use
15591
+ * `Schedule.spaced` for a flush timer.
15592
+ *
15593
+ * When the schedule ends, the stream emits the current aggregation and any sink
15594
+ * leftovers, then ends without pulling more from upstream.
15546
15595
  *
15547
15596
  * **Example** (Aggregating with a sink and schedule)
15548
15597
  *
@@ -15571,6 +15620,18 @@ export const aggregateWithin: {
15571
15620
  * **Details**
15572
15621
  *
15573
15622
  * The schedule can flush the current aggregation even if the sink has not finished.
15623
+ * It is stepped at most once per aggregation, when the aggregation receives its
15624
+ * first element, with the previous aggregation's output as input. An aggregation
15625
+ * the sink completes immediately, such as one built from leftovers, may finish
15626
+ * without stepping the schedule.
15627
+ *
15628
+ * Time between aggregations is hidden from the schedule, so an idle stream does
15629
+ * not run it. Time-based schedules such as `Schedule.fixed` and
15630
+ * `Schedule.upTo({ duration })` only count time spent aggregating; use
15631
+ * `Schedule.spaced` for a flush timer.
15632
+ *
15633
+ * When the schedule ends, the stream emits the current aggregation and any sink
15634
+ * leftovers, then ends without pulling more from upstream.
15574
15635
  *
15575
15636
  * **Example** (Aggregating with a sink and schedule)
15576
15637
  *
@@ -15597,25 +15658,41 @@ export const aggregateWithin: {
15597
15658
  capacity: 0
15598
15659
  })
15599
15660
 
15600
- // upstream -> buffer
15601
15661
  yield* pull.pipe(
15602
15662
  pullLatch.whenOpen,
15603
15663
  Effect.flatMap((arr) => {
15604
15664
  pullLatch.closeUnsafe()
15605
15665
  return Queue.offer(buffer, arr)
15606
15666
  }),
15607
- Effect.forever, // don't disable autoYield to prevent choking the schedule
15667
+ Effect.forever, // Keep autoYield enabled so the schedule can run.
15608
15668
  Effect.catchCause((cause) => Queue.failCause(buffer, cause)),
15609
15669
  Effect.forkIn(scope)
15610
15670
  )
15611
15671
 
15612
- // schedule -> buffer
15672
+ // The schedule clock excludes time between aggregations.
15673
+ const clock = yield* Clock
15674
+ const step = yield* Schedule.toStep(schedule)
15675
+ const hasInput = Latch.makeUnsafe(false)
15676
+ let scheduleTime = clock.currentTimeMillisUnsafe()
15677
+ let openedAt = 0
15613
15678
  let lastOutput = Option.none</**
15614
15679
  * Aggregates elements with a sink, emitting each result when the sink completes or the schedule triggers.
15615
15680
  *
15616
15681
  * **Details**
15617
15682
  *
15618
15683
  * The schedule can flush the current aggregation even if the sink has not finished.
15684
+ * It is stepped at most once per aggregation, when the aggregation receives its
15685
+ * first element, with the previous aggregation's output as input. An aggregation
15686
+ * the sink completes immediately, such as one built from leftovers, may finish
15687
+ * without stepping the schedule.
15688
+ *
15689
+ * Time between aggregations is hidden from the schedule, so an idle stream does
15690
+ * not run it. Time-based schedules such as `Schedule.fixed` and
15691
+ * `Schedule.upTo({ duration })` only count time spent aggregating; use
15692
+ * `Schedule.spaced` for a flush timer.
15693
+ *
15694
+ * When the schedule ends, the stream emits the current aggregation and any sink
15695
+ * leftovers, then ends without pulling more from upstream.
15619
15696
  *
15620
15697
  * **Example** (Aggregating with a sink and schedule)
15621
15698
  *
@@ -15640,58 +15717,51 @@ export const aggregateWithin: {
15640
15717
  */
15641
15718
  B>()
15642
15719
  let leftover: Arr.NonEmptyReadonlyArray<A2> | undefined
15643
- let sinkHasInput = false
15644
- const step = yield* Schedule.toStepWithSleep(schedule)
15645
- const stepLoop = Effect.suspend(function loop(): Pull.Pull<void, E3, C | void, R3> {
15646
- return Effect.flatMap(step(lastOutput), () => !sinkHasInput ? loop() : Queue.offer(buffer, scheduleStep))
15647
- })
15648
- const stepToBuffer: Pull.Pull<never, E3, void, R3> = stepLoop.pipe(
15649
- Effect.flatMap(() => Effect.never),
15650
- Pull.catchDone(() => Cause.done())
15651
- )
15652
-
15653
- // buffer -> sink
15654
- const pullFromBuffer: Pull.Pull<
15655
- Arr.NonEmptyReadonlyArray<A>,
15656
- E
15657
- > = Queue.take(buffer).pipe(
15658
- Effect.flatMap((arr) => {
15659
- if (arr === scheduleStep) {
15660
- return Cause.done()
15661
- }
15662
- sinkHasInput = true
15663
- return Effect.succeed(arr)
15664
- })
15720
+ const onInput = <X>(chunk: X): Effect.Effect<X> => {
15721
+ if (hasInput.openUnsafe()) {
15722
+ openedAt = clock.currentTimeMillisUnsafe()
15723
+ }
15724
+ return Effect.succeed(chunk)
15725
+ }
15726
+ const stepToBuffer: Pull.Pull<never, E3, void, R3> = hasInput.await.pipe(
15727
+ Effect.flatMap(() => step(scheduleTime, lastOutput)),
15728
+ Effect.flatMap(([, delay]) => Effect.sleep(delay)),
15729
+ Effect.flatMap(() => Queue.offer(buffer, scheduleStep)),
15730
+ // End input so the sink drains leftovers without further upstream pulls.
15731
+ Pull.catchDone(() => Queue.end(buffer)),
15732
+ Effect.flatMap(() => Effect.never)
15665
15733
  )
15666
15734
 
15667
15735
  const sinkUpstream = Effect.suspend((): Pull.Pull<Arr.NonEmptyReadonlyArray<A | A2>, E> => {
15668
15736
  if (leftover !== undefined) {
15669
15737
  const chunk = leftover
15670
15738
  leftover = undefined
15671
- sinkHasInput = true
15672
- return Effect.succeed(chunk)
15739
+ return onInput(chunk)
15740
+ }
15741
+ if (buffer.state._tag === "Open") {
15742
+ pullLatch.openUnsafe()
15673
15743
  }
15674
- pullLatch.openUnsafe()
15675
- return pullFromBuffer
15744
+ return Effect.flatMap(Queue.take(buffer), (arr) => arr === scheduleStep ? Cause.done() : onInput(arr))
15676
15745
  })
15677
- const catchSinkHalt = Effect.flatMap(([value, leftover_]: Sink.End<B, A2>) => {
15678
- // ignore the last output if the upstream only pulled a halt
15679
- if (!sinkHasInput && buffer.state._tag === "Done") return Cause.done()
15746
+ const emit = Effect.flatMap(([value, leftover_]: Sink.End<B, A2>) => {
15747
+ if (hasInput.isOpen()) {
15748
+ scheduleTime += clock.currentTimeMillisUnsafe() - openedAt
15749
+ } else if (buffer.state._tag === "Done") {
15750
+ return Cause.done()
15751
+ }
15680
15752
  lastOutput = Option.some(value)
15681
15753
  leftover = leftover_
15682
15754
  return Effect.succeed(Arr.of(value))
15683
15755
  })
15684
15756
 
15685
- return Effect.suspend(() => {
15686
- // if the buffer has exited and there is no more data to process
15757
+ return Effect.suspend((): Pull.Pull<Arr.NonEmptyReadonlyArray<B>, E | E2 | E3, void, R2 | R3> => {
15687
15758
  if (buffer.state._tag === "Done" && leftover === undefined) {
15688
15759
  return buffer.state.exit as Exit.Exit<never, Cause.Done<void> | E>
15689
15760
  }
15690
- sinkHasInput = leftover !== undefined
15691
- return Effect.succeed(Effect.suspend(() => sink.transform(sinkUpstream as any, scope)))
15692
- }).pipe(
15693
- Effect.flatMap((pull) => Effect.raceFirst(catchSinkHalt(pull), stepToBuffer))
15694
- )
15761
+ hasInput.closeUnsafe()
15762
+ const pull = emit(Effect.suspend(() => sink.transform(sinkUpstream as any, scope)))
15763
+ return buffer.state._tag === "Open" ? Effect.raceFirst(pull, stepToBuffer) : pull
15764
+ })
15695
15765
  }))))
15696
15766
 
15697
15767
  /**
@@ -107,6 +107,13 @@ export const TypeId: TypeId = "~effect/ai/LanguageModel"
107
107
  export interface LanguageModel {
108
108
  readonly [TypeId]: TypeId
109
109
 
110
+ /**
111
+ * Whether the effective provider configuration supports system messages in
112
+ * history. Evaluate in the request's context to respect scoped overrides.
113
+ * Placement restrictions may apply; an absent capability means unknown support.
114
+ */
115
+ readonly supportsSystemMessagesInHistory?: Effect.Effect<boolean> | undefined
116
+
110
117
  /**
111
118
  * Generate text using the language model.
112
119
  */
@@ -833,6 +840,9 @@ export const make: (params: {
833
840
  * for structured output generation.
834
841
  */
835
842
  readonly codecTransformer?: CodecTransformer | undefined
843
+
844
+ /** Whether the effective provider configuration supports system messages in history. */
845
+ readonly supportsSystemMessagesInHistory?: Effect.Effect<boolean> | undefined
836
846
  }) => Effect.Effect<LanguageModel> = Effect.fnUntraced(function*(params) {
837
847
  const codecTransformer = params.codecTransformer ?? defaultCodecTransformer
838
848
 
@@ -1749,6 +1759,7 @@ export const make: (params: {
1749
1759
 
1750
1760
  return LanguageModel.of({
1751
1761
  [TypeId]: TypeId,
1762
+ supportsSystemMessagesInHistory: params.supportsSystemMessagesInHistory,
1752
1763
  generateText: generateText as LanguageModel["generateText"],
1753
1764
  generateObject: generateObject as LanguageModel["generateObject"],
1754
1765
  streamText: streamText as LanguageModel["streamText"]
@@ -2417,18 +2428,32 @@ const resolveToolCalls = <Tools extends Record<string, Tool.Any>>(
2417
2428
  // Utilities
2418
2429
  // =============================================================================
2419
2430
 
2431
+ // Stable parameter-mode copies let Response reuse each tool's part schemas.
2432
+ const parameterModeTools = new WeakMap<Tool.Any, { encoded?: Tool.Any; opaque?: Tool.Any }>()
2433
+
2434
+ const withParameterMode = (tool: Tool.Any, mode: "encoded" | "opaque"): Tool.Any => {
2435
+ let tools = parameterModeTools.get(tool)
2436
+ if (tools === undefined) {
2437
+ tools = {}
2438
+ parameterModeTools.set(tool, tools)
2439
+ }
2440
+ return tools[mode] ??= tool.setParameters(
2441
+ mode === "encoded" ? Schema.toEncoded(tool.parametersSchema) : Schema.Unknown
2442
+ )
2443
+ }
2444
+
2420
2445
  const makeToolkitWithEncodedParameters = <Tools extends Record<string, Tool.Any>>(
2421
2446
  toolkit: Toolkit.WithHandler<Tools>
2422
2447
  ): Toolkit.Any =>
2423
2448
  Toolkit.make(
2424
- ...Object.values(toolkit.tools).map((tool) => tool.setParameters(Schema.toEncoded(tool.parametersSchema)))
2449
+ ...Object.values(toolkit.tools).map((tool) => withParameterMode(tool, "encoded"))
2425
2450
  )
2426
2451
 
2427
2452
  const makeToolkitWithOpaqueParameters = <Tools extends Record<string, Tool.Any>>(
2428
2453
  toolkit: Toolkit.WithHandler<Tools>
2429
2454
  ): Toolkit.Any =>
2430
2455
  Toolkit.make(
2431
- ...Object.values(toolkit.tools).map((tool) => tool.setParameters(Schema.Unknown))
2456
+ ...Object.values(toolkit.tools).map((tool) => withParameterMode(tool, "opaque"))
2432
2457
  )
2433
2458
 
2434
2459
  // Provider-executed tools bypass Toolkit, so validate their parameters here.
@@ -86,10 +86,10 @@ export const optionalWithDefault = <S extends Schema.Constraint & Schema.Without
86
86
  */
87
87
  export const optional = <S extends Schema.Constraint>(
88
88
  schema: S
89
- ): Schema.decodeTo<Schema.optional<S>, Schema.optionalKey<S>> =>
89
+ ): Schema.decodeTo<Schema.toType<Schema.optional<S>>, Schema.optionalKey<S>> =>
90
90
  Schema.optionalKey(schema).pipe(
91
- Schema.decodeTo(Schema.optional(schema), {
92
- decode: SchemaGetter.passthrough() as any,
91
+ Schema.decodeTo(Schema.toType(Schema.optional(schema)), {
92
+ decode: SchemaGetter.passthrough(),
93
93
  encode: SchemaGetter.transformOptional(Option.flatMap(Option.fromUndefinedOr))
94
94
  })
95
95
  )
@@ -1620,7 +1620,7 @@ const layerMcpProtocolHttp = (options: {
1620
1620
  const hasMultipleMessages = response.body._tag === "Uint8Array" &&
1621
1621
  response.body.body.subarray(0, -1).includes(10)
1622
1622
  return admission.isSubscription || response.body._tag === "Stream" || hasMultipleMessages
1623
- ? toServerSentEvents(response)
1623
+ ? toServerSentEvents(response, admission.isSubscription)
1624
1624
  : response
1625
1625
  })
1626
1626
  return yield* admission.acknowledge
@@ -1713,7 +1713,7 @@ function mcpJsonRpcSerialization(options?: {
1713
1713
  })
1714
1714
  }
1715
1715
 
1716
- const toServerSentEvents = (response: HttpServerResponse.HttpServerResponse) => {
1716
+ const toServerSentEvents = (response: HttpServerResponse.HttpServerResponse, keepAlive: boolean) => {
1717
1717
  const encoder = new TextEncoder()
1718
1718
  const decoder = new TextDecoder()
1719
1719
  const frame = (data: Uint8Array) =>
@@ -1726,7 +1726,16 @@ const toServerSentEvents = (response: HttpServerResponse.HttpServerResponse) =>
1726
1726
  contentType: "text/event-stream"
1727
1727
  }
1728
1728
  if (response.body._tag === "Stream") {
1729
- return HttpServerResponse.stream(response.body.stream.pipe(Stream.map(frame)), options)
1729
+ const events = response.body.stream.pipe(Stream.map(frame))
1730
+ if (!keepAlive) {
1731
+ return HttpServerResponse.stream(events, options)
1732
+ }
1733
+ // Keep a native timer pending so workerd does not treat idle subscriptions as hung requests.
1734
+ const keepAliveComments = Stream.tick("15 seconds").pipe(
1735
+ Stream.drop(1),
1736
+ Stream.map(() => encoder.encode(": keepalive\n\n"))
1737
+ )
1738
+ return HttpServerResponse.stream(Stream.merge(events, keepAliveComments, { haltStrategy: "left" }), options)
1730
1739
  }
1731
1740
  if (response.body._tag === "Uint8Array") {
1732
1741
  return HttpServerResponse.uint8Array(frame(response.body.body), options)
@@ -152,6 +152,24 @@ export type AllPartsEncoded =
152
152
  | FinishPartEncoded
153
153
  | ErrorPartEncoded
154
154
 
155
+ // Tools are immutable, so response schemas can share their per-tool parts.
156
+ const toolPartSchemaCache = new WeakMap<Tool.Any, {
157
+ readonly toolCall: Schema.Top
158
+ readonly toolResult: Schema.Top
159
+ }>()
160
+
161
+ const toolPartSchemas = (tool: Tool.Any) => {
162
+ let parts = toolPartSchemaCache.get(tool)
163
+ if (parts === undefined) {
164
+ parts = {
165
+ toolCall: ToolCallPart(tool.name, tool.parametersSchema),
166
+ toolResult: ToolResultPart(tool.name, tool.successSchema, Tool.failureResultSchema(tool))
167
+ }
168
+ toolPartSchemaCache.set(tool, parts)
169
+ }
170
+ return parts
171
+ }
172
+
155
173
  /**
156
174
  * Creates a Schema for all response parts based on a toolkit.
157
175
  *
@@ -192,10 +210,9 @@ export const AllParts = <T extends Toolkit.Any | Toolkit.WithHandler<any>>(
192
210
  const toolCalls: Array<Schema.Top> = []
193
211
  const toolResults: Array<Schema.Top> = []
194
212
  for (const tool of Object.values(toolkit.tools as Record<string, Tool.Any>)) {
195
- const toolCall = ToolCallPart(tool.name, tool.parametersSchema)
196
- const toolResult = ToolResultPart(tool.name, tool.successSchema, Tool.failureResultSchema(tool))
197
- toolCalls.push(toolCall)
198
- toolResults.push(toolResult)
213
+ const parts = toolPartSchemas(tool)
214
+ toolCalls.push(parts.toolCall)
215
+ toolResults.push(parts.toolResult)
199
216
  }
200
217
  return Schema.Union([
201
218
  TextPart,
@@ -287,10 +304,9 @@ export const Part = <T extends Toolkit.Any | Toolkit.WithHandler<any>>(
287
304
  const toolCalls: Array<Schema.Top> = []
288
305
  const toolResults: Array<Schema.Top> = []
289
306
  for (const tool of Object.values(toolkit.tools as Record<string, Tool.Any>)) {
290
- const toolCall = ToolCallPart(tool.name, tool.parametersSchema)
291
- const toolResult = ToolResultPart(tool.name, tool.successSchema, Tool.failureResultSchema(tool))
292
- toolCalls.push(toolCall)
293
- toolResults.push(toolResult)
307
+ const parts = toolPartSchemas(tool)
308
+ toolCalls.push(parts.toolCall)
309
+ toolResults.push(parts.toolResult)
294
310
  }
295
311
  return Schema.Union([
296
312
  TextPart,
@@ -385,10 +401,9 @@ export const StreamPart = <T extends Toolkit.Any | Toolkit.WithHandler<any>>(
385
401
  const toolCalls: Array<Schema.Top> = []
386
402
  const toolResults: Array<Schema.Top> = []
387
403
  for (const tool of Object.values(toolkit.tools as Record<string, Tool.Any>)) {
388
- const toolCall = ToolCallPart(tool.name, tool.parametersSchema)
389
- const toolResult = ToolResultPart(tool.name, tool.successSchema, Tool.failureResultSchema(tool))
390
- toolCalls.push(toolCall)
391
- toolResults.push(toolResult)
404
+ const parts = toolPartSchemas(tool)
405
+ toolCalls.push(parts.toolCall)
406
+ toolResults.push(parts.toolResult)
392
407
  }
393
408
  return Schema.Union([
394
409
  TextStartPart,
@@ -53,6 +53,7 @@ const projectCapabilities = (
53
53
  capabilities: McpCore.CanonicalServerCapabilities
54
54
  ): typeof McpSchema.ServerCapabilities.Type => ({
55
55
  experimental: capabilities.experimental,
56
+ extensions: capabilities.extensions,
56
57
  logging: capabilities.logging ? {} : undefined,
57
58
  prompts: capabilities.prompts,
58
59
  resources: capabilities.resources,
@@ -134,6 +134,7 @@ export const protocol = McpProtocol.make({
134
134
  protocolVersion: McpSchema.protocolVersion,
135
135
  capabilities: ({
136
136
  experimental: result.capabilities.experimental,
137
+ extensions: result.capabilities.extensions,
137
138
  logging: result.capabilities.logging ? {} : undefined,
138
139
  completions: result.capabilities.completions ? {} : undefined,
139
140
  prompts: result.capabilities.prompts,
@@ -150,6 +150,7 @@ export const protocol = McpProtocol.make({
150
150
  protocolVersion: McpSchema.protocolVersion,
151
151
  capabilities: ({
152
152
  experimental: result.capabilities.experimental,
153
+ extensions: result.capabilities.extensions,
153
154
  logging: result.capabilities.logging ? {} : undefined,
154
155
  completions: result.capabilities.completions ? {} : undefined,
155
156
  prompts: result.capabilities.prompts,
@@ -145,6 +145,7 @@ export const protocol = McpProtocol.make({
145
145
  protocolVersion: McpSchema.protocolVersion,
146
146
  capabilities: ({
147
147
  experimental: result.capabilities.experimental,
148
+ extensions: result.capabilities.extensions,
148
149
  logging: result.capabilities.logging ? {} : undefined,
149
150
  completions: result.capabilities.completions ? {} : undefined,
150
151
  prompts: result.capabilities.prompts,
@@ -22,9 +22,9 @@ export const protocolVersion = "2024-11-05"
22
22
  */
23
23
  export const optional = <S extends Schema.Constraint>(
24
24
  schema: S
25
- ): Schema.decodeTo<Schema.optional<S>, Schema.optionalKey<S>> =>
25
+ ): Schema.decodeTo<Schema.toType<Schema.optional<S>>, Schema.optionalKey<S>> =>
26
26
  Schema.optionalKey(schema).pipe(
27
- Schema.decodeTo(Schema.optional(schema), {
27
+ Schema.decodeTo(Schema.toType(Schema.optional(schema)), {
28
28
  decode: SchemaGetter.passthrough(),
29
29
  encode: SchemaGetter.transformOptional(Option.flatMap(Option.fromUndefinedOr))
30
30
  })
@@ -111,6 +111,7 @@ export const Implementation = Schema.Struct({
111
111
  * @internal
112
112
  */
113
113
  export const ClientCapabilities = Schema.Struct({
114
+ extensions: optional(Schema.Record(Schema.TemplateLiteral([Schema.String, "/", Schema.String]), Schema.Json)),
114
115
  experimental: optional(Schema.Record(Schema.String, JsonObject)),
115
116
  roots: optional(Schema.Struct({
116
117
  listChanged: optional(Schema.Boolean)
@@ -122,6 +123,7 @@ export const ClientCapabilities = Schema.Struct({
122
123
  * @internal
123
124
  */
124
125
  export const ServerCapabilities = Schema.Struct({
126
+ extensions: optional(Schema.Record(Schema.TemplateLiteral([Schema.String, "/", Schema.String]), Schema.Json)),
125
127
  experimental: optional(Schema.Record(Schema.String, JsonObject)),
126
128
  logging: optional(JsonObject),
127
129
  prompts: optional(Schema.Struct({