retrace-sdk 0.11.6 → 0.11.7

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/config.d.ts CHANGED
@@ -11,6 +11,11 @@ export interface Config {
11
11
  * request/response only (recommended for short-lived scripts and serverless — it never
12
12
  * holds an open socket and always surfaces upload errors); "ws" forces WebSocket. */
13
13
  transport: "auto" | "ws" | "http";
14
+ /** Replay safety. When a deterministic replay hits a cassette MISS (no recorded entry for a
15
+ * call), the SDK otherwise falls through to a REAL provider call (live cost + non-determinism).
16
+ * With strictReplay=true the SDK throws instead (fail-closed). Default false: warn + fall through.
17
+ * Env: RETRACE_STRICT_REPLAY. */
18
+ strictReplay: boolean;
14
19
  /** Called with a STRUCTURED signal when the server signals credits_exhausted | rate_limited |
15
20
  * halt | error. Branch on `signal.code`; use `signal.retryable`/`signal.fatal` to decide
16
21
  * behavior. Defaults to a throttled console warning so signals are never silently dropped. */
package/dist/config.js CHANGED
@@ -7,6 +7,7 @@ const config = {
7
7
  sampleRate: parseFloat(process.env.RETRACE_SAMPLE_RATE || "1"),
8
8
  sampleSeed: process.env.RETRACE_SAMPLE_SEED || undefined,
9
9
  transport: (["auto", "ws", "http"].includes(process.env.RETRACE_TRANSPORT || "") ? process.env.RETRACE_TRANSPORT : "auto"),
10
+ strictReplay: ["true", "1"].includes((process.env.RETRACE_STRICT_REPLAY || "").toLowerCase()),
10
11
  };
11
12
  config.wsUrl = config.baseUrl.replace("https://", "wss://").replace("http://", "ws://");
12
13
  export function configure(opts) {
package/dist/replay.js CHANGED
@@ -10,6 +10,7 @@
10
10
  * This enables one-click reproduction of any production trace locally.
11
11
  */
12
12
  import { getResumable } from "./resume.js";
13
+ import { getConfig } from "./config.js";
13
14
  import { AsyncLocalStorage } from "async_hooks";
14
15
  const cassetteStorage = new AsyncLocalStorage();
15
16
  /**
@@ -42,8 +43,25 @@ export function consumeCassetteEntry(name, spanType) {
42
43
  return ctx.cassette[i];
43
44
  }
44
45
  }
46
+ // Cassette MISS during an active replay: there is NO recorded entry for this call. Returning null
47
+ // makes the interceptor fall through to a REAL provider call (live cost + non-determinism). Never
48
+ // do that silently — warn (throttled), and fail closed if strictReplay is set.
49
+ reportCassetteMiss(name, spanType);
45
50
  return null;
46
51
  }
52
+ const _missWarnedAt = new Map();
53
+ /** Throttled-warn (or throw, under strictReplay) on a cassette miss during replay. */
54
+ function reportCassetteMiss(name, spanType) {
55
+ if (getConfig().strictReplay) {
56
+ throw new Error(`[retrace] Replay cassette MISS for ${spanType} "${name}": no recorded entry, and strictReplay is enabled — refusing to fall through to a real provider call. The recorded trace likely diverged (different call order/count).`);
57
+ }
58
+ const key = `${spanType}:${name}`;
59
+ const now = Date.now();
60
+ if (now - (_missWarnedAt.get(key) ?? 0) > 5000) {
61
+ _missWarnedAt.set(key, now);
62
+ console.warn(`[retrace] Replay cassette MISS for ${spanType} "${name}" — no recorded entry; falling through to a REAL provider call (live cost + non-determinism). Set strictReplay:true (or RETRACE_STRICT_REPLAY=true) to fail closed instead.`);
63
+ }
64
+ }
47
65
  /**
48
66
  * Handle a replay command from the server.
49
67
  * Returns a Promise that resolves when replay completes or rejects on failure.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "retrace-sdk",
3
- "version": "0.11.6",
3
+ "version": "0.11.7",
4
4
  "description": "The execution replay engine for AI agents. Record, replay, fork, and share agent executions.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",