brass-runtime 1.13.8 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/agent/cli/main.cjs +43 -43
  2. package/dist/agent/cli/main.js +2 -2
  3. package/dist/agent/cli/main.mjs +2 -2
  4. package/dist/agent/index.cjs +3 -3
  5. package/dist/agent/index.d.ts +1 -1
  6. package/dist/agent/index.js +2 -2
  7. package/dist/agent/index.mjs +2 -2
  8. package/dist/chunk-4N2JEK4H.mjs +3897 -0
  9. package/dist/chunk-BKBFSOGT.cjs +3897 -0
  10. package/dist/{chunk-XNOTJSMZ.mjs → chunk-BMRF4FN6.js} +268 -8
  11. package/dist/chunk-JT7D6M5H.js +3897 -0
  12. package/dist/{chunk-3R7ZYRK2.mjs → chunk-MQF7HZ7Y.mjs} +1 -1
  13. package/dist/chunk-SKVY72E5.cjs +667 -0
  14. package/dist/{chunk-ATHSSDUF.js → chunk-UWMMYKVK.mjs} +268 -8
  15. package/dist/{chunk-INZBKOHY.js → chunk-WJESVBWN.js} +1 -1
  16. package/dist/{chunk-XDINDYNA.cjs → chunk-XTMZTVIT.cjs} +134 -134
  17. package/dist/{effect-ISvXPLgc.d.ts → effect-DM56H743.d.ts} +191 -21
  18. package/dist/http/index.cjs +808 -140
  19. package/dist/http/index.d.ts +181 -8
  20. package/dist/http/index.js +793 -125
  21. package/dist/http/index.mjs +793 -125
  22. package/dist/index.cjs +1785 -137
  23. package/dist/index.d.ts +979 -36
  24. package/dist/index.js +1675 -27
  25. package/dist/index.mjs +1675 -27
  26. package/dist/stream-Oqe6WeLE.d.ts +173 -0
  27. package/package.json +1 -1
  28. package/wasm/pkg/brass_runtime_wasm_engine.d.ts +95 -16
  29. package/wasm/pkg/brass_runtime_wasm_engine.js +715 -15
  30. package/wasm/pkg/brass_runtime_wasm_engine_bg.wasm +0 -0
  31. package/wasm/pkg/brass_runtime_wasm_engine_bg.wasm.d.ts +78 -7
  32. package/dist/chunk-2P4PD6D7.cjs +0 -2557
  33. package/dist/chunk-7F2R7A2V.mjs +0 -2557
  34. package/dist/chunk-L6KKKM66.js +0 -2557
  35. package/dist/chunk-ZTDK2DLG.cjs +0 -407
  36. package/dist/stream-BvukHxCv.d.ts +0 -66
@@ -22,7 +22,214 @@ import {
22
22
  sync,
23
23
  unsafeGetCurrentRuntime,
24
24
  unsafeRunFoldWithEnv
25
- } from "./chunk-L6KKKM66.js";
25
+ } from "./chunk-4N2JEK4H.mjs";
26
+
27
+ // src/core/runtime/combinators.ts
28
+ function sleep(ms) {
29
+ return async((_env, cb) => {
30
+ const delay = Math.max(0, Math.floor(ms));
31
+ const id = setTimeout(() => cb({ _tag: "Success", value: void 0 }), delay);
32
+ return () => clearTimeout(id);
33
+ });
34
+ }
35
+ function timeout(effect, ms) {
36
+ return async((env, cb) => {
37
+ let done = false;
38
+ let timerId;
39
+ let effectRunning = true;
40
+ timerId = setTimeout(() => {
41
+ if (done) return;
42
+ done = true;
43
+ effectRunning = false;
44
+ cb({
45
+ _tag: "Failure",
46
+ cause: { _tag: "Fail", error: { _tag: "TimeoutError", ms } }
47
+ });
48
+ }, Math.max(0, Math.floor(ms)));
49
+ const runtime = unsafeGetCurrentRuntime();
50
+ if (runtime) {
51
+ const fiber = runtime.fork(effect);
52
+ fiber.join((exit) => {
53
+ if (done) return;
54
+ done = true;
55
+ clearTimeout(timerId);
56
+ cb(exit);
57
+ });
58
+ return () => {
59
+ if (done) return;
60
+ done = true;
61
+ clearTimeout(timerId);
62
+ fiber.interrupt();
63
+ };
64
+ }
65
+ return () => {
66
+ if (done) return;
67
+ done = true;
68
+ clearTimeout(timerId);
69
+ };
70
+ });
71
+ }
72
+ function retry(effect, policy) {
73
+ const shouldRetry = policy.shouldRetry ?? (() => true);
74
+ const jitter = policy.jitter ?? "full";
75
+ const maxElapsedMs = policy.maxElapsedMs;
76
+ const computeDelay = (attempt) => {
77
+ const exp = policy.baseDelayMs * Math.pow(2, attempt);
78
+ const capped = Math.min(exp, policy.maxDelayMs);
79
+ if (jitter === "none") return capped;
80
+ return Math.floor(Math.random() * capped);
81
+ };
82
+ const loop = (attempt, startedAt) => asyncFold(
83
+ effect,
84
+ (error) => {
85
+ if (attempt >= policy.maxRetries) return asyncFail(error);
86
+ if (!shouldRetry(error, attempt)) return asyncFail(error);
87
+ if (maxElapsedMs !== void 0) {
88
+ const elapsed = performance.now() - startedAt;
89
+ if (elapsed >= maxElapsedMs) return asyncFail(error);
90
+ }
91
+ const delay = computeDelay(attempt);
92
+ return asyncFlatMap(sleep(delay), () => loop(attempt + 1, startedAt));
93
+ },
94
+ (value) => asyncSucceed(value)
95
+ );
96
+ return asyncFlatMap(
97
+ { _tag: "Sync", thunk: () => performance.now() },
98
+ (startedAt) => loop(0, startedAt)
99
+ );
100
+ }
101
+ function retryN(effect, n) {
102
+ return retry(effect, {
103
+ maxRetries: n,
104
+ baseDelayMs: 0,
105
+ maxDelayMs: 0,
106
+ jitter: "none"
107
+ });
108
+ }
109
+ function retryWithBackoff(effect, opts = {}) {
110
+ return retry(effect, {
111
+ maxRetries: opts.maxRetries ?? 3,
112
+ baseDelayMs: opts.baseDelayMs ?? 100,
113
+ maxDelayMs: opts.maxDelayMs ?? 1e4,
114
+ maxElapsedMs: opts.maxElapsedMs,
115
+ shouldRetry: opts.shouldRetry,
116
+ jitter: "full"
117
+ });
118
+ }
119
+
120
+ // src/core/runtime/circuitBreaker.ts
121
+ function makeCircuitBreaker(config = {}) {
122
+ const failureThreshold = config.failureThreshold ?? 5;
123
+ const resetTimeoutMs = config.resetTimeoutMs ?? 3e4;
124
+ const successThreshold = config.successThreshold ?? 1;
125
+ const isFailure = config.isFailure ?? (() => true);
126
+ const onStateChange = config.onStateChange;
127
+ let currentState = "closed";
128
+ let consecutiveFailures = 0;
129
+ let consecutiveSuccesses = 0;
130
+ let openedAt = 0;
131
+ let totalRequests = 0;
132
+ let totalFailures = 0;
133
+ let totalSuccesses = 0;
134
+ let totalRejected = 0;
135
+ let lastFailureTime = null;
136
+ let lastSuccessTime = null;
137
+ const transition = (to) => {
138
+ if (currentState === to) return;
139
+ const from = currentState;
140
+ currentState = to;
141
+ onStateChange?.(from, to);
142
+ };
143
+ const onSuccess = () => {
144
+ totalSuccesses++;
145
+ lastSuccessTime = Date.now();
146
+ consecutiveFailures = 0;
147
+ if (currentState === "half-open") {
148
+ consecutiveSuccesses++;
149
+ if (consecutiveSuccesses >= successThreshold) {
150
+ consecutiveSuccesses = 0;
151
+ transition("closed");
152
+ }
153
+ }
154
+ };
155
+ const onFailure = (error) => {
156
+ if (!isFailure(error)) {
157
+ onSuccess();
158
+ return;
159
+ }
160
+ totalFailures++;
161
+ lastFailureTime = Date.now();
162
+ consecutiveSuccesses = 0;
163
+ consecutiveFailures++;
164
+ if (currentState === "half-open") {
165
+ openedAt = Date.now();
166
+ transition("open");
167
+ } else if (currentState === "closed" && consecutiveFailures >= failureThreshold) {
168
+ openedAt = Date.now();
169
+ transition("open");
170
+ }
171
+ };
172
+ const shouldAllow = () => {
173
+ switch (currentState) {
174
+ case "closed":
175
+ return true;
176
+ case "open": {
177
+ const elapsed = Date.now() - openedAt;
178
+ if (elapsed >= resetTimeoutMs) {
179
+ transition("half-open");
180
+ return true;
181
+ }
182
+ return false;
183
+ }
184
+ case "half-open":
185
+ return true;
186
+ }
187
+ };
188
+ const protect = (effect) => {
189
+ totalRequests++;
190
+ if (!shouldAllow()) {
191
+ totalRejected++;
192
+ return asyncFail({
193
+ _tag: "CircuitBreakerOpen",
194
+ openSince: openedAt,
195
+ failures: consecutiveFailures
196
+ });
197
+ }
198
+ return asyncFold(
199
+ effect,
200
+ (error) => {
201
+ onFailure(error);
202
+ return asyncFail(error);
203
+ },
204
+ (value) => {
205
+ onSuccess();
206
+ return asyncSucceed(value);
207
+ }
208
+ );
209
+ };
210
+ const stats = () => ({
211
+ state: currentState,
212
+ failures: consecutiveFailures,
213
+ successes: consecutiveSuccesses,
214
+ totalRequests,
215
+ totalFailures,
216
+ totalSuccesses,
217
+ totalRejected,
218
+ lastFailureTime,
219
+ lastSuccessTime
220
+ });
221
+ const reset = () => {
222
+ consecutiveFailures = 0;
223
+ consecutiveSuccesses = 0;
224
+ transition("closed");
225
+ };
226
+ return {
227
+ state: () => currentState,
228
+ protect,
229
+ stats,
230
+ reset
231
+ };
232
+ }
26
233
 
27
234
  // src/core/stream/stream.ts
28
235
  var widenOpt = (opt) => opt._tag === "None" ? none : some(opt.value);
@@ -111,6 +318,12 @@ function uncons(self) {
111
318
  switch (self._tag) {
112
319
  case "Empty":
113
320
  return fail(none);
321
+ case "FromArray": {
322
+ const arr = self.values;
323
+ if (arr.length === 0) return fail(none);
324
+ const tail = arr.length === 1 ? EMPTY_STREAM : { _tag: "FromArray", values: arr.slice(1) };
325
+ return succeed([arr[0], tail]);
326
+ }
114
327
  case "Emit":
115
328
  return map(
116
329
  mapError(self.value, (e) => some(e)),
@@ -244,6 +457,8 @@ function mapStream(self, f) {
244
457
  switch (self._tag) {
245
458
  case "Empty":
246
459
  return emptyStream();
460
+ case "FromArray":
461
+ return { _tag: "FromArray", values: self.values.map(f) };
247
462
  case "Emit":
248
463
  return emitStream(map(self.value, f));
249
464
  case "FromPull":
@@ -327,27 +542,66 @@ function foreachStream(stream, f) {
327
542
  );
328
543
  }
329
544
  function fromArray(values) {
330
- let s = emptyStream();
331
- for (let i = values.length - 1; i >= 0; i--) {
332
- const head = emitStream(succeed(values[i]));
333
- s = concatStream(head, s);
334
- }
335
- return s;
545
+ if (values.length === 0) return emptyStream();
546
+ return { _tag: "FromArray", values };
336
547
  }
337
548
  function collectStream(stream) {
549
+ const syncResult = drainStreamSyncFull(stream);
550
+ if (syncResult !== null) {
551
+ return asyncSucceed(syncResult);
552
+ }
338
553
  const loop = (cur, acc) => asyncFold(
339
554
  uncons(cur),
340
555
  (opt) => {
341
556
  if (opt._tag === "None") return succeed(acc);
342
557
  return fail(opt);
343
558
  },
344
- ([a, tail]) => loop(tail, [...acc, a])
559
+ ([a, tail]) => {
560
+ acc.push(a);
561
+ return loop(tail, acc);
562
+ }
345
563
  );
346
564
  return mapError(loop(stream, []), (opt) => {
347
565
  if (opt._tag === "Some") return opt.value;
348
566
  throw new Error("unreachable: stream end handled as success");
349
567
  });
350
568
  }
569
+ function drainStreamSyncFull(stream) {
570
+ const result = [];
571
+ let cur = stream;
572
+ while (true) {
573
+ switch (cur._tag) {
574
+ case "Empty":
575
+ return result;
576
+ case "FromArray": {
577
+ const arr = cur.values;
578
+ for (let i = 0; i < arr.length; i++) {
579
+ result.push(arr[i]);
580
+ }
581
+ return result;
582
+ }
583
+ case "Emit": {
584
+ const zio = cur.value;
585
+ if (zio._tag === "Succeed") {
586
+ result.push(zio.value);
587
+ return result;
588
+ }
589
+ return null;
590
+ }
591
+ case "Concat": {
592
+ const leftItems = drainStreamSyncFull(cur.left);
593
+ if (leftItems === null) return null;
594
+ for (let i = 0; i < leftItems.length; i++) {
595
+ result.push(leftItems[i]);
596
+ }
597
+ cur = cur.right;
598
+ break;
599
+ }
600
+ default:
601
+ return null;
602
+ }
603
+ }
604
+ }
351
605
  function readerStream(reader, normalizeError) {
352
606
  const pull = async((_, cb) => {
353
607
  reader.read().then(({ done, value }) => {
@@ -385,6 +639,12 @@ function streamFromReadableStream(body, normalizeError) {
385
639
  }
386
640
 
387
641
  export {
642
+ sleep,
643
+ timeout,
644
+ retry,
645
+ retryN,
646
+ retryWithBackoff,
647
+ makeCircuitBreaker,
388
648
  widenOpt,
389
649
  fromPull,
390
650
  unwrapScoped,
@@ -11,7 +11,7 @@ import {
11
11
  fromPromiseAbortable,
12
12
  race,
13
13
  withScopeAsync
14
- } from "./chunk-L6KKKM66.js";
14
+ } from "./chunk-JT7D6M5H.js";
15
15
 
16
16
  // src/agent/core/state.ts
17
17
  var initialAgentState = (goal) => ({