@oh-my-pi/pi-utils 18.2.2 → 18.2.4
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.
- package/CHANGELOG.md +9 -0
- package/dist/types/async.d.ts +2 -9
- package/dist/types/stream.d.ts +13 -1
- package/package.json +2 -2
- package/src/async.ts +6 -12
- package/src/stream.ts +15 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [18.2.3] - 2026-09-17
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Optimized model configuration command execution by deduplicating requests and adding failure backoff
|
|
10
|
+
- Prevented unnecessary credential command execution when runtime API keys are configured
|
|
11
|
+
- Retained `readLines()` results no longer change when later chunks reuse the internal buffer.
|
|
12
|
+
- Long sleeps honor elapsed time and re-arm after premature timer wakes without overflowing native timer delays.
|
|
13
|
+
|
|
5
14
|
## [18.2.2] - 2026-09-16
|
|
6
15
|
|
|
7
16
|
### Added
|
package/dist/types/async.d.ts
CHANGED
|
@@ -12,15 +12,8 @@ export declare const MAX_TIMER_DELAY_MS = 2147483647;
|
|
|
12
12
|
* so no single timer overflows; an abort during any chunk rejects like
|
|
13
13
|
* `scheduler.wait`.
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* instant `scheduler.wait` mocks (retry-cap suites spy it to resolve
|
|
18
|
-
* immediately, so `deadline - performance.now()` never reaches zero and the
|
|
19
|
-
* loop spins forever). A premature native wake (Bun `uv_async_send`, see
|
|
20
|
-
* `sleepAtLeast` in `packages/agent/src/utils/yield.ts`) can therefore
|
|
21
|
-
* under-wait by the unelapsed chunk time — but that self-corrects downstream:
|
|
22
|
-
* credential blocks carry the true deadline independently of this sleep, so
|
|
23
|
-
* an early retry re-hits 429 and re-sleeps on a fresh server hint.
|
|
15
|
+
* Uses a monotonic deadline so a timer that wakes prematurely is re-armed for
|
|
16
|
+
* the unelapsed duration instead of shortening the requested sleep.
|
|
24
17
|
*/
|
|
25
18
|
export declare function sleepLong(delayMs: number, signal?: AbortSignal): Promise<void>;
|
|
26
19
|
/**
|
package/dist/types/stream.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Split a byte stream on LF boundaries.
|
|
3
|
+
*
|
|
4
|
+
* Every yielded line owns its bytes and remains unchanged after the generator
|
|
5
|
+
* advances or drains. Line terminators are excluded.
|
|
6
|
+
*/
|
|
1
7
|
export declare function readLines(stream: ReadableStream<Uint8Array>, signal?: AbortSignal): AsyncGenerator<Uint8Array>;
|
|
2
8
|
export declare function readJsonl<T>(stream: ReadableStream<Uint8Array>, signal?: AbortSignal): AsyncGenerator<T>;
|
|
3
9
|
/**
|
|
@@ -22,7 +28,13 @@ export declare class ConcatSink {
|
|
|
22
28
|
/** Drop the first `count` buffered bytes, keeping the remainder. */
|
|
23
29
|
consume(count: number): void;
|
|
24
30
|
clear(): void;
|
|
25
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Append a chunk and yield each complete LF-delimited line.
|
|
33
|
+
*
|
|
34
|
+
* Yielded lines are owned snapshots. Unlike {@link flush}, they remain
|
|
35
|
+
* valid after this sink or the input chunk is mutated.
|
|
36
|
+
*/
|
|
37
|
+
appendAndFlushLines(chunk: Uint8Array): Generator<Uint8Array>;
|
|
26
38
|
appendAndFlushText(chunk: Uint8Array, decoder: TextDecoder): string | undefined;
|
|
27
39
|
pullJSONL<T>(chunk: Uint8Array, beg: number, end: number): Generator<T, void, unknown>;
|
|
28
40
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-utils",
|
|
3
|
-
"version": "18.2.
|
|
3
|
+
"version": "18.2.4",
|
|
4
4
|
"description": "Shared utilities for pi packages",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"fmt": "oxfmt --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts'"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@oh-my-pi/pi-natives": "18.2.
|
|
57
|
+
"@oh-my-pi/pi-natives": "18.2.4"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@types/bun": "^1.3.14"
|
package/src/async.ts
CHANGED
|
@@ -15,22 +15,16 @@ export const MAX_TIMER_DELAY_MS = 2_147_483_647;
|
|
|
15
15
|
* so no single timer overflows; an abort during any chunk rejects like
|
|
16
16
|
* `scheduler.wait`.
|
|
17
17
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* instant `scheduler.wait` mocks (retry-cap suites spy it to resolve
|
|
21
|
-
* immediately, so `deadline - performance.now()` never reaches zero and the
|
|
22
|
-
* loop spins forever). A premature native wake (Bun `uv_async_send`, see
|
|
23
|
-
* `sleepAtLeast` in `packages/agent/src/utils/yield.ts`) can therefore
|
|
24
|
-
* under-wait by the unelapsed chunk time — but that self-corrects downstream:
|
|
25
|
-
* credential blocks carry the true deadline independently of this sleep, so
|
|
26
|
-
* an early retry re-hits 429 and re-sleeps on a fresh server hint.
|
|
18
|
+
* Uses a monotonic deadline so a timer that wakes prematurely is re-armed for
|
|
19
|
+
* the unelapsed duration instead of shortening the requested sleep.
|
|
27
20
|
*/
|
|
28
21
|
export async function sleepLong(delayMs: number, signal?: AbortSignal): Promise<void> {
|
|
29
22
|
signal?.throwIfAborted();
|
|
30
|
-
|
|
31
|
-
while (
|
|
23
|
+
const deadline = performance.now() + delayMs;
|
|
24
|
+
while (true) {
|
|
25
|
+
const remaining = deadline - performance.now();
|
|
26
|
+
if (!(remaining > 0)) return;
|
|
32
27
|
await scheduler.wait(Math.min(remaining, MAX_TIMER_DELAY_MS), { signal });
|
|
33
|
-
remaining -= MAX_TIMER_DELAY_MS;
|
|
34
28
|
signal?.throwIfAborted();
|
|
35
29
|
}
|
|
36
30
|
}
|
package/src/stream.ts
CHANGED
|
@@ -6,6 +6,12 @@ import { parseStreamingJson } from "./json-parse";
|
|
|
6
6
|
const LF = 0x0a;
|
|
7
7
|
const CR = 0x0d;
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Split a byte stream on LF boundaries.
|
|
11
|
+
*
|
|
12
|
+
* Every yielded line owns its bytes and remains unchanged after the generator
|
|
13
|
+
* advances or drains. Line terminators are excluded.
|
|
14
|
+
*/
|
|
9
15
|
export async function* readLines(stream: ReadableStream<Uint8Array>, signal?: AbortSignal): AsyncGenerator<Uint8Array> {
|
|
10
16
|
const buffer = new ConcatSink();
|
|
11
17
|
const source = abortableSource(stream, signal);
|
|
@@ -131,7 +137,13 @@ export class ConcatSink {
|
|
|
131
137
|
this.#length = 0;
|
|
132
138
|
}
|
|
133
139
|
|
|
134
|
-
|
|
140
|
+
/**
|
|
141
|
+
* Append a chunk and yield each complete LF-delimited line.
|
|
142
|
+
*
|
|
143
|
+
* Yielded lines are owned snapshots. Unlike {@link flush}, they remain
|
|
144
|
+
* valid after this sink or the input chunk is mutated.
|
|
145
|
+
*/
|
|
146
|
+
*appendAndFlushLines(chunk: Uint8Array): Generator<Uint8Array> {
|
|
135
147
|
let pos = 0;
|
|
136
148
|
while (pos < chunk.length) {
|
|
137
149
|
const nl = chunk.indexOf(LF, pos);
|
|
@@ -142,12 +154,12 @@ export class ConcatSink {
|
|
|
142
154
|
const suffix = chunk.subarray(pos, nl);
|
|
143
155
|
pos = nl + 1;
|
|
144
156
|
if (this.isEmpty) {
|
|
145
|
-
yield suffix;
|
|
157
|
+
yield new Uint8Array(suffix);
|
|
146
158
|
} else {
|
|
147
159
|
this.append(suffix);
|
|
148
160
|
const payload = this.flush();
|
|
149
161
|
if (payload) {
|
|
150
|
-
yield payload;
|
|
162
|
+
yield new Uint8Array(payload);
|
|
151
163
|
this.clear();
|
|
152
164
|
}
|
|
153
165
|
}
|