retrace-sdk 0.11.5 → 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 +5 -0
- package/dist/config.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/replay.js +18 -0
- package/package.json +1 -1
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/index.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export { isReplaying, consumeCassetteEntry, handleReplay } from "./replay.js";
|
|
|
16
16
|
export type { CassetteEntry, ReplayCommand } from "./replay.js";
|
|
17
17
|
export { setTraceContext, clearTraceContext, getTraceparent, injectTraceparent, parseTraceparent, withTraceContext } from "./traceparent.js";
|
|
18
18
|
export { markGolden } from "./golden.js";
|
|
19
|
+
export { setTruncationLimits } from "./utils.js";
|
|
19
20
|
export { createLangChainHandler } from "./adapters/langchain.js";
|
|
20
21
|
export { retraceOnStepFinish, recordVercelStep } from "./adapters/vercel-ai.js";
|
|
21
22
|
export type { AISDKStep } from "./adapters/vercel-ai.js";
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@ export { registerResumable, handleResume } from "./resume.js";
|
|
|
12
12
|
export { isReplaying, consumeCassetteEntry, handleReplay } from "./replay.js";
|
|
13
13
|
export { setTraceContext, clearTraceContext, getTraceparent, injectTraceparent, parseTraceparent, withTraceContext } from "./traceparent.js";
|
|
14
14
|
export { markGolden } from "./golden.js";
|
|
15
|
+
export { setTruncationLimits } from "./utils.js";
|
|
15
16
|
// Framework adapters (5B) — drop-in instrumentation for LangChain/LangGraph + Vercel AI SDK.
|
|
16
17
|
export { createLangChainHandler } from "./adapters/langchain.js";
|
|
17
18
|
export { retraceOnStepFinish, recordVercelStep } from "./adapters/vercel-ai.js";
|
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.
|