@skillstate/core 0.0.1 → 2.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.
- package/dist/atomic-write.d.ts +40 -0
- package/dist/atomic-write.d.ts.map +1 -0
- package/dist/atomic-write.js +97 -0
- package/dist/atomic-write.js.map +1 -0
- package/dist/clock.d.ts +27 -0
- package/dist/clock.d.ts.map +1 -0
- package/dist/clock.js +45 -0
- package/dist/clock.js.map +1 -0
- package/dist/config.d.ts +43 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +152 -0
- package/dist/config.js.map +1 -0
- package/dist/events.d.ts +59 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +36 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/instrumentation.d.ts +35 -0
- package/dist/instrumentation.d.ts.map +1 -0
- package/dist/instrumentation.js +41 -0
- package/dist/instrumentation.js.map +1 -0
- package/dist/logger.d.ts +34 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +40 -0
- package/dist/logger.js.map +1 -0
- package/dist/migrations.d.ts +35 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/migrations.js +26 -0
- package/dist/migrations.js.map +1 -0
- package/dist/prompt-transformer.d.ts +106 -0
- package/dist/prompt-transformer.d.ts.map +1 -0
- package/dist/prompt-transformer.js +265 -0
- package/dist/prompt-transformer.js.map +1 -0
- package/dist/provider.d.ts +62 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +46 -0
- package/dist/provider.js.map +1 -0
- package/dist/redaction.d.ts +26 -0
- package/dist/redaction.d.ts.map +1 -0
- package/dist/redaction.js +38 -0
- package/dist/redaction.js.map +1 -0
- package/dist/resilience.d.ts +83 -0
- package/dist/resilience.d.ts.map +1 -0
- package/dist/resilience.js +171 -0
- package/dist/resilience.js.map +1 -0
- package/dist/runtime.d.ts +223 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +362 -0
- package/dist/runtime.js.map +1 -0
- package/dist/schemas/index.d.ts +2 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +3 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/intercode-ctf.d.ts +3 -0
- package/dist/schemas/intercode-ctf.d.ts.map +1 -0
- package/dist/schemas/intercode-ctf.js +53 -0
- package/dist/schemas/intercode-ctf.js.map +1 -0
- package/dist/shutdown.d.ts +20 -0
- package/dist/shutdown.d.ts.map +1 -0
- package/dist/shutdown.js +42 -0
- package/dist/shutdown.js.map +1 -0
- package/dist/state-manager.d.ts +23 -0
- package/dist/state-manager.d.ts.map +1 -0
- package/dist/state-manager.js +129 -0
- package/dist/state-manager.js.map +1 -0
- package/dist/state-store.d.ts +48 -0
- package/dist/state-store.d.ts.map +1 -0
- package/dist/state-store.js +101 -0
- package/dist/state-store.js.map +1 -0
- package/dist/token-tracker.d.ts +104 -0
- package/dist/token-tracker.d.ts.map +1 -0
- package/dist/token-tracker.js +204 -0
- package/dist/token-tracker.js.map +1 -0
- package/dist/types.d.ts +61 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/validate.d.ts +39 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +180 -0
- package/dist/validate.js.map +1 -0
- package/package.json +23 -5
- package/LICENSE +0 -21
- package/README.md +0 -11
- package/index.js +0 -3
package/dist/provider.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @non-paper LLM provider seam (Wave 4 DX).
|
|
3
|
+
*
|
|
4
|
+
* The paper core calls a bare `LLMFn` (`prompt => response text`) and
|
|
5
|
+
* measures raw string chars itself (§4.3). This module adds an OPTIONAL,
|
|
6
|
+
* additive provider interface for hosts that already report usage:
|
|
7
|
+
*
|
|
8
|
+
* - `LLMProvider.call(prompt, opts?)` resolves `{ text, usage? }` where
|
|
9
|
+
* `usage.promptChars` / `usage.completionChars` are RAW STRING CHARS
|
|
10
|
+
* (§4.3) reported by the caller — never tokenizer output;
|
|
11
|
+
* - `fromLLMFn(fn)` wraps a legacy `LLMFn` into an `LLMProvider`
|
|
12
|
+
* (backwards compatibility; `LLMFn` itself is NOT removed);
|
|
13
|
+
* - `isLLMProvider(v)` distinguishes `LLMFn | LLMProvider` at runtime
|
|
14
|
+
* (function = legacy fn, object with a `call` function = provider).
|
|
15
|
+
*
|
|
16
|
+
* The runtime accepts `llm: LLMFn | LLMProvider`: with a provider it
|
|
17
|
+
* prefers `usage` over measuring strings, otherwise it measures exactly
|
|
18
|
+
* as before. Zero dependencies, Node >= 20, ESM.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* @non-paper runtime guard: an object with a callable `call` is a
|
|
22
|
+
* provider; anything else passed as `llm` is treated as a legacy `LLMFn`.
|
|
23
|
+
*/
|
|
24
|
+
export function isLLMProvider(value) {
|
|
25
|
+
if (typeof value !== 'object' || value === null) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
return typeof value.call === 'function';
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* @non-paper backwards-compatibility adapter: wrap a legacy `LLMFn`
|
|
32
|
+
* into an `LLMProvider`. The wrapper honors an already-aborted `signal`
|
|
33
|
+
* (rejects with `signal.reason`) and otherwise delegates verbatim —
|
|
34
|
+
* no usage is synthesized, so the runtime measures strings as before.
|
|
35
|
+
*/
|
|
36
|
+
export function fromLLMFn(fn) {
|
|
37
|
+
return {
|
|
38
|
+
async call(prompt, opts) {
|
|
39
|
+
if (opts?.signal?.aborted === true) {
|
|
40
|
+
throw opts.signal.reason;
|
|
41
|
+
}
|
|
42
|
+
return { text: await fn(prompt) };
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAqCH;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAChD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,OAAQ,KAA4B,CAAC,IAAI,KAAK,UAAU,CAAC;AAClE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,EAAa;IACrC,OAAO;QACL,KAAK,CAAC,IAAI,CAAC,MAAc,EAAE,IAAqB;YAC9C,IAAI,IAAI,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,EAAE,CAAC;gBACnC,MAAO,IAAI,CAAC,MAAsB,CAAC,MAAM,CAAC;YAC5C,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;QACpC,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @non-paper secret redaction for logs, prompts, and persisted reports.
|
|
3
|
+
*
|
|
4
|
+
* The paper core never sees credentials, but the @non-paper adapters and
|
|
5
|
+
* trackers shuttle raw LLM text through logs and state files. `redactSecrets`
|
|
6
|
+
* is a fail-closed scrubber: anything shaped like a credential is replaced
|
|
7
|
+
* with `[REDACTED]` before the text leaves the process boundary.
|
|
8
|
+
*
|
|
9
|
+
* Covered shapes:
|
|
10
|
+
* - AWS access keys (`AKIA` + 16 uppercase alphanumerics);
|
|
11
|
+
* - GitHub tokens (`ghp_` + alphanumerics);
|
|
12
|
+
* - OpenAI-style keys (`sk-` + alphanumerics/dashes/underscores);
|
|
13
|
+
* - `Bearer <token>` authorisation headers (scheme is kept, token scrubbed);
|
|
14
|
+
* - PEM private-key blocks (`-----BEGIN … PRIVATE KEY-----` … `-----END …`).
|
|
15
|
+
*
|
|
16
|
+
* Pure string function, zero dependencies, Node >= 20, ESM.
|
|
17
|
+
*/
|
|
18
|
+
/** Replacement marker for anything shaped like a secret. */
|
|
19
|
+
export declare const REDACTED = "[REDACTED]";
|
|
20
|
+
/**
|
|
21
|
+
* Replace every credential-shaped span in `text` with `[REDACTED]`
|
|
22
|
+
* (`Bearer <token>` keeps the scheme: `Bearer [REDACTED]`). Pure: the
|
|
23
|
+
* input string is never mutated.
|
|
24
|
+
*/
|
|
25
|
+
export declare function redactSecrets(text: string): string;
|
|
26
|
+
//# sourceMappingURL=redaction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redaction.d.ts","sourceRoot":"","sources":["../src/redaction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,4DAA4D;AAC5D,eAAO,MAAM,QAAQ,eAAe,CAAC;AASrC;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOlD"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @non-paper secret redaction for logs, prompts, and persisted reports.
|
|
3
|
+
*
|
|
4
|
+
* The paper core never sees credentials, but the @non-paper adapters and
|
|
5
|
+
* trackers shuttle raw LLM text through logs and state files. `redactSecrets`
|
|
6
|
+
* is a fail-closed scrubber: anything shaped like a credential is replaced
|
|
7
|
+
* with `[REDACTED]` before the text leaves the process boundary.
|
|
8
|
+
*
|
|
9
|
+
* Covered shapes:
|
|
10
|
+
* - AWS access keys (`AKIA` + 16 uppercase alphanumerics);
|
|
11
|
+
* - GitHub tokens (`ghp_` + alphanumerics);
|
|
12
|
+
* - OpenAI-style keys (`sk-` + alphanumerics/dashes/underscores);
|
|
13
|
+
* - `Bearer <token>` authorisation headers (scheme is kept, token scrubbed);
|
|
14
|
+
* - PEM private-key blocks (`-----BEGIN … PRIVATE KEY-----` … `-----END …`).
|
|
15
|
+
*
|
|
16
|
+
* Pure string function, zero dependencies, Node >= 20, ESM.
|
|
17
|
+
*/
|
|
18
|
+
/** Replacement marker for anything shaped like a secret. */
|
|
19
|
+
export const REDACTED = '[REDACTED]';
|
|
20
|
+
const PRIVATE_KEY_BLOCK = /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z0-9 ]*PRIVATE KEY-----/g;
|
|
21
|
+
const AWS_ACCESS_KEY = /\bAKIA[0-9A-Z]{16}\b/g;
|
|
22
|
+
const GITHUB_TOKEN = /\bghp_[A-Za-z0-9_]+/g;
|
|
23
|
+
const OPENAI_KEY = /\bsk-[A-Za-z0-9_-]+/g;
|
|
24
|
+
const BEARER_TOKEN = /\bBearer\s+[A-Za-z0-9\-._~+/=]{8,}/g;
|
|
25
|
+
/**
|
|
26
|
+
* Replace every credential-shaped span in `text` with `[REDACTED]`
|
|
27
|
+
* (`Bearer <token>` keeps the scheme: `Bearer [REDACTED]`). Pure: the
|
|
28
|
+
* input string is never mutated.
|
|
29
|
+
*/
|
|
30
|
+
export function redactSecrets(text) {
|
|
31
|
+
return text
|
|
32
|
+
.replace(PRIVATE_KEY_BLOCK, REDACTED)
|
|
33
|
+
.replace(AWS_ACCESS_KEY, REDACTED)
|
|
34
|
+
.replace(GITHUB_TOKEN, REDACTED)
|
|
35
|
+
.replace(OPENAI_KEY, REDACTED)
|
|
36
|
+
.replace(BEARER_TOKEN, 'Bearer [REDACTED]');
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=redaction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redaction.js","sourceRoot":"","sources":["../src/redaction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,4DAA4D;AAC5D,MAAM,CAAC,MAAM,QAAQ,GAAG,YAAY,CAAC;AAErC,MAAM,iBAAiB,GACrB,mFAAmF,CAAC;AACtF,MAAM,cAAc,GAAG,uBAAuB,CAAC;AAC/C,MAAM,YAAY,GAAG,sBAAsB,CAAC;AAC5C,MAAM,UAAU,GAAG,sBAAsB,CAAC;AAC1C,MAAM,YAAY,GAAG,qCAAqC,CAAC;AAE3D;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,IAAI;SACR,OAAO,CAAC,iBAAiB,EAAE,QAAQ,CAAC;SACpC,OAAO,CAAC,cAAc,EAAE,QAAQ,CAAC;SACjC,OAAO,CAAC,YAAY,EAAE,QAAQ,CAAC;SAC/B,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC;SAC7B,OAAO,CAAC,YAAY,EAAE,mBAAmB,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @non-paper resilience helpers — timeouts, retries with backoff+jitter,
|
|
3
|
+
* and a circuit breaker for flaky LLM / executor calls.
|
|
4
|
+
*
|
|
5
|
+
* Nothing here changes paper semantics: these wrap the TRANSPORT (how long
|
|
6
|
+
* we wait, how often we re-issue a failed call), never the Algorithm 1
|
|
7
|
+
* prompt format, the ⊕ merge, or the §7 validation-retry cycle. All of it
|
|
8
|
+
* is opt-in — the runtime only uses these when the caller passes the
|
|
9
|
+
* @non-paper `timeoutMs` / `signal` / `retry` options.
|
|
10
|
+
*
|
|
11
|
+
* Zero dependencies, Node >= 20, ESM.
|
|
12
|
+
*/
|
|
13
|
+
/** Rejection reason for {@link withTimeout} when the deadline fires. */
|
|
14
|
+
export declare class TimeoutError extends Error {
|
|
15
|
+
constructor(ms: number);
|
|
16
|
+
}
|
|
17
|
+
/** Rejection reason for {@link CircuitBreaker.exec} while the circuit is open. */
|
|
18
|
+
export declare class CircuitOpenError extends Error {
|
|
19
|
+
constructor();
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Race `promise` against a deadline (and, optionally, an AbortSignal).
|
|
23
|
+
*
|
|
24
|
+
* - Resolves/rejects with whatever `promise` settles to when it wins.
|
|
25
|
+
* - Rejects with {@link TimeoutError} when `ms` elapses first.
|
|
26
|
+
* - Rejects with `signal.reason` when `signal` is already aborted or aborts
|
|
27
|
+
* mid-flight. The timer is always cleared on settle so no handle leaks.
|
|
28
|
+
*/
|
|
29
|
+
export declare function withTimeout<T>(promise: Promise<T>, ms: number, signal?: AbortSignal): Promise<T>;
|
|
30
|
+
/** Options for {@link withRetry}. */
|
|
31
|
+
export interface RetryOptions {
|
|
32
|
+
/** Retries AFTER the first attempt (total attempts = 1 + maxRetries). */
|
|
33
|
+
maxRetries: number;
|
|
34
|
+
/** Base backoff in ms; attempt n waits `baseMs * 2^n` (+ jitter). */
|
|
35
|
+
baseMs: number;
|
|
36
|
+
/** When true, add `Math.random() * backoff` on top of the backoff. */
|
|
37
|
+
jitter?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Re-issue a rejected `fn` up to `maxRetries` times with exponential
|
|
41
|
+
* backoff (`baseMs * 2^attempt`) and optional jitter. Resolves with the
|
|
42
|
+
* first success; rethrows the last error when attempts are exhausted.
|
|
43
|
+
* A `maxRetries` of 0 means a single attempt (no waiting).
|
|
44
|
+
*/
|
|
45
|
+
export declare function withRetry<T>(fn: () => Promise<T>, options: RetryOptions): Promise<T>;
|
|
46
|
+
/** Observable circuit state. */
|
|
47
|
+
export type CircuitState = 'closed' | 'open' | 'half-open';
|
|
48
|
+
/** Options for {@link CircuitBreaker}. */
|
|
49
|
+
export interface CircuitBreakerOptions {
|
|
50
|
+
/** Consecutive failures that trip the circuit from closed to open. */
|
|
51
|
+
failureThreshold: number;
|
|
52
|
+
/** Ms an open circuit waits before letting one trial call through. */
|
|
53
|
+
resetTimeoutMs: number;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Minimal circuit breaker (@non-paper transport guard).
|
|
57
|
+
*
|
|
58
|
+
* - `closed`: calls pass through; consecutive failures are counted and
|
|
59
|
+
* reset by any success. `failureThreshold` consecutive failures open it.
|
|
60
|
+
* - `open`: calls are rejected immediately with {@link CircuitOpenError}
|
|
61
|
+
* without invoking `fn`. After `resetTimeoutMs` the next observed state
|
|
62
|
+
* (and the next `exec`) becomes `half-open`.
|
|
63
|
+
* - `half-open`: a single trial call goes through. Success closes the
|
|
64
|
+
* circuit (counters reset); failure re-opens it (timeout restarts).
|
|
65
|
+
*/
|
|
66
|
+
export declare class CircuitBreaker {
|
|
67
|
+
private readonly options;
|
|
68
|
+
private failures;
|
|
69
|
+
private opened;
|
|
70
|
+
private halfOpen;
|
|
71
|
+
private openedAt;
|
|
72
|
+
constructor(options: CircuitBreakerOptions);
|
|
73
|
+
/** Current state; lazily transitions open → half-open after the timeout. */
|
|
74
|
+
get state(): CircuitState;
|
|
75
|
+
/**
|
|
76
|
+
* Run `fn` through the circuit. Rejects with {@link CircuitOpenError}
|
|
77
|
+
* while open; otherwise runs `fn` and records success/failure.
|
|
78
|
+
*/
|
|
79
|
+
exec<T>(fn: () => Promise<T>): Promise<T>;
|
|
80
|
+
private onSuccess;
|
|
81
|
+
private onFailure;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=resilience.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resilience.d.ts","sourceRoot":"","sources":["../src/resilience.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,wEAAwE;AACxE,qBAAa,YAAa,SAAQ,KAAK;IACrC,YAAY,EAAE,EAAE,MAAM,EAGrB;CACF;AAED,kFAAkF;AAClF,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,cAGC;CACF;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC3B,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,EAAE,EAAE,MAAM,EACV,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,CAAC,CAAC,CA4BZ;AAED,qCAAqC;AACrC,MAAM,WAAW,YAAY;IAC3B,yEAAyE;IACzE,UAAU,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAQD;;;;;GAKG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,CAAC,CAAC,CAoBZ;AAED,gCAAgC;AAChC,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;AAE3D,0CAA0C;AAC1C,MAAM,WAAW,qBAAqB;IACpC,sEAAsE;IACtE,gBAAgB,EAAE,MAAM,CAAC;IACzB,sEAAsE;IACtE,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;GAUG;AACH,qBAAa,cAAc;IAMb,OAAO,CAAC,QAAQ,CAAC,OAAO;IALpC,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAK;IAErB,YAA6B,OAAO,EAAE,qBAAqB,EAAI;IAE/D,4EAA4E;IAC5E,IAAI,KAAK,IAAI,YAAY,CAexB;IAED;;;OAGG;IACG,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAa9C;IAED,OAAO,CAAC,SAAS;IAUjB,OAAO,CAAC,SAAS;CAYlB"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @non-paper resilience helpers — timeouts, retries with backoff+jitter,
|
|
3
|
+
* and a circuit breaker for flaky LLM / executor calls.
|
|
4
|
+
*
|
|
5
|
+
* Nothing here changes paper semantics: these wrap the TRANSPORT (how long
|
|
6
|
+
* we wait, how often we re-issue a failed call), never the Algorithm 1
|
|
7
|
+
* prompt format, the ⊕ merge, or the §7 validation-retry cycle. All of it
|
|
8
|
+
* is opt-in — the runtime only uses these when the caller passes the
|
|
9
|
+
* @non-paper `timeoutMs` / `signal` / `retry` options.
|
|
10
|
+
*
|
|
11
|
+
* Zero dependencies, Node >= 20, ESM.
|
|
12
|
+
*/
|
|
13
|
+
/** Rejection reason for {@link withTimeout} when the deadline fires. */
|
|
14
|
+
export class TimeoutError extends Error {
|
|
15
|
+
constructor(ms) {
|
|
16
|
+
super(`Timed out after ${ms}ms`);
|
|
17
|
+
this.name = 'TimeoutError';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** Rejection reason for {@link CircuitBreaker.exec} while the circuit is open. */
|
|
21
|
+
export class CircuitOpenError extends Error {
|
|
22
|
+
constructor() {
|
|
23
|
+
super('Circuit breaker is open');
|
|
24
|
+
this.name = 'CircuitOpenError';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Race `promise` against a deadline (and, optionally, an AbortSignal).
|
|
29
|
+
*
|
|
30
|
+
* - Resolves/rejects with whatever `promise` settles to when it wins.
|
|
31
|
+
* - Rejects with {@link TimeoutError} when `ms` elapses first.
|
|
32
|
+
* - Rejects with `signal.reason` when `signal` is already aborted or aborts
|
|
33
|
+
* mid-flight. The timer is always cleared on settle so no handle leaks.
|
|
34
|
+
*/
|
|
35
|
+
export function withTimeout(promise, ms, signal) {
|
|
36
|
+
return new Promise((resolve, reject) => {
|
|
37
|
+
if (signal?.aborted) {
|
|
38
|
+
reject(signal.reason);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const onAbort = () => {
|
|
42
|
+
clearTimeout(timer);
|
|
43
|
+
reject(signal.reason);
|
|
44
|
+
};
|
|
45
|
+
const timer = setTimeout(() => {
|
|
46
|
+
signal?.removeEventListener('abort', onAbort);
|
|
47
|
+
reject(new TimeoutError(ms));
|
|
48
|
+
}, ms);
|
|
49
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
50
|
+
promise.then((value) => {
|
|
51
|
+
clearTimeout(timer);
|
|
52
|
+
signal?.removeEventListener('abort', onAbort);
|
|
53
|
+
resolve(value);
|
|
54
|
+
}, (error) => {
|
|
55
|
+
clearTimeout(timer);
|
|
56
|
+
signal?.removeEventListener('abort', onAbort);
|
|
57
|
+
reject(error);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function sleep(ms) {
|
|
62
|
+
return new Promise((resolve) => {
|
|
63
|
+
setTimeout(resolve, ms);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Re-issue a rejected `fn` up to `maxRetries` times with exponential
|
|
68
|
+
* backoff (`baseMs * 2^attempt`) and optional jitter. Resolves with the
|
|
69
|
+
* first success; rethrows the last error when attempts are exhausted.
|
|
70
|
+
* A `maxRetries` of 0 means a single attempt (no waiting).
|
|
71
|
+
*/
|
|
72
|
+
export async function withRetry(fn, options) {
|
|
73
|
+
let lastError = null;
|
|
74
|
+
const attempts = options.maxRetries + 1;
|
|
75
|
+
for (let attempt = 0; attempt < attempts; attempt += 1) {
|
|
76
|
+
try {
|
|
77
|
+
return await fn();
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
lastError = error;
|
|
81
|
+
if (attempt >= options.maxRetries) {
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
const backoff = options.baseMs * 2 ** attempt;
|
|
85
|
+
const delay = options.jitter === true ? backoff + Math.random() * backoff : backoff;
|
|
86
|
+
if (delay > 0) {
|
|
87
|
+
await sleep(delay);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
throw lastError;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Minimal circuit breaker (@non-paper transport guard).
|
|
95
|
+
*
|
|
96
|
+
* - `closed`: calls pass through; consecutive failures are counted and
|
|
97
|
+
* reset by any success. `failureThreshold` consecutive failures open it.
|
|
98
|
+
* - `open`: calls are rejected immediately with {@link CircuitOpenError}
|
|
99
|
+
* without invoking `fn`. After `resetTimeoutMs` the next observed state
|
|
100
|
+
* (and the next `exec`) becomes `half-open`.
|
|
101
|
+
* - `half-open`: a single trial call goes through. Success closes the
|
|
102
|
+
* circuit (counters reset); failure re-opens it (timeout restarts).
|
|
103
|
+
*/
|
|
104
|
+
export class CircuitBreaker {
|
|
105
|
+
options;
|
|
106
|
+
failures = 0;
|
|
107
|
+
opened = false;
|
|
108
|
+
halfOpen = false;
|
|
109
|
+
openedAt = 0;
|
|
110
|
+
constructor(options) {
|
|
111
|
+
this.options = options;
|
|
112
|
+
}
|
|
113
|
+
/** Current state; lazily transitions open → half-open after the timeout. */
|
|
114
|
+
get state() {
|
|
115
|
+
if (this.opened &&
|
|
116
|
+
!this.halfOpen &&
|
|
117
|
+
Date.now() - this.openedAt >= this.options.resetTimeoutMs) {
|
|
118
|
+
this.halfOpen = true;
|
|
119
|
+
}
|
|
120
|
+
if (this.halfOpen) {
|
|
121
|
+
return 'half-open';
|
|
122
|
+
}
|
|
123
|
+
if (this.opened) {
|
|
124
|
+
return 'open';
|
|
125
|
+
}
|
|
126
|
+
return 'closed';
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Run `fn` through the circuit. Rejects with {@link CircuitOpenError}
|
|
130
|
+
* while open; otherwise runs `fn` and records success/failure.
|
|
131
|
+
*/
|
|
132
|
+
async exec(fn) {
|
|
133
|
+
const current = this.state;
|
|
134
|
+
if (current === 'open') {
|
|
135
|
+
throw new CircuitOpenError();
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
const result = await fn();
|
|
139
|
+
this.onSuccess();
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
this.onFailure();
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
onSuccess() {
|
|
148
|
+
if (this.halfOpen) {
|
|
149
|
+
this.opened = false;
|
|
150
|
+
this.halfOpen = false;
|
|
151
|
+
this.failures = 0;
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
this.failures = 0;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
onFailure() {
|
|
158
|
+
if (this.halfOpen) {
|
|
159
|
+
this.halfOpen = false;
|
|
160
|
+
this.openedAt = Date.now();
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
this.failures += 1;
|
|
164
|
+
if (this.failures >= this.options.failureThreshold) {
|
|
165
|
+
this.opened = true;
|
|
166
|
+
this.openedAt = Date.now();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=resilience.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resilience.js","sourceRoot":"","sources":["../src/resilience.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import type { ProceduralSpec, SkillState, Observation, StatePatch } from './types.js';
|
|
2
|
+
import type { RetryOptions } from './resilience.js';
|
|
3
|
+
import type { TokenTracker } from './token-tracker.js';
|
|
4
|
+
import type { Clock } from './clock.js';
|
|
5
|
+
import type { RuntimeEventEmitter } from './events.js';
|
|
6
|
+
import type { Logger } from './logger.js';
|
|
7
|
+
import type { LLMProvider } from './provider.js';
|
|
8
|
+
/** LLM function: prompt in, response out. */
|
|
9
|
+
export interface LLMFn {
|
|
10
|
+
(prompt: string): Promise<string>;
|
|
11
|
+
}
|
|
12
|
+
/** Action executor: runs the chosen action against the environment. */
|
|
13
|
+
export interface ActionExecutor {
|
|
14
|
+
(action: string, state: SkillState): Promise<Observation>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Options for constructing a SkillStateRuntime.
|
|
18
|
+
*
|
|
19
|
+
* Paper-exact Algorithm 1 (§3.2) takes no size caps, no history budget, and
|
|
20
|
+
* no token estimator: the prompt is At = (P, Σt, Ot) and nothing else.
|
|
21
|
+
*/
|
|
22
|
+
export interface RuntimeOptions {
|
|
23
|
+
spec: ProceduralSpec;
|
|
24
|
+
initialState?: SkillState;
|
|
25
|
+
/**
|
|
26
|
+
* Paper-exact `LLMFn` or the @non-paper `LLMProvider` seam (Wave 4 DX).
|
|
27
|
+
* A function is called verbatim and measured in raw chars; a provider's
|
|
28
|
+
* `usage` (raw chars, §4.3) is preferred over measuring when present.
|
|
29
|
+
*/
|
|
30
|
+
llm: LLMFn | LLMProvider;
|
|
31
|
+
execute: ActionExecutor;
|
|
32
|
+
tracker?: TokenTracker;
|
|
33
|
+
/**
|
|
34
|
+
* Retries after the first failed attempt (§7 rollback-retry).
|
|
35
|
+
* Default 2 (max attempts = 3).
|
|
36
|
+
*/
|
|
37
|
+
maxValidationRetries?: number;
|
|
38
|
+
/**
|
|
39
|
+
* @non-paper resilience (additive, opt-in). Per-call deadline in ms for
|
|
40
|
+
* the `llm`/`execute` transport calls. Unset = paper-exact direct calls
|
|
41
|
+
* with no timeout layer at all.
|
|
42
|
+
*/
|
|
43
|
+
timeoutMs?: number;
|
|
44
|
+
/**
|
|
45
|
+
* @non-paper resilience (additive, opt-in). AbortSignal threaded through
|
|
46
|
+
* the `llm`/`execute` calls: an aborted signal rejects the in-flight call
|
|
47
|
+
* with `signal.reason`. Unset = no abort handling.
|
|
48
|
+
*/
|
|
49
|
+
signal?: AbortSignal;
|
|
50
|
+
/**
|
|
51
|
+
* @non-paper resilience (additive, opt-in). Transient transport-error
|
|
52
|
+
* retries for `llm`/`execute` (thrown errors re-issued with backoff).
|
|
53
|
+
* Orthogonal to `maxValidationRetries` (§7), which re-prompts on
|
|
54
|
+
* invalid CONTENT. Unset = a single transport attempt.
|
|
55
|
+
*/
|
|
56
|
+
retry?: RetryOptions;
|
|
57
|
+
/**
|
|
58
|
+
* @non-paper observability (additive, opt-in). Timestamps come from
|
|
59
|
+
* `clock.now()` instead of `Date.now()`. Unset = paper-exact `Date.now()`
|
|
60
|
+
* behavior; even an explicit `SystemClock` changes nothing observable.
|
|
61
|
+
*/
|
|
62
|
+
clock?: Clock;
|
|
63
|
+
/**
|
|
64
|
+
* @non-paper observability (additive, opt-in). Receives
|
|
65
|
+
* `step:start`/`step:end`/`step:error` (and `budget:exceeded` from
|
|
66
|
+
* `run()`). Unset = nothing is emitted, zero overhead.
|
|
67
|
+
*/
|
|
68
|
+
events?: RuntimeEventEmitter;
|
|
69
|
+
/**
|
|
70
|
+
* @non-paper observability (additive, opt-in). `info` per completed
|
|
71
|
+
* step, `warn` on invalidated/budget-exceeded steps, `error` on
|
|
72
|
+
* transport throws. Unset = silent.
|
|
73
|
+
*/
|
|
74
|
+
logger?: Logger;
|
|
75
|
+
/**
|
|
76
|
+
* @non-paper char budget (additive, opt-in). Default cap for `run()`;
|
|
77
|
+
* a per-call `RunOptions` value wins when both are set. Alias pair:
|
|
78
|
+
* `tokenBudget`/`charsBudget` are interchangeable (chars, per §4.3 —
|
|
79
|
+
* the "token" name is kept for caller convenience only).
|
|
80
|
+
*/
|
|
81
|
+
tokenBudget?: CharsBudget;
|
|
82
|
+
/** @non-paper alias of `tokenBudget` (additive, opt-in). */
|
|
83
|
+
charsBudget?: CharsBudget;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* @non-paper char budget (chars, per paper §4.3 — never tokenizer output).
|
|
87
|
+
* Trips when cumulative prompt+response chars EXCEED `maxChars` (`>`).
|
|
88
|
+
* Unset `maxChars` = no cap.
|
|
89
|
+
*/
|
|
90
|
+
export interface CharsBudget {
|
|
91
|
+
maxChars?: number;
|
|
92
|
+
}
|
|
93
|
+
/** @non-paper alias of {@link CharsBudget} (naming convenience only). */
|
|
94
|
+
export type TokenBudget = CharsBudget;
|
|
95
|
+
/**
|
|
96
|
+
* @non-paper per-`run()` budget overrides. Precedence (first defined wins):
|
|
97
|
+
* `maxChars` → `tokenBudget` → `charsBudget` → constructor
|
|
98
|
+
* `tokenBudget` → constructor `charsBudget`. All optional, all additive.
|
|
99
|
+
*/
|
|
100
|
+
export interface RunOptions {
|
|
101
|
+
tokenBudget?: CharsBudget;
|
|
102
|
+
charsBudget?: CharsBudget;
|
|
103
|
+
maxChars?: number;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* @non-paper rejection reason when `run()` trips a char budget. Carries
|
|
107
|
+
* the committed prefix (`partialResults`, WITHOUT the exceeding step —
|
|
108
|
+
* the trip rolls its state and tracker entry back) so callers can resume
|
|
109
|
+
* or report deterministically.
|
|
110
|
+
*/
|
|
111
|
+
export declare class BudgetExceededError extends Error {
|
|
112
|
+
readonly maxChars: number;
|
|
113
|
+
readonly totalChars: number;
|
|
114
|
+
readonly partialResults: StepResult[];
|
|
115
|
+
constructor(maxChars: number, totalChars: number, partialResults: StepResult[]);
|
|
116
|
+
}
|
|
117
|
+
/** Result of a single Algorithm 1 step. */
|
|
118
|
+
export interface StepResult {
|
|
119
|
+
step: number;
|
|
120
|
+
observation: Observation;
|
|
121
|
+
reasoning: string;
|
|
122
|
+
statePatch: StatePatch;
|
|
123
|
+
action: string;
|
|
124
|
+
newObservation: Observation;
|
|
125
|
+
newState: SkillState;
|
|
126
|
+
validationAttempts: number;
|
|
127
|
+
invalidated: boolean;
|
|
128
|
+
/**
|
|
129
|
+
* @non-paper measured sizes for this step (raw string CHARS, §4.3):
|
|
130
|
+
* `promptChars` is |At| (base prompt only — retry feedback is transport,
|
|
131
|
+
* never part of At), `responseChars` accumulates every attempt's raw
|
|
132
|
+
* response. Additive: paper consumers ignore them.
|
|
133
|
+
*/
|
|
134
|
+
promptChars: number;
|
|
135
|
+
responseChars: number;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Algorithm 1 runtime (paper §3.2) with the §7 rollback-retry cycle.
|
|
139
|
+
*
|
|
140
|
+
* Each step: format the paper-exact prompt At = (P, Σt, Ot), call the LLM,
|
|
141
|
+
* parse the response (Rt, ΔΣt, at), validate ΔΣt against the schema, merge
|
|
142
|
+
* it (Σt+1 = Σt ⊕ ΔΣt), and execute the action. The model never receives
|
|
143
|
+
* previous observations, actions, or reasoning (§3). Failed attempts
|
|
144
|
+
* re-prompt with corrective feedback; after exhausting retries the step
|
|
145
|
+
* fails deterministically — the state is left untouched and the action
|
|
146
|
+
* becomes `__invalid_patch__`.
|
|
147
|
+
*
|
|
148
|
+
* Reasoning is returned but never stored, and merged states are fresh
|
|
149
|
+
* objects, so a rejected patch can never leak into state (rollback is free).
|
|
150
|
+
*/
|
|
151
|
+
export declare class SkillStateRuntime {
|
|
152
|
+
private readonly spec;
|
|
153
|
+
private readonly llm;
|
|
154
|
+
private readonly execute;
|
|
155
|
+
private readonly tracker;
|
|
156
|
+
private readonly maxValidationRetries;
|
|
157
|
+
private readonly timeoutMs;
|
|
158
|
+
private readonly signal;
|
|
159
|
+
private readonly retry;
|
|
160
|
+
private readonly clock;
|
|
161
|
+
private readonly events;
|
|
162
|
+
private readonly logger;
|
|
163
|
+
private readonly tokenBudget;
|
|
164
|
+
private readonly charsBudget;
|
|
165
|
+
private readonly transformer;
|
|
166
|
+
private currentState;
|
|
167
|
+
private stepCounter;
|
|
168
|
+
constructor(options: RuntimeOptions);
|
|
169
|
+
/** Current state Σt (read-only copy). */
|
|
170
|
+
get state(): SkillState;
|
|
171
|
+
/**
|
|
172
|
+
* @non-paper resilience wrapper (additive, opt-in).
|
|
173
|
+
*
|
|
174
|
+
* Paper path: no `timeoutMs`/`signal`/`retry` options — `fn` is invoked
|
|
175
|
+
* directly, byte-for-byte the paper behavior (no timer, no extra attempt).
|
|
176
|
+
* Resilience path: the call is threaded through `withTimeout` (deadline
|
|
177
|
+
* and/or abort) and, when `retry` is set, transient throws are re-issued
|
|
178
|
+
* via `withRetry`. Validation-retry (§7) semantics above this are
|
|
179
|
+
* unchanged: a TRANSPORT throw still propagates out of `step` exactly as
|
|
180
|
+
* a throwing `llm`/`execute` did before.
|
|
181
|
+
*/
|
|
182
|
+
private invokeResilient;
|
|
183
|
+
/**
|
|
184
|
+
* @non-paper LLM dispatch (Wave 4 DX, additive).
|
|
185
|
+
*
|
|
186
|
+
* Paper path: `llm` is a legacy `LLMFn` — called verbatim with the
|
|
187
|
+
* prompt, exactly as before. Provider path: `llm.call(prompt, opts?)`
|
|
188
|
+
* is used instead, forwarding the runtime `signal?` so aborts reach
|
|
189
|
+
* the provider; both paths stay inside `invokeResilient`, so the
|
|
190
|
+
* `timeoutMs`/`signal`/`retry` transport semantics are identical.
|
|
191
|
+
*/
|
|
192
|
+
private invokeLLM;
|
|
193
|
+
/**
|
|
194
|
+
* @non-paper timestamp source: injected `clock` or `Date.now()`.
|
|
195
|
+
* The default path is exactly the paper core's `Date.now()`.
|
|
196
|
+
*/
|
|
197
|
+
private now;
|
|
198
|
+
/** @non-paper: first defined budget cap wins (run-level beats ctor-level). */
|
|
199
|
+
private resolveMaxChars;
|
|
200
|
+
/** @non-paper: tracker total when tracked, local tally otherwise. */
|
|
201
|
+
private currentTotalChars;
|
|
202
|
+
/**
|
|
203
|
+
* Execute one Algorithm 1 step for observation Ot.
|
|
204
|
+
*
|
|
205
|
+
* Paper-exact Algorithm 1 + §7 rollback-retry; the @non-paper
|
|
206
|
+
* `events`/`logger` options only OBSERVE (emitted payloads never feed
|
|
207
|
+
* back into prompts, merges, or validation).
|
|
208
|
+
*/
|
|
209
|
+
step(observation: Observation): Promise<StepResult>;
|
|
210
|
+
/**
|
|
211
|
+
* Run steps until isDone(result) is true or maxSteps is reached. Each
|
|
212
|
+
* step's input observation is the previous step's newObservation.
|
|
213
|
+
*
|
|
214
|
+
* @non-paper `runOpts`/constructor budgets cap cumulative CHARS
|
|
215
|
+
* (prompt+response, §4.3). On trip the exceeding step is rolled back —
|
|
216
|
+
* runtime state restored, its tracker entry truncated — and
|
|
217
|
+
* `BudgetExceededError` (with the committed prefix) is thrown alongside
|
|
218
|
+
* a `budget:exceeded` event. No budget = the paper-exact loop above,
|
|
219
|
+
* untouched.
|
|
220
|
+
*/
|
|
221
|
+
run(first: Observation, isDone: (r: StepResult) => boolean, maxSteps?: number, runOpts?: RunOptions): Promise<StepResult[]>;
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
|