@rheonic/sdk 0.1.0-beta.11 → 0.1.0-beta.13

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.
@@ -14,18 +14,21 @@ export interface EventResponse {
14
14
  latency_ms?: number;
15
15
  total_tokens?: number;
16
16
  error_type?: string;
17
+ error_message?: string;
17
18
  }
18
19
  export interface EventPayload {
19
20
  ts: string;
20
21
  provider: string;
21
- model: string | null;
22
+ requested_model: string | null;
23
+ resolved_model: string | null;
22
24
  environment: string;
23
25
  request: EventRequest;
24
26
  response: EventResponse;
25
27
  }
26
28
  export interface BuildEventInput {
27
29
  provider: string;
28
- model?: string | null;
30
+ requested_model?: string | null;
31
+ resolved_model?: string | null;
29
32
  environment?: string;
30
33
  ts?: string;
31
34
  request?: EventRequest;
@@ -2,7 +2,8 @@ export function buildEvent(input) {
2
2
  return {
3
3
  ts: input.ts ?? new Date().toISOString(),
4
4
  provider: input.provider,
5
- model: input.model ?? null,
5
+ requested_model: input.requested_model ?? null,
6
+ resolved_model: input.resolved_model ?? null,
6
7
  environment: input.environment ?? "dev",
7
8
  request: input.request ?? {},
8
9
  response: input.response ?? {},
@@ -2,7 +2,7 @@ export type ProtectDecision = "allow" | "clamp" | "block";
2
2
  export type ProtectFailMode = "open" | "closed";
3
3
  export interface ProtectContext {
4
4
  provider: string;
5
- model?: string | null;
5
+ requested_model?: string | null;
6
6
  feature?: string;
7
7
  max_output_tokens?: number;
8
8
  input_tokens_estimate?: number;
@@ -90,7 +90,7 @@ export class ProtectEngine {
90
90
  status_code: response.status,
91
91
  latency_ms: Date.now() - startedAt,
92
92
  });
93
- void this.reportDecisionUnavailable(context.provider, typeof context.model === "string" ? context.model : undefined, requestId, traceId);
93
+ void this.reportDecisionUnavailable(context.provider, typeof context.requested_model === "string" ? context.requested_model : undefined, requestId, traceId);
94
94
  return this.fallbackEvaluation(traceId, requestId);
95
95
  }
96
96
  const parsed = (await response.json());
@@ -140,7 +140,7 @@ export class ProtectEngine {
140
140
  latency_ms: Date.now() - startedAt,
141
141
  timeout_ms: timeoutMs,
142
142
  });
143
- void this.reportDecisionTimeout(context.provider, typeof context.model === "string" ? context.model : undefined, requestId, traceId);
143
+ void this.reportDecisionTimeout(context.provider, typeof context.requested_model === "string" ? context.requested_model : undefined, requestId, traceId);
144
144
  }
145
145
  else {
146
146
  this.debugLog?.("Protect preflight failed", {
@@ -148,7 +148,7 @@ export class ProtectEngine {
148
148
  latency_ms: Date.now() - startedAt,
149
149
  error_type: extractErrorType(error),
150
150
  });
151
- void this.reportDecisionUnavailable(context.provider, typeof context.model === "string" ? context.model : undefined, requestId, traceId);
151
+ void this.reportDecisionUnavailable(context.provider, typeof context.requested_model === "string" ? context.requested_model : undefined, requestId, traceId);
152
152
  }
153
153
  return this.fallbackEvaluation(traceId, requestId);
154
154
  }
@@ -189,7 +189,7 @@ export class ProtectEngine {
189
189
  // Best effort only; keep local defaults if bootstrap fails.
190
190
  }
191
191
  }
192
- async reportDecisionTimeout(provider, model, requestId, traceId) {
192
+ async reportDecisionTimeout(provider, requestedModel, requestId, traceId) {
193
193
  try {
194
194
  await requestJson(`${this.baseUrl}/api/v1/protect/decision-timeout`, {
195
195
  method: "POST",
@@ -200,14 +200,19 @@ export class ProtectEngine {
200
200
  "X-Span-ID": generateSpanId(),
201
201
  "X-Rheonic-Protect-Request-Id": requestId,
202
202
  },
203
- body: JSON.stringify({ environment: this.environment, provider, model, request_id: requestId }),
203
+ body: JSON.stringify({
204
+ environment: this.environment,
205
+ provider,
206
+ requested_model: requestedModel,
207
+ request_id: requestId,
208
+ }),
204
209
  });
205
210
  }
206
211
  catch {
207
212
  // Swallow timeout reporting errors; protect evaluation must never throw here.
208
213
  }
209
214
  }
210
- async reportDecisionUnavailable(provider, model, requestId, traceId) {
215
+ async reportDecisionUnavailable(provider, requestedModel, requestId, traceId) {
211
216
  try {
212
217
  await requestJson(`${this.baseUrl}/api/v1/protect/decision-unavailable`, {
213
218
  method: "POST",
@@ -218,7 +223,12 @@ export class ProtectEngine {
218
223
  "X-Span-ID": generateSpanId(),
219
224
  "X-Rheonic-Protect-Request-Id": requestId,
220
225
  },
221
- body: JSON.stringify({ environment: this.environment, provider, model, request_id: requestId }),
226
+ body: JSON.stringify({
227
+ environment: this.environment,
228
+ provider,
229
+ requested_model: requestedModel,
230
+ request_id: requestId,
231
+ }),
222
232
  });
223
233
  }
224
234
  catch {
@@ -36,7 +36,7 @@ export function instrumentAnthropic(anthropicClient, options) {
36
36
  });
37
37
  const protectPayload = {
38
38
  provider: "anthropic",
39
- model: requestedModel,
39
+ requested_model: requestedModel,
40
40
  environment: options.environment ?? options.client.environment,
41
41
  feature: options.feature,
42
42
  max_output_tokens: extractMaxOutputTokens(args),
@@ -56,7 +56,8 @@ export function instrumentAnthropic(anthropicClient, options) {
56
56
  const response = await originalCreate(...callArgs);
57
57
  await options.client.captureEventAndFlush(buildEvent({
58
58
  provider: "anthropic",
59
- model: extractResponseModel(response) ?? requestedModel,
59
+ requested_model: requestedModel,
60
+ resolved_model: extractResponseModel(response),
60
61
  environment: options.environment ?? options.client.environment,
61
62
  request: {
62
63
  endpoint: options.endpoint,
@@ -77,7 +78,8 @@ export function instrumentAnthropic(anthropicClient, options) {
77
78
  catch (error) {
78
79
  await options.client.captureEventAndFlush(buildEvent({
79
80
  provider: "anthropic",
80
- model: requestedModel,
81
+ requested_model: requestedModel,
82
+ resolved_model: null,
81
83
  environment: options.environment ?? options.client.environment,
82
84
  request: {
83
85
  endpoint: options.endpoint,
@@ -90,6 +92,7 @@ export function instrumentAnthropic(anthropicClient, options) {
90
92
  response: {
91
93
  latency_ms: Date.now() - startedAt,
92
94
  error_type: extractErrorType(error),
95
+ error_message: extractErrorMessage(error),
93
96
  http_status: extractHttpStatus(error),
94
97
  },
95
98
  }));
@@ -145,6 +148,15 @@ function extractErrorType(error) {
145
148
  }
146
149
  return "unknown";
147
150
  }
151
+ function extractErrorMessage(error) {
152
+ if (error && typeof error === "object" && "message" in error) {
153
+ const message = error.message;
154
+ if (typeof message === "string" && message.length > 0) {
155
+ return message;
156
+ }
157
+ }
158
+ return undefined;
159
+ }
148
160
  function extractHttpStatus(error) {
149
161
  if (!error || typeof error !== "object") {
150
162
  return undefined;
@@ -36,7 +36,7 @@ export function instrumentGoogle(googleModel, options) {
36
36
  });
37
37
  const protectPayload = {
38
38
  provider: "google",
39
- model: requestedModel,
39
+ requested_model: requestedModel,
40
40
  environment: options.environment ?? options.client.environment,
41
41
  feature: options.feature,
42
42
  max_output_tokens: extractMaxOutputTokens(args),
@@ -56,7 +56,8 @@ export function instrumentGoogle(googleModel, options) {
56
56
  const response = await originalGenerate(...callArgs);
57
57
  await options.client.captureEventAndFlush(buildEvent({
58
58
  provider: "google",
59
- model: requestedModel,
59
+ requested_model: requestedModel,
60
+ resolved_model: extractResponseModel(response),
60
61
  environment: options.environment ?? options.client.environment,
61
62
  request: {
62
63
  endpoint: options.endpoint,
@@ -77,7 +78,8 @@ export function instrumentGoogle(googleModel, options) {
77
78
  catch (error) {
78
79
  await options.client.captureEventAndFlush(buildEvent({
79
80
  provider: "google",
80
- model: requestedModel,
81
+ requested_model: requestedModel,
82
+ resolved_model: null,
81
83
  environment: options.environment ?? options.client.environment,
82
84
  request: {
83
85
  endpoint: options.endpoint,
@@ -90,6 +92,7 @@ export function instrumentGoogle(googleModel, options) {
90
92
  response: {
91
93
  latency_ms: Date.now() - startedAt,
92
94
  error_type: extractErrorType(error),
95
+ error_message: extractErrorMessage(error),
93
96
  http_status: extractHttpStatus(error),
94
97
  },
95
98
  }));
@@ -193,6 +196,23 @@ function extractTotalTokens(response) {
193
196
  const total = prompt + candidates;
194
197
  return total > 0 ? total : undefined;
195
198
  }
199
+ function extractResponseModel(response) {
200
+ if (!response || typeof response !== "object") {
201
+ return null;
202
+ }
203
+ const topLevelModel = response.model;
204
+ if (typeof topLevelModel === "string" && topLevelModel.trim()) {
205
+ return topLevelModel;
206
+ }
207
+ const nestedResponse = response.response;
208
+ if (typeof nestedResponse?.modelVersion === "string" && nestedResponse.modelVersion.trim()) {
209
+ return nestedResponse.modelVersion;
210
+ }
211
+ if (typeof nestedResponse?.model === "string" && nestedResponse.model.trim()) {
212
+ return nestedResponse.model;
213
+ }
214
+ return null;
215
+ }
196
216
  function extractErrorType(error) {
197
217
  if (error && typeof error === "object" && "name" in error) {
198
218
  const name = error.name;
@@ -202,6 +222,15 @@ function extractErrorType(error) {
202
222
  }
203
223
  return "unknown";
204
224
  }
225
+ function extractErrorMessage(error) {
226
+ if (error && typeof error === "object" && "message" in error) {
227
+ const message = error.message;
228
+ if (typeof message === "string" && message.length > 0) {
229
+ return message;
230
+ }
231
+ }
232
+ return undefined;
233
+ }
205
234
  function extractHttpStatus(error) {
206
235
  if (!error || typeof error !== "object") {
207
236
  return undefined;
@@ -35,7 +35,7 @@ export function instrumentOpenAI(openaiClient, options) {
35
35
  });
36
36
  const protectPayload = {
37
37
  provider: "openai",
38
- model,
38
+ requested_model: model,
39
39
  environment: options.environment ?? options.client.environment,
40
40
  feature: options.feature,
41
41
  max_output_tokens: extractMaxOutputTokens(args),
@@ -57,7 +57,8 @@ export function instrumentOpenAI(openaiClient, options) {
57
57
  const response = await originalCreate(...callArgs);
58
58
  await options.client.captureEventAndFlush(buildEvent({
59
59
  provider: "openai",
60
- model: extractResponseModel(response) ?? model,
60
+ requested_model: model,
61
+ resolved_model: extractResponseModel(response),
61
62
  environment: options.environment ?? options.client.environment,
62
63
  request: {
63
64
  endpoint: options.endpoint,
@@ -77,7 +78,8 @@ export function instrumentOpenAI(openaiClient, options) {
77
78
  catch (error) {
78
79
  await options.client.captureEventAndFlush(buildEvent({
79
80
  provider: "openai",
80
- model,
81
+ requested_model: model,
82
+ resolved_model: null,
81
83
  environment: options.environment ?? options.client.environment,
82
84
  request: {
83
85
  endpoint: options.endpoint,
@@ -89,6 +91,7 @@ export function instrumentOpenAI(openaiClient, options) {
89
91
  response: {
90
92
  latency_ms: Date.now() - startedAt,
91
93
  error_type: extractErrorType(error),
94
+ error_message: extractErrorMessage(error),
92
95
  http_status: extractHttpStatus(error),
93
96
  },
94
97
  }));
@@ -194,6 +197,15 @@ function extractErrorType(error) {
194
197
  }
195
198
  return "unknown";
196
199
  }
200
+ function extractErrorMessage(error) {
201
+ if (error && typeof error === "object" && "message" in error) {
202
+ const message = error.message;
203
+ if (typeof message === "string" && message.length > 0) {
204
+ return message;
205
+ }
206
+ }
207
+ return undefined;
208
+ }
197
209
  function extractHttpStatus(error) {
198
210
  if (!error || typeof error !== "object") {
199
211
  return undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rheonic/sdk",
3
- "version": "0.1.0-beta.11",
3
+ "version": "0.1.0-beta.13",
4
4
  "description": "Node.js SDK for Rheonic observability and protect preflight enforcement.",
5
5
  "author": "Rheonic <founder@rheonic.dev>",
6
6
  "license": "MIT",