@rheonic/sdk 0.1.0-beta.2 → 0.1.0-beta.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/README.md +82 -100
- package/dist/client.js +7 -1
- package/dist/config.d.ts +2 -2
- package/dist/config.js +2 -2
- package/dist/logger.js +6 -1
- package/dist/protectEngine.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,150 +1,132 @@
|
|
|
1
1
|
# Rheonic Node SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Rheonic captures provider telemetry and applies protect preflight decisions before provider calls.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
|
-
Beta prerelease install:
|
|
8
|
-
|
|
9
7
|
```bash
|
|
10
8
|
npm install @rheonic/sdk
|
|
11
9
|
```
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
- Node.js 18+
|
|
15
|
-
- One of the supported provider SDKs: `openai`, `@anthropic-ai/sdk`, or `@google/generative-ai`
|
|
16
|
-
|
|
17
|
-
Beta note:
|
|
18
|
-
- Public beta releases may add guardrail fields and provider wrappers before `1.0.0`.
|
|
19
|
-
|
|
20
|
-
## Configuration
|
|
21
|
-
|
|
22
|
-
- Required: `ingestKey`
|
|
23
|
-
- Optional for local development: `baseUrl` (defaults to `RHEONIC_BASE_URL`, else `http://localhost:8000`)
|
|
24
|
-
- Optional: `environment` (default `dev`)
|
|
25
|
-
|
|
26
|
-
For hosted beta, staging, or production deployments, set `RHEONIC_BASE_URL` or pass `baseUrl` explicitly. The localhost default is intended only for local development.
|
|
27
|
-
|
|
28
|
-
Provider/model validation: SDK wrappers fail fast with `RHEONICValidationError` when provider is missing/unsupported or model is missing/empty. Supported providers are `openai`, `anthropic`, and `google`. Model naming is not pattern-validated so future vendor naming changes remain compatible.
|
|
29
|
-
|
|
30
|
-
## Integration Recommendation
|
|
11
|
+
## Required environment variables
|
|
31
12
|
|
|
32
|
-
|
|
13
|
+
```bash
|
|
14
|
+
RHEONIC_INGEST_KEY=<your_project_ingest_key>
|
|
15
|
+
RHEONIC_BASE_URL=<value_shown_in_dashboard>
|
|
16
|
+
```
|
|
33
17
|
|
|
34
|
-
##
|
|
18
|
+
## Instrument provider calls
|
|
35
19
|
|
|
36
|
-
|
|
20
|
+
Wrap your provider SDK once.
|
|
37
21
|
|
|
38
|
-
|
|
22
|
+
Telemetry is captured automatically after each provider call.
|
|
39
23
|
|
|
40
|
-
|
|
41
|
-
{
|
|
42
|
-
"timestamp": "2026-03-18T09:20:15.145102+00:00",
|
|
43
|
-
"level": "info",
|
|
44
|
-
"service": "sdk-node",
|
|
45
|
-
"env": "staging",
|
|
46
|
-
"trace_id": "f4ac8b6b-6f8d-4f4c-b54f-3c2c2f76a27b",
|
|
47
|
-
"span_id": "9f12db3a1d204f8f",
|
|
48
|
-
"event": "sdk_client_initialized",
|
|
49
|
-
"message": "SDK client initialized",
|
|
50
|
-
"metadata": {}
|
|
51
|
-
}
|
|
52
|
-
```
|
|
24
|
+
Enforcement follows Project mode in the dashboard (`Observe` / `Protect`).
|
|
53
25
|
|
|
54
|
-
|
|
55
|
-
- backend requests automatically include `X-Trace-ID`,
|
|
56
|
-
- SDK logs share that `trace_id` so you can correlate SDK, backend, worker, and webhook activity,
|
|
57
|
-
- sensitive fields such as API keys and tokens are redacted.
|
|
58
|
-
|
|
59
|
-
## Integration Path 1: Manual Capture (generic)
|
|
26
|
+
OpenAI:
|
|
60
27
|
|
|
61
28
|
```ts
|
|
62
|
-
import
|
|
29
|
+
import OpenAI from "openai";
|
|
30
|
+
import { createClient, instrumentOpenAI, RHEONICBlockedError } from "@rheonic/sdk";
|
|
63
31
|
|
|
64
|
-
const
|
|
32
|
+
const rheonic = createClient({
|
|
65
33
|
baseUrl: process.env.RHEONIC_BASE_URL!,
|
|
66
34
|
ingestKey: process.env.RHEONIC_INGEST_KEY!,
|
|
67
35
|
});
|
|
68
36
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
model: "gpt-4o-mini",
|
|
73
|
-
request: { endpoint: "/chat", input_tokens: 12 },
|
|
74
|
-
response: { total_tokens: 32, latency_ms: 140, http_status: 200 },
|
|
75
|
-
}),
|
|
76
|
-
);
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
Initialize `client` once during app startup, then reuse that same instance for manual capture and provider instrumentation.
|
|
80
|
-
|
|
81
|
-
Minimal protect preflight usage:
|
|
82
|
-
|
|
83
|
-
```ts
|
|
84
|
-
const decision = await client.protect({
|
|
85
|
-
provider: "openai",
|
|
86
|
-
model: "gpt-4o-mini",
|
|
37
|
+
const openai = instrumentOpenAI(new OpenAI({ apiKey: process.env.OPENAI_API_KEY! }), {
|
|
38
|
+
client: rheonic,
|
|
39
|
+
endpoint: "/chat/completions",
|
|
87
40
|
feature: "assistant",
|
|
88
|
-
inputTokensEstimate: 32,
|
|
89
|
-
maxOutputTokens: 256,
|
|
90
41
|
});
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
await openai.chat.completions.create({
|
|
45
|
+
model: "gpt-4o-mini",
|
|
46
|
+
messages: [{ role: "user", content: "hello" }],
|
|
47
|
+
max_tokens: 256,
|
|
48
|
+
});
|
|
49
|
+
} catch (error) {
|
|
50
|
+
if (error instanceof RHEONICBlockedError) {
|
|
51
|
+
console.log("Blocked by protect preflight");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
91
54
|
```
|
|
92
55
|
|
|
93
|
-
|
|
56
|
+
Anthropic:
|
|
94
57
|
|
|
95
58
|
```ts
|
|
96
|
-
import
|
|
97
|
-
import { createClient,
|
|
59
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
60
|
+
import { createClient, RHEONICBlockedError } from "@rheonic/sdk";
|
|
98
61
|
|
|
99
|
-
const
|
|
62
|
+
const rheonic = createClient({
|
|
100
63
|
baseUrl: process.env.RHEONIC_BASE_URL!,
|
|
101
64
|
ingestKey: process.env.RHEONIC_INGEST_KEY!,
|
|
102
65
|
});
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
66
|
+
|
|
67
|
+
const anthropic = rheonic.instrumentAnthropic(new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY! }));
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
await anthropic.messages.create({
|
|
71
|
+
model: "claude-3-5-sonnet-latest",
|
|
72
|
+
max_tokens: 256,
|
|
73
|
+
messages: [{ role: "user", content: "hello" }],
|
|
74
|
+
});
|
|
75
|
+
} catch (error) {
|
|
76
|
+
if (error instanceof RHEONICBlockedError) {
|
|
77
|
+
console.log("Blocked by protect preflight");
|
|
78
|
+
}
|
|
79
|
+
}
|
|
108
80
|
```
|
|
109
81
|
|
|
110
|
-
|
|
82
|
+
Google:
|
|
111
83
|
|
|
112
84
|
```ts
|
|
113
|
-
import Anthropic from "@anthropic-ai/sdk";
|
|
114
85
|
import { GoogleGenerativeAI } from "@google/generative-ai";
|
|
115
|
-
import { createClient } from "rheonic
|
|
86
|
+
import { createClient, RHEONICBlockedError } from "@rheonic/sdk";
|
|
116
87
|
|
|
117
|
-
const
|
|
88
|
+
const rheonic = createClient({
|
|
118
89
|
baseUrl: process.env.RHEONIC_BASE_URL!,
|
|
119
90
|
ingestKey: process.env.RHEONIC_INGEST_KEY!,
|
|
120
91
|
});
|
|
121
92
|
|
|
122
|
-
const anthropic = client.instrumentAnthropic(new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY }));
|
|
123
|
-
await anthropic.messages.create({
|
|
124
|
-
model: "claude-3-5-sonnet-latest",
|
|
125
|
-
max_tokens: 256,
|
|
126
|
-
messages: [{ role: "user", content: "Hello Claude" }],
|
|
127
|
-
});
|
|
128
|
-
|
|
129
93
|
const genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY!);
|
|
130
|
-
const
|
|
131
|
-
|
|
94
|
+
const model = rheonic.instrumentGoogle(genAI.getGenerativeModel({ model: "gemini-1.5-pro" }));
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
await model.generateContent("hello");
|
|
98
|
+
} catch (error) {
|
|
99
|
+
if (error instanceof RHEONICBlockedError) {
|
|
100
|
+
console.log("Blocked by protect preflight");
|
|
101
|
+
}
|
|
102
|
+
}
|
|
132
103
|
```
|
|
133
104
|
|
|
134
|
-
|
|
135
|
-
- SDK instrumentation calls `POST /api/v1/protect/decision` then `POST /api/v1/events`.
|
|
136
|
-
- Project mode in dashboard controls decision behavior:
|
|
137
|
-
- Observe: allow only.
|
|
138
|
-
- Protect: allow/warn/block with cooldown.
|
|
105
|
+
Keep one long-lived SDK client per app process. Initialize it during app startup and reuse it for all capture and instrumentation calls so Rheonic can avoid repeated protect cold-start latency.
|
|
139
106
|
|
|
140
|
-
##
|
|
107
|
+
## Optional: custom event capture
|
|
141
108
|
|
|
142
|
-
|
|
109
|
+
Use this only if you can't instrument a provider SDK or need custom events.
|
|
143
110
|
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
111
|
+
```ts
|
|
112
|
+
import { createClient, buildEvent } from "@rheonic/sdk";
|
|
113
|
+
|
|
114
|
+
const client = createClient({
|
|
115
|
+
baseUrl: process.env.RHEONIC_BASE_URL!,
|
|
116
|
+
ingestKey: process.env.RHEONIC_INGEST_KEY!,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
await client.captureEvent(
|
|
120
|
+
buildEvent({
|
|
121
|
+
provider: "openai",
|
|
122
|
+
model: "gpt-4o-mini",
|
|
123
|
+
request: { endpoint: "/chat/completions", feature: "assistant" },
|
|
124
|
+
response: { total_tokens: 64, latency_ms: 120, http_status: 200 },
|
|
125
|
+
}),
|
|
126
|
+
);
|
|
148
127
|
```
|
|
149
128
|
|
|
150
|
-
|
|
129
|
+
## Reference
|
|
130
|
+
|
|
131
|
+
Full quickstart:
|
|
132
|
+
- `https://beta.rheonic.dev/quickstart`
|
package/dist/client.js
CHANGED
|
@@ -30,7 +30,13 @@ export class Client {
|
|
|
30
30
|
constructor(config) {
|
|
31
31
|
this.baseUrl = config.baseUrl ?? process.env.RHEONIC_BASE_URL ?? sdkNodeConfig.defaultBaseUrl;
|
|
32
32
|
this.ingestKey = config.ingestKey;
|
|
33
|
-
this.environment =
|
|
33
|
+
this.environment =
|
|
34
|
+
config.environment ??
|
|
35
|
+
process.env.NODE_ENV ??
|
|
36
|
+
process.env.APP_ENV ??
|
|
37
|
+
process.env.ENVIRONMENT ??
|
|
38
|
+
process.env.ENV ??
|
|
39
|
+
sdkNodeConfig.defaultEnvironment;
|
|
34
40
|
this.flushIntervalMs = config.flushIntervalMs ?? sdkNodeConfig.defaultFlushIntervalMs;
|
|
35
41
|
this.maxQueueSize = config.maxQueueSize ?? sdkNodeConfig.defaultMaxQueueSize;
|
|
36
42
|
this.overflowPolicy = config.overflowPolicy ?? "drop_oldest";
|
package/dist/config.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export declare const sdkNodeConfig: {
|
|
2
2
|
readonly defaultBaseUrl: "http://localhost:8000";
|
|
3
|
-
readonly defaultEnvironment: "
|
|
3
|
+
readonly defaultEnvironment: "unknown";
|
|
4
4
|
readonly defaultFlushIntervalMs: 1000;
|
|
5
5
|
readonly defaultMaxQueueSize: 1000;
|
|
6
6
|
readonly defaultFlushTimeoutMs: 500;
|
|
7
7
|
readonly defaultRequestTimeoutMs: 1000;
|
|
8
8
|
readonly defaultProtectFailMode: "open";
|
|
9
|
-
readonly internalProtectDecisionTimeoutMs:
|
|
9
|
+
readonly internalProtectDecisionTimeoutMs: 160;
|
|
10
10
|
readonly retryDelayMinMs: 200;
|
|
11
11
|
readonly retryDelayMaxMs: 400;
|
|
12
12
|
readonly defaultTokenizerEncoding: "cl100k_base";
|
package/dist/config.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export const sdkNodeConfig = {
|
|
2
2
|
defaultBaseUrl: "http://localhost:8000",
|
|
3
|
-
defaultEnvironment: "
|
|
3
|
+
defaultEnvironment: "unknown",
|
|
4
4
|
defaultFlushIntervalMs: 1000,
|
|
5
5
|
defaultMaxQueueSize: 1000,
|
|
6
6
|
defaultFlushTimeoutMs: 500,
|
|
7
7
|
defaultRequestTimeoutMs: 1000,
|
|
8
8
|
defaultProtectFailMode: "open",
|
|
9
|
-
internalProtectDecisionTimeoutMs:
|
|
9
|
+
internalProtectDecisionTimeoutMs: 160,
|
|
10
10
|
retryDelayMinMs: 200,
|
|
11
11
|
retryDelayMaxMs: 400,
|
|
12
12
|
defaultTokenizerEncoding: "cl100k_base",
|
package/dist/logger.js
CHANGED
|
@@ -23,7 +23,12 @@ export function emitLog(params) {
|
|
|
23
23
|
timestamp: new Date().toISOString(),
|
|
24
24
|
level: params.level,
|
|
25
25
|
service: SERVICE_NAME,
|
|
26
|
-
env: (params.environment ??
|
|
26
|
+
env: (params.environment ??
|
|
27
|
+
process.env.NODE_ENV ??
|
|
28
|
+
process.env.APP_ENV ??
|
|
29
|
+
process.env.ENVIRONMENT ??
|
|
30
|
+
process.env.ENV ??
|
|
31
|
+
"unknown").toLowerCase(),
|
|
27
32
|
trace_id: params.traceId ?? getTraceId(),
|
|
28
33
|
span_id: params.spanId ?? getSpanId(),
|
|
29
34
|
event: sanitizeEvent(params.event),
|
package/dist/protectEngine.d.ts
CHANGED
package/package.json
CHANGED