retrace-sdk 0.13.2 → 0.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.
- package/README.md +5 -5
- package/dist/config.d.ts +4 -0
- package/dist/config.js +5 -3
- package/dist/telemetry.d.ts +1 -0
- package/dist/telemetry.js +51 -0
- package/dist/trace.js +10 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ Requires Node.js 20+. ESM-only package.
|
|
|
15
15
|
```typescript
|
|
16
16
|
import { configure, trace } from "retrace-sdk";
|
|
17
17
|
|
|
18
|
-
configure({ apiKey: "
|
|
18
|
+
configure({ apiKey: "rt_..." }); // Get your key at retraceai.tech/settings
|
|
19
19
|
|
|
20
20
|
const myAgent = trace(async (prompt: string) => {
|
|
21
21
|
const response = await openai.chat.completions.create({
|
|
@@ -44,7 +44,7 @@ No extra setup needed. Install the provider SDK alongside `retrace-sdk`.
|
|
|
44
44
|
import { configure } from "retrace-sdk";
|
|
45
45
|
|
|
46
46
|
configure({
|
|
47
|
-
apiKey: "
|
|
47
|
+
apiKey: "rt_...", // or RETRACE_API_KEY env var
|
|
48
48
|
baseUrl: "https://api.retraceai.tech",
|
|
49
49
|
projectId: "...", // or RETRACE_PROJECT_ID env var
|
|
50
50
|
});
|
|
@@ -74,7 +74,7 @@ Mark a function as resumable to enable full cascade replay from the dashboard:
|
|
|
74
74
|
```typescript
|
|
75
75
|
import { configure, trace } from "retrace-sdk";
|
|
76
76
|
|
|
77
|
-
configure({ apiKey: "
|
|
77
|
+
configure({ apiKey: "rt_..." });
|
|
78
78
|
|
|
79
79
|
const myAgent = trace(async (prompt: string) => {
|
|
80
80
|
const plan = await planner(prompt);
|
|
@@ -101,7 +101,7 @@ Hard ceilings that stop a runaway agent before the next call. Local limits are e
|
|
|
101
101
|
import { configure, RetraceEnforcementError } from "retrace-sdk";
|
|
102
102
|
|
|
103
103
|
configure({
|
|
104
|
-
apiKey: "
|
|
104
|
+
apiKey: "rt_...",
|
|
105
105
|
maxStepsPerRun: 50,
|
|
106
106
|
maxUsdPerRun: 2.0,
|
|
107
107
|
serverEnforcement: true, // optional: also consult server policies
|
|
@@ -141,7 +141,7 @@ writeGoldenCassette("golden.json", { recorder });
|
|
|
141
141
|
## Sampling
|
|
142
142
|
|
|
143
143
|
```typescript
|
|
144
|
-
configure({ apiKey: "
|
|
144
|
+
configure({ apiKey: "rt_...", sampleRate: 0.1 }); // Record 10% of traces
|
|
145
145
|
```
|
|
146
146
|
|
|
147
147
|
## Changelog
|
package/dist/config.d.ts
CHANGED
|
@@ -32,6 +32,10 @@ export interface Config {
|
|
|
32
32
|
* the fail-closed timeout verdict. 0 = trip immediately. (The auto path is synchronous, so the
|
|
33
33
|
* poll runs in the background and a denial/timeout trips the NEXT span.) */
|
|
34
34
|
enforcementHoldWaitSeconds: number;
|
|
35
|
+
/** Environment indicator sent with every trace as `metadata.environment`. Set to "sandbox" to
|
|
36
|
+
* record into the auto-expiring sandbox data-namespace instead of production (the server also
|
|
37
|
+
* accepts an `X-Retrace-Environment` header). Env: RETRACE_ENVIRONMENT. */
|
|
38
|
+
environment: string | undefined;
|
|
35
39
|
}
|
|
36
40
|
export declare function configure(opts: Partial<Config>): Config;
|
|
37
41
|
export declare function requireApiKey(): string;
|
package/dist/config.js
CHANGED
|
@@ -13,11 +13,12 @@ const config = {
|
|
|
13
13
|
maxUsdPerRun: process.env.RETRACE_MAX_USD_PER_RUN ? parseFloat(process.env.RETRACE_MAX_USD_PER_RUN) : undefined,
|
|
14
14
|
serverEnforcement: ["true", "1", "yes"].includes((process.env.RETRACE_SERVER_ENFORCEMENT || "").toLowerCase()),
|
|
15
15
|
enforcementHoldWaitSeconds: process.env.RETRACE_ENFORCEMENT_HOLD_WAIT_SECONDS ? parseInt(process.env.RETRACE_ENFORCEMENT_HOLD_WAIT_SECONDS, 10) : 0,
|
|
16
|
+
environment: process.env.RETRACE_ENVIRONMENT || undefined,
|
|
16
17
|
};
|
|
17
18
|
config.wsUrl = config.baseUrl.replace("https://", "wss://").replace("http://", "ws://");
|
|
18
19
|
export function configure(opts) {
|
|
19
|
-
if (opts.apiKey && !opts.apiKey.startsWith("rt_live_")) {
|
|
20
|
-
throw new Error("Invalid Retrace API key. Keys must start with '
|
|
20
|
+
if (opts.apiKey && (!opts.apiKey.startsWith("rt_") || opts.apiKey.startsWith("rt_live_") || opts.apiKey.startsWith("rt_test_"))) {
|
|
21
|
+
throw new Error("Invalid Retrace API key. Keys must start with 'rt_'. Get yours at https://retraceai.tech/settings");
|
|
21
22
|
}
|
|
22
23
|
Object.assign(config, opts);
|
|
23
24
|
if (opts.baseUrl && !opts.wsUrl) {
|
|
@@ -30,11 +31,12 @@ export function configure(opts) {
|
|
|
30
31
|
if (config.enabled) {
|
|
31
32
|
void import("./interceptors/install.js").then((m) => m.ensureInterceptorsInstalled()).catch(() => { });
|
|
32
33
|
}
|
|
34
|
+
void import("./telemetry.js").then((m) => m.track("configure")).catch(() => { });
|
|
33
35
|
return config;
|
|
34
36
|
}
|
|
35
37
|
export function requireApiKey() {
|
|
36
38
|
if (!config.apiKey) {
|
|
37
|
-
throw new Error("Retrace API key required. Call configure({ apiKey: '
|
|
39
|
+
throw new Error("Retrace API key required. Call configure({ apiKey: 'rt_...' }) or set RETRACE_API_KEY. Get yours at https://retraceai.tech/settings");
|
|
38
40
|
}
|
|
39
41
|
return config.apiKey;
|
|
40
42
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function track(event: string, fields?: Record<string, string | number | boolean>): void;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anonymous, opt-out diagnostic telemetry.
|
|
3
|
+
*
|
|
4
|
+
* Sends NO user code, API keys, prompts, responses, or personal information — only the SDK version,
|
|
5
|
+
* the runtime/OS family, an anonymous per-process id, and event/error *categories* — to the Retrace
|
|
6
|
+
* API's internal log ingest (forwarded to the centralized logging platform under
|
|
7
|
+
* service="sdk-typescript"). Fire-and-forget; never blocks, never throws.
|
|
8
|
+
*
|
|
9
|
+
* Disable entirely with RETRACE_TELEMETRY=0 (also accepts false/no/off).
|
|
10
|
+
*/
|
|
11
|
+
import os from "node:os";
|
|
12
|
+
import { getConfig } from "./config.js";
|
|
13
|
+
// Per-process random id — anonymous, not linked to any account, user, or machine identity.
|
|
14
|
+
const ANON_ID = Math.random().toString(16).slice(2, 18);
|
|
15
|
+
const DISABLED = new Set(["0", "false", "no", "off"]);
|
|
16
|
+
// Keep in sync with package.json version.
|
|
17
|
+
const SDK_VERSION = "0.14.0";
|
|
18
|
+
function enabled() {
|
|
19
|
+
return !DISABLED.has((process.env.RETRACE_TELEMETRY ?? "1").trim().toLowerCase());
|
|
20
|
+
}
|
|
21
|
+
export function track(event, fields = {}) {
|
|
22
|
+
if (!enabled())
|
|
23
|
+
return;
|
|
24
|
+
try {
|
|
25
|
+
const base = (getConfig().baseUrl || "https://api.retraceai.tech").replace(/\/$/, "");
|
|
26
|
+
const body = JSON.stringify({
|
|
27
|
+
service: "sdk-typescript",
|
|
28
|
+
events: [
|
|
29
|
+
{
|
|
30
|
+
level: "info",
|
|
31
|
+
message: `sdk-typescript ${event}`,
|
|
32
|
+
event,
|
|
33
|
+
sdk_version: SDK_VERSION,
|
|
34
|
+
node: process.version,
|
|
35
|
+
os: os.platform(),
|
|
36
|
+
anon_id: ANON_ID,
|
|
37
|
+
...fields,
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
});
|
|
41
|
+
// Fire-and-forget; never block or throw.
|
|
42
|
+
void fetch(`${base}/api/v1/internal/logs`, {
|
|
43
|
+
method: "POST",
|
|
44
|
+
headers: { "Content-Type": "application/json" },
|
|
45
|
+
body,
|
|
46
|
+
}).catch(() => { });
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
/* telemetry must never affect the user's program */
|
|
50
|
+
}
|
|
51
|
+
}
|
package/dist/trace.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { genId, nowIso, utcNow } from "./utils.js";
|
|
2
|
+
import { getConfig } from "./config.js";
|
|
2
3
|
export var SpanType;
|
|
3
4
|
(function (SpanType) {
|
|
4
5
|
SpanType["LLM_CALL"] = "llm_call";
|
|
@@ -106,5 +107,13 @@ export class TraceBuilder {
|
|
|
106
107
|
setProjectId(id) { this.data.project_id = id; }
|
|
107
108
|
setSessionId(id) { this.data.session_id = id; }
|
|
108
109
|
setMetadata(m) { this.data.metadata = m; }
|
|
109
|
-
toDict() {
|
|
110
|
+
toDict() {
|
|
111
|
+
// Tag the run's environment (e.g. "sandbox") from config as metadata.environment so the server
|
|
112
|
+
// routes it to the matching data-namespace. Explicit per-trace metadata.environment always wins.
|
|
113
|
+
const env = getConfig().environment;
|
|
114
|
+
if (env && !(this.data.metadata && "environment" in this.data.metadata)) {
|
|
115
|
+
this.data.metadata = { ...(this.data.metadata || {}), environment: env };
|
|
116
|
+
}
|
|
117
|
+
return this.data;
|
|
118
|
+
}
|
|
110
119
|
}
|