primeorbit-sdk 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) [year] [fullname]
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,201 @@
1
+ # πŸ“˜ PrimeOrbit JavaScript Client β€” Complete Getting Started Guide
2
+
3
+ # πŸš€ Overview
4
+
5
+ We can track conversations, model responses, user feedback, and custom analytics
6
+ through a simple event-based API.
7
+
8
+ # πŸ“¦ Installation
9
+
10
+ Install the SDK using:
11
+
12
+ ```bash
13
+ npm install primeorbit-sdk
14
+ ```
15
+
16
+ πŸ”§ Import & Initialize
17
+
18
+ ```javascript
19
+ import { PrimeOrbitClient } from 'primeorbit-sdk';
20
+
21
+ const po = new PrimeOrbitClient(
22
+ 'np_live_abc123', // Your API Key
23
+ 'http://localhost:8000', // Endpoint
24
+ );
25
+ ```
26
+
27
+ Note: You will receive your API key and the endpoint when you onboard with
28
+ PrimeOrbit. Each API key is unique to your organization and should be kept
29
+ confidential. Use this key to authenticate requests to the PrimeOrbit backend.
30
+
31
+ You can either pass the api_key and endpoint parameter directly when creating
32
+ the client, or set PRIMEORBIT_API_KEY and PRIMEORBIT_ENDPOINT in a .env file β€”
33
+ the client will automatically use it if the parameter is not provided.
34
+
35
+ 🧩 Set Base Properties (Required Once)
36
+
37
+ Call this once when your app loads or when the user session starts:
38
+
39
+ ```javacript
40
+ po.add_properties({
41
+ agentId: "agent_456",
42
+ conversationId: "conv_789",
43
+ userId: "user_123",
44
+ sessionId: "sess_001",
45
+ platform: "web"
46
+ });
47
+ ```
48
+
49
+ These will be automatically included in every event.
50
+
51
+ ## πŸ“ Supported Event Types
52
+
53
+ **Message Events:**
54
+
55
+ - `user_message`
56
+ - `agent_response`
57
+
58
+ **Feedback Events:**
59
+
60
+ - `user_feedback`
61
+ - `star_rating`
62
+ - `thumbs_feedback`
63
+
64
+ ## 🧱 Required Fields for Every Event
65
+
66
+ Regardless of event type, the following fields must always be present:
67
+
68
+ | Field | Type | Description |
69
+ | ---------------- | ------ | --------------------------------------- |
70
+ | `conversationId` | string | Unique ID representing the conversation |
71
+ | `userId` | string | ID of the end user |
72
+ | `content` | string | Message text or feedback content |
73
+
74
+ These four fields are mandatory for all events.
75
+
76
+ Tip: To avoid repeating conversationId, agentId, and userId in every event, it’s
77
+ better to configure them once using po.add_properties(). You can then pass only
78
+ content and any event-specific fields in each record_raw_event() call. This
79
+ keeps your code clean and consistent.
80
+
81
+ ## 🧩 Optional Supported Fields
82
+
83
+ In addition to the required fields, you may send any of the following optional
84
+ attributes:
85
+
86
+ | Field | Type | Description |
87
+ | ---------------------- | ------------ | ------------------------------------------------ |
88
+ | `eventId` | string | Optional unique event identifier |
89
+ | `agentId` | string | ID of the agent/app/model that handled the event |
90
+ | `sessionId` | string | Session identifier |
91
+ | `inputMode` | string | e.g., `"text"`, `"voice"`, `"button"` |
92
+ | `experimentId` | string | A/B test or experiment tracking |
93
+ | `productId` | string | Product or feature identifier |
94
+ | `errorMessage` | string | Error info for debugging |
95
+ | `country` | string | User’s country |
96
+ | `device` | string | Device type (`mobile`, `desktop`) |
97
+ | `platform` | string | Platform (`web`, `ios`, `android`) |
98
+ | `timestamp` | datetime ISO | Auto-generated if omitted |
99
+ | `model` | string | Model name for `agent_response` events |
100
+ | `additionalProperties` | dict | Automatically populated metadata bucket |
101
+
102
+ > Any unsupported fields you send will automatically be placed inside
103
+ > `additionalProperties`.
104
+
105
+ additionalProperties: { ... } No data is lost β€” PrimeOrbit captures everything.
106
+
107
+ ## πŸ“€ Recording Events
108
+
109
+ The primary method for sending events:
110
+
111
+ ```javascript
112
+ po.record_raw_event(event_type, propertiesObject);
113
+ ```
114
+
115
+ πŸ“š Event Examples
116
+
117
+ 1️⃣ User Message Event
118
+
119
+ ```javascript
120
+ po.record_raw_event('user_message', {
121
+ content: 'Hello, I need help!',
122
+ });
123
+ ```
124
+
125
+ 2️⃣ Agent Response Event
126
+
127
+ ```javascript
128
+ po.record_raw_event('agent_response', {
129
+ content: 'Sure! What can I help you with?',
130
+ model: 'gpt-5.1',
131
+ });
132
+ ```
133
+
134
+ 3️⃣ User Feedback (Free Text)
135
+
136
+ ```javascript
137
+ po.record_raw_event('user_feedback', {
138
+ content: "The answer wasn't very helpful.",
139
+ });
140
+ ```
141
+
142
+ 4️⃣ Star Rating Event
143
+
144
+ ```javascript
145
+ po.record_raw_event('star_rating', {
146
+ content: '4',
147
+ });
148
+ ```
149
+
150
+ 5️⃣ Thumbs Feedback Event
151
+
152
+ ```javascript
153
+ po.record_raw_event('thumbs_feedback', {
154
+ content: 'thumbs_down',
155
+ });
156
+ ```
157
+
158
+ 6️⃣ Full example:
159
+
160
+ ```javascript
161
+ import { PrimeOrbitClient } from 'primeorbit-sdk';
162
+
163
+ // Initialize the client (endpoint from parameter or .env)
164
+ const po = new PrimeOrbitClient('YOUR_API_KEY');
165
+
166
+ // Add conversation metadata including agent_id
167
+ po.add_properties({
168
+ userId: 'user_123',
169
+ agentId: 'agent_001',
170
+ conversationId: 'conv_456',
171
+ sessionId: 'session_789',
172
+ });
173
+
174
+ // Dummy function simulating sending a message to your bot/system
175
+ async function sendMessageToBot(message) {
176
+ // Simulate processing delay
177
+ await new Promise((resolve) => setTimeout(resolve, 500));
178
+ return { message: `Bot reply to: "${message}"` };
179
+ }
180
+
181
+ async function runConversation() {
182
+ const userMessage = 'Hello, I need help!';
183
+
184
+ // Record user message *before* sending to bot
185
+ po.record_raw_event('user_message', {
186
+ content: userMessage,
187
+ });
188
+
189
+ // Send the message to the bot
190
+ const botResponse = await sendMessageToBot(userMessage);
191
+
192
+ // Record bot response as agent_response
193
+ po.record_raw_event('agent_response', {
194
+ content: botResponse.message,
195
+ });
196
+
197
+ console.log('Bot response recorded:', botResponse.message);
198
+ }
199
+
200
+ runConversation();
201
+ ```
@@ -0,0 +1,320 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ PrimeOrbitClient: () => PrimeOrbitClient,
34
+ getNovaPhaseApiUrl: () => getNovaPhaseApiUrl,
35
+ record_star_rating: () => record_star_rating,
36
+ record_thumbs_feedback: () => record_thumbs_feedback,
37
+ setNovaPhaseApiUrl: () => setNovaPhaseApiUrl,
38
+ wrapToRecordLatency: () => wrapToRecordLatency
39
+ });
40
+ module.exports = __toCommonJS(index_exports);
41
+
42
+ // src/api_utils.ts
43
+ async function recordData(endpoint, payload, headers = { "Content-Type": "application/json" }) {
44
+ const res = await fetch(endpoint, {
45
+ method: "POST",
46
+ headers,
47
+ body: JSON.stringify(payload)
48
+ });
49
+ const text = await res.text();
50
+ let responseBody;
51
+ try {
52
+ responseBody = text ? JSON.parse(text) : null;
53
+ } catch {
54
+ responseBody = text;
55
+ }
56
+ if (!res.ok) {
57
+ throw new Error(`HTTP ${res.status} ${res.statusText}: ${text}`);
58
+ }
59
+ return responseBody;
60
+ }
61
+
62
+ // src/routes.ts
63
+ var routes = {
64
+ latencies: "/system-metrics/latencies",
65
+ "star-ratings": "/user-metrics/star-ratings",
66
+ "thumbs-feedbacks": "/user-metrics/thumbs-feedbacks",
67
+ "raw-events": "/user-metrics/raw-events"
68
+ };
69
+
70
+ // src/system_metrics/measure_latency.ts
71
+ function recordLatency(startTime, agentId, actionId, actionFailed) {
72
+ const endTime = performance.now();
73
+ const latency = Math.floor(endTime - startTime);
74
+ recordData(routes["latencies"], {
75
+ agent_id: agentId,
76
+ latency,
77
+ action_id: actionId,
78
+ action_failed: actionFailed
79
+ });
80
+ }
81
+ function wrapToRecordLatency(fn, agentId, actionId = "") {
82
+ return function(...args) {
83
+ const start = performance.now();
84
+ let failed = true;
85
+ const agentActionId = actionId || fn.name;
86
+ try {
87
+ const result = fn.apply(this, args);
88
+ if (result instanceof Promise) {
89
+ return result.then((res) => {
90
+ failed = false;
91
+ recordLatency(start, agentId, agentActionId, failed);
92
+ return res;
93
+ }).catch((err) => {
94
+ recordLatency(start, agentId, agentActionId, failed);
95
+ throw err;
96
+ });
97
+ } else {
98
+ failed = false;
99
+ recordLatency(start, agentId, agentActionId, failed);
100
+ return result;
101
+ }
102
+ } catch (err) {
103
+ recordLatency(start, agentId, agentActionId, failed);
104
+ throw err;
105
+ }
106
+ };
107
+ }
108
+
109
+ // src/config.ts
110
+ var baseApiUrl;
111
+ function setNovaPhaseApiUrl(url) {
112
+ baseApiUrl = url;
113
+ }
114
+ function getNovaPhaseApiUrl() {
115
+ if (!baseApiUrl) {
116
+ throw new Error(
117
+ `NovaPhase API URL is not set. Please call 'setNovaPhaseApiUrl(<url>)' before using the SDK.`
118
+ );
119
+ }
120
+ return baseApiUrl;
121
+ }
122
+
123
+ // src/user_metrics/record_star_rating.ts
124
+ async function record_star_rating(agentId, rating, taskName, userId = "") {
125
+ try {
126
+ const payload = {
127
+ agent_id: agentId,
128
+ rating,
129
+ task_name: taskName
130
+ };
131
+ if (userId) {
132
+ payload.user_id = userId;
133
+ }
134
+ await recordData(routes["star-ratings"], payload);
135
+ } catch (err) {
136
+ console.error(
137
+ `[NovaPhase SDK] recordData failed: ${err.message}`
138
+ );
139
+ }
140
+ }
141
+
142
+ // src/user_metrics/record_thumbs_feedback.ts
143
+ async function record_thumbs_feedback(agentId, isThumbsUp, taskName, userId = "") {
144
+ try {
145
+ const payload = {
146
+ agent_id: agentId,
147
+ is_thumbs_up: isThumbsUp,
148
+ task_name: taskName
149
+ };
150
+ if (userId) {
151
+ payload.user_id = userId;
152
+ }
153
+ await recordData(routes["thumbs-feedbacks"], payload);
154
+ } catch (err) {
155
+ console.error(
156
+ `[NovaPhase SDK] Failed to record thumbs feedback: ${err.message}`
157
+ );
158
+ }
159
+ }
160
+
161
+ // src/user_metrics/record_user_event.ts
162
+ var dotenv = __toESM(require("dotenv"), 1);
163
+ dotenv.config();
164
+ var PrimeOrbitClient = class {
165
+ apiKey;
166
+ baseUrl;
167
+ baseProperties = {};
168
+ verbose = false;
169
+ /**
170
+ * @param {string} apiKey - Your PrimeOrbit API key
171
+ * @param {string} [endpoint] - endpoint URL
172
+ */
173
+ constructor(apiKey, endpoint) {
174
+ if (apiKey) {
175
+ this.apiKey = apiKey;
176
+ } else if (process.env.PRIMEORBIT_API_KEY) {
177
+ this.apiKey = process.env.PRIMEORBIT_API_KEY;
178
+ } else {
179
+ throw new Error(
180
+ "API key not provided. Set the 'apiKey' parameter or the 'PRIMEORBIT_API_KEY' environment variable."
181
+ );
182
+ }
183
+ if (endpoint) {
184
+ this.baseUrl = endpoint;
185
+ } else if (process.env.PRIMEORBIT_ENDPOINT) {
186
+ this.baseUrl = process.env.PRIMEORBIT_ENDPOINT;
187
+ } else {
188
+ this.baseUrl = "https://sdk-dev.primeorbit.ai";
189
+ }
190
+ this.baseProperties = {};
191
+ }
192
+ add_properties(props) {
193
+ this.baseProperties = {
194
+ ...this.baseProperties,
195
+ ...props
196
+ };
197
+ }
198
+ _headers() {
199
+ return {
200
+ Authorization: `Bearer ${this.apiKey}`,
201
+ "Content-Type": "application/json"
202
+ };
203
+ }
204
+ /**
205
+ * Records any agent interaction event such as user_question, agent_response, or user_feedback.
206
+ *
207
+ * @param eventType - Type of event. Can be:
208
+ * - 'user_question' – when the user asks a question
209
+ * - 'agent_response' – when the agent replies
210
+ * - 'user_feedback' – when the user gives feedback
211
+ *
212
+ * @param params - Object containing event details:
213
+ * - conversationId: string – Unique conversation identifier
214
+ * - agentId: string – Agent ID
215
+ * - userId: string – User ID
216
+ * - productId?: string – Optional product ID
217
+ * - content: string – Text content of the event (user question, agent reply, or feedback)
218
+ * - sessionId?: string – Optional session ID
219
+ * - messageId?: string – Optional message ID (for tracking within conversation)
220
+ * - inputMode?: string – Optional input mode (e.g., 'text', 'voice')
221
+ * - device?: string – Optional device name or model (e.g., 'iPhone 13')
222
+ * - country?: string – Optional country of the user (ISO country code, e.g., 'US')
223
+ * - platform?: string – Optional platform or OS (e.g., 'iOS', 'Android', 'Web')
224
+ * - language?: string – Optional language of the user (e.g., 'en-US')
225
+ * - Any additional properties will be captured in additional_properties
226
+ */
227
+ async record_raw_event(eventType, params) {
228
+ const finalParams = {
229
+ ...this.baseProperties,
230
+ ...params
231
+ };
232
+ try {
233
+ const {
234
+ conversationId,
235
+ messageId,
236
+ agentId,
237
+ userId,
238
+ appId,
239
+ content,
240
+ sessionId,
241
+ eventId,
242
+ inputMode,
243
+ device,
244
+ country,
245
+ platform,
246
+ experimentId,
247
+ ...extraProps
248
+ } = finalParams;
249
+ const requiredFields = ["conversationId", "userId", "content"];
250
+ const missingRequired = requiredFields.filter(
251
+ (field) => !(field in finalParams) || finalParams[field] === void 0
252
+ );
253
+ if (missingRequired.length > 0) {
254
+ throw new Error(
255
+ `Missing required fields: ${missingRequired.join(", ")}`
256
+ );
257
+ }
258
+ const optionalFields = [
259
+ "agentId",
260
+ "sessionId",
261
+ "eventId",
262
+ "messageId",
263
+ "experimentId",
264
+ "inputMode",
265
+ "device",
266
+ "country",
267
+ "platform",
268
+ "appId",
269
+ "model"
270
+ ];
271
+ const missingOptionals = optionalFields.filter(
272
+ (field) => !(field in finalParams) || finalParams[field] === void 0
273
+ );
274
+ if (missingOptionals.length > 0) {
275
+ if (this.verbose) {
276
+ console.warn(
277
+ `[PrimeOrbit Analytics Warning] Missing optional fields: ${missingOptionals.join(", ")}. Analytics may be less accurate or incomplete.`
278
+ );
279
+ }
280
+ }
281
+ const payload = {
282
+ event_type: eventType,
283
+ conversation_id: conversationId,
284
+ session_id: sessionId,
285
+ user_id: userId,
286
+ agent_id: agentId,
287
+ message_id: messageId,
288
+ event_id: eventId,
289
+ app_id: appId,
290
+ content,
291
+ input_mode: inputMode,
292
+ device,
293
+ country,
294
+ platform,
295
+ experiment_id: experimentId,
296
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
297
+ additional_properties: Object.keys(extraProps).length > 0 ? extraProps : void 0
298
+ };
299
+ console.log("[PrimeOrbit] Recording event:", payload);
300
+ await recordData(
301
+ `${this.baseUrl}${routes["raw-events"]}`,
302
+ payload,
303
+ this._headers()
304
+ );
305
+ } catch (err) {
306
+ console.error(
307
+ `[PrimeOrbit Error] recording_event failed}: ${err}`
308
+ );
309
+ }
310
+ }
311
+ };
312
+ // Annotate the CommonJS export names for ESM import in node:
313
+ 0 && (module.exports = {
314
+ PrimeOrbitClient,
315
+ getNovaPhaseApiUrl,
316
+ record_star_rating,
317
+ record_thumbs_feedback,
318
+ setNovaPhaseApiUrl,
319
+ wrapToRecordLatency
320
+ });
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Wraps a synchronous or asynchronous function and logs its execution latency.
3
+ *
4
+ * @template T - A function type with any parameters and return type.
5
+ * @param {T} fn - The function to be wrapped.
6
+ * @param {string} agentId - Identifier for the agent.
7
+ * @param {string} actionId - Identifier for the action id. If not provided, defaults to the name of the function `fn`.
8
+ * @returns {(...args: Parameters<T>) => ReturnType<T>} A wrapped function that logs latency and returns the same result as `fn`.
9
+ */
10
+ declare function wrapToRecordLatency<T extends (...args: unknown[]) => unknown>(fn: T, agentId: string, actionId?: string): (...args: Parameters<T>) => ReturnType<T>;
11
+
12
+ declare function setNovaPhaseApiUrl(url: string): void;
13
+ declare function getNovaPhaseApiUrl(): string;
14
+
15
+ /**
16
+ * Records a star rating for an agent after task completion.
17
+ *
18
+ * @param agentId - Unique identifier for the agent
19
+ * @param rating - Star rating given (e.g. 1–5)
20
+ * @param taskName - Name of completed task
21
+ * @param userId - Optional ID of the user giving the rating
22
+ */
23
+ declare function record_star_rating(agentId: string, rating: number, taskName: string, userId?: string): Promise<void>;
24
+
25
+ /**
26
+ * Sends thumbs-up/down feedback to the backend.
27
+ *
28
+ * @param agentId - ID of the agent being rated
29
+ * @param isThumbsUp - true if thumbs up, false if thumbs down
30
+ * @param taskName - summary of the task
31
+ * @param userId - ID of the user who provided the feedback; defaults to ''.
32
+ */
33
+ declare function record_thumbs_feedback(agentId: string, isThumbsUp: boolean, taskName: string, userId?: string): Promise<void>;
34
+
35
+ declare class PrimeOrbitClient {
36
+ private apiKey;
37
+ private baseUrl;
38
+ private baseProperties;
39
+ private verbose;
40
+ /**
41
+ * @param {string} apiKey - Your PrimeOrbit API key
42
+ * @param {string} [endpoint] - endpoint URL
43
+ */
44
+ constructor(apiKey?: string, endpoint?: string);
45
+ add_properties(props: Record<string, unknown>): void;
46
+ _headers(): {
47
+ Authorization: string;
48
+ 'Content-Type': string;
49
+ };
50
+ /**
51
+ * Records any agent interaction event such as user_question, agent_response, or user_feedback.
52
+ *
53
+ * @param eventType - Type of event. Can be:
54
+ * - 'user_question' – when the user asks a question
55
+ * - 'agent_response' – when the agent replies
56
+ * - 'user_feedback' – when the user gives feedback
57
+ *
58
+ * @param params - Object containing event details:
59
+ * - conversationId: string – Unique conversation identifier
60
+ * - agentId: string – Agent ID
61
+ * - userId: string – User ID
62
+ * - productId?: string – Optional product ID
63
+ * - content: string – Text content of the event (user question, agent reply, or feedback)
64
+ * - sessionId?: string – Optional session ID
65
+ * - messageId?: string – Optional message ID (for tracking within conversation)
66
+ * - inputMode?: string – Optional input mode (e.g., 'text', 'voice')
67
+ * - device?: string – Optional device name or model (e.g., 'iPhone 13')
68
+ * - country?: string – Optional country of the user (ISO country code, e.g., 'US')
69
+ * - platform?: string – Optional platform or OS (e.g., 'iOS', 'Android', 'Web')
70
+ * - language?: string – Optional language of the user (e.g., 'en-US')
71
+ * - Any additional properties will be captured in additional_properties
72
+ */
73
+ record_raw_event(eventType: 'user_question' | 'agent_response' | 'user_feedback', params: Record<string, unknown>): Promise<void>;
74
+ }
75
+
76
+ export { PrimeOrbitClient, getNovaPhaseApiUrl, record_star_rating, record_thumbs_feedback, setNovaPhaseApiUrl, wrapToRecordLatency };
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Wraps a synchronous or asynchronous function and logs its execution latency.
3
+ *
4
+ * @template T - A function type with any parameters and return type.
5
+ * @param {T} fn - The function to be wrapped.
6
+ * @param {string} agentId - Identifier for the agent.
7
+ * @param {string} actionId - Identifier for the action id. If not provided, defaults to the name of the function `fn`.
8
+ * @returns {(...args: Parameters<T>) => ReturnType<T>} A wrapped function that logs latency and returns the same result as `fn`.
9
+ */
10
+ declare function wrapToRecordLatency<T extends (...args: unknown[]) => unknown>(fn: T, agentId: string, actionId?: string): (...args: Parameters<T>) => ReturnType<T>;
11
+
12
+ declare function setNovaPhaseApiUrl(url: string): void;
13
+ declare function getNovaPhaseApiUrl(): string;
14
+
15
+ /**
16
+ * Records a star rating for an agent after task completion.
17
+ *
18
+ * @param agentId - Unique identifier for the agent
19
+ * @param rating - Star rating given (e.g. 1–5)
20
+ * @param taskName - Name of completed task
21
+ * @param userId - Optional ID of the user giving the rating
22
+ */
23
+ declare function record_star_rating(agentId: string, rating: number, taskName: string, userId?: string): Promise<void>;
24
+
25
+ /**
26
+ * Sends thumbs-up/down feedback to the backend.
27
+ *
28
+ * @param agentId - ID of the agent being rated
29
+ * @param isThumbsUp - true if thumbs up, false if thumbs down
30
+ * @param taskName - summary of the task
31
+ * @param userId - ID of the user who provided the feedback; defaults to ''.
32
+ */
33
+ declare function record_thumbs_feedback(agentId: string, isThumbsUp: boolean, taskName: string, userId?: string): Promise<void>;
34
+
35
+ declare class PrimeOrbitClient {
36
+ private apiKey;
37
+ private baseUrl;
38
+ private baseProperties;
39
+ private verbose;
40
+ /**
41
+ * @param {string} apiKey - Your PrimeOrbit API key
42
+ * @param {string} [endpoint] - endpoint URL
43
+ */
44
+ constructor(apiKey?: string, endpoint?: string);
45
+ add_properties(props: Record<string, unknown>): void;
46
+ _headers(): {
47
+ Authorization: string;
48
+ 'Content-Type': string;
49
+ };
50
+ /**
51
+ * Records any agent interaction event such as user_question, agent_response, or user_feedback.
52
+ *
53
+ * @param eventType - Type of event. Can be:
54
+ * - 'user_question' – when the user asks a question
55
+ * - 'agent_response' – when the agent replies
56
+ * - 'user_feedback' – when the user gives feedback
57
+ *
58
+ * @param params - Object containing event details:
59
+ * - conversationId: string – Unique conversation identifier
60
+ * - agentId: string – Agent ID
61
+ * - userId: string – User ID
62
+ * - productId?: string – Optional product ID
63
+ * - content: string – Text content of the event (user question, agent reply, or feedback)
64
+ * - sessionId?: string – Optional session ID
65
+ * - messageId?: string – Optional message ID (for tracking within conversation)
66
+ * - inputMode?: string – Optional input mode (e.g., 'text', 'voice')
67
+ * - device?: string – Optional device name or model (e.g., 'iPhone 13')
68
+ * - country?: string – Optional country of the user (ISO country code, e.g., 'US')
69
+ * - platform?: string – Optional platform or OS (e.g., 'iOS', 'Android', 'Web')
70
+ * - language?: string – Optional language of the user (e.g., 'en-US')
71
+ * - Any additional properties will be captured in additional_properties
72
+ */
73
+ record_raw_event(eventType: 'user_question' | 'agent_response' | 'user_feedback', params: Record<string, unknown>): Promise<void>;
74
+ }
75
+
76
+ export { PrimeOrbitClient, getNovaPhaseApiUrl, record_star_rating, record_thumbs_feedback, setNovaPhaseApiUrl, wrapToRecordLatency };
package/build/index.js ADDED
@@ -0,0 +1,278 @@
1
+ // src/api_utils.ts
2
+ async function recordData(endpoint, payload, headers = { "Content-Type": "application/json" }) {
3
+ const res = await fetch(endpoint, {
4
+ method: "POST",
5
+ headers,
6
+ body: JSON.stringify(payload)
7
+ });
8
+ const text = await res.text();
9
+ let responseBody;
10
+ try {
11
+ responseBody = text ? JSON.parse(text) : null;
12
+ } catch {
13
+ responseBody = text;
14
+ }
15
+ if (!res.ok) {
16
+ throw new Error(`HTTP ${res.status} ${res.statusText}: ${text}`);
17
+ }
18
+ return responseBody;
19
+ }
20
+
21
+ // src/routes.ts
22
+ var routes = {
23
+ latencies: "/system-metrics/latencies",
24
+ "star-ratings": "/user-metrics/star-ratings",
25
+ "thumbs-feedbacks": "/user-metrics/thumbs-feedbacks",
26
+ "raw-events": "/user-metrics/raw-events"
27
+ };
28
+
29
+ // src/system_metrics/measure_latency.ts
30
+ function recordLatency(startTime, agentId, actionId, actionFailed) {
31
+ const endTime = performance.now();
32
+ const latency = Math.floor(endTime - startTime);
33
+ recordData(routes["latencies"], {
34
+ agent_id: agentId,
35
+ latency,
36
+ action_id: actionId,
37
+ action_failed: actionFailed
38
+ });
39
+ }
40
+ function wrapToRecordLatency(fn, agentId, actionId = "") {
41
+ return function(...args) {
42
+ const start = performance.now();
43
+ let failed = true;
44
+ const agentActionId = actionId || fn.name;
45
+ try {
46
+ const result = fn.apply(this, args);
47
+ if (result instanceof Promise) {
48
+ return result.then((res) => {
49
+ failed = false;
50
+ recordLatency(start, agentId, agentActionId, failed);
51
+ return res;
52
+ }).catch((err) => {
53
+ recordLatency(start, agentId, agentActionId, failed);
54
+ throw err;
55
+ });
56
+ } else {
57
+ failed = false;
58
+ recordLatency(start, agentId, agentActionId, failed);
59
+ return result;
60
+ }
61
+ } catch (err) {
62
+ recordLatency(start, agentId, agentActionId, failed);
63
+ throw err;
64
+ }
65
+ };
66
+ }
67
+
68
+ // src/config.ts
69
+ var baseApiUrl;
70
+ function setNovaPhaseApiUrl(url) {
71
+ baseApiUrl = url;
72
+ }
73
+ function getNovaPhaseApiUrl() {
74
+ if (!baseApiUrl) {
75
+ throw new Error(
76
+ `NovaPhase API URL is not set. Please call 'setNovaPhaseApiUrl(<url>)' before using the SDK.`
77
+ );
78
+ }
79
+ return baseApiUrl;
80
+ }
81
+
82
+ // src/user_metrics/record_star_rating.ts
83
+ async function record_star_rating(agentId, rating, taskName, userId = "") {
84
+ try {
85
+ const payload = {
86
+ agent_id: agentId,
87
+ rating,
88
+ task_name: taskName
89
+ };
90
+ if (userId) {
91
+ payload.user_id = userId;
92
+ }
93
+ await recordData(routes["star-ratings"], payload);
94
+ } catch (err) {
95
+ console.error(
96
+ `[NovaPhase SDK] recordData failed: ${err.message}`
97
+ );
98
+ }
99
+ }
100
+
101
+ // src/user_metrics/record_thumbs_feedback.ts
102
+ async function record_thumbs_feedback(agentId, isThumbsUp, taskName, userId = "") {
103
+ try {
104
+ const payload = {
105
+ agent_id: agentId,
106
+ is_thumbs_up: isThumbsUp,
107
+ task_name: taskName
108
+ };
109
+ if (userId) {
110
+ payload.user_id = userId;
111
+ }
112
+ await recordData(routes["thumbs-feedbacks"], payload);
113
+ } catch (err) {
114
+ console.error(
115
+ `[NovaPhase SDK] Failed to record thumbs feedback: ${err.message}`
116
+ );
117
+ }
118
+ }
119
+
120
+ // src/user_metrics/record_user_event.ts
121
+ import * as dotenv from "dotenv";
122
+ dotenv.config();
123
+ var PrimeOrbitClient = class {
124
+ apiKey;
125
+ baseUrl;
126
+ baseProperties = {};
127
+ verbose = false;
128
+ /**
129
+ * @param {string} apiKey - Your PrimeOrbit API key
130
+ * @param {string} [endpoint] - endpoint URL
131
+ */
132
+ constructor(apiKey, endpoint) {
133
+ if (apiKey) {
134
+ this.apiKey = apiKey;
135
+ } else if (process.env.PRIMEORBIT_API_KEY) {
136
+ this.apiKey = process.env.PRIMEORBIT_API_KEY;
137
+ } else {
138
+ throw new Error(
139
+ "API key not provided. Set the 'apiKey' parameter or the 'PRIMEORBIT_API_KEY' environment variable."
140
+ );
141
+ }
142
+ if (endpoint) {
143
+ this.baseUrl = endpoint;
144
+ } else if (process.env.PRIMEORBIT_ENDPOINT) {
145
+ this.baseUrl = process.env.PRIMEORBIT_ENDPOINT;
146
+ } else {
147
+ this.baseUrl = "https://sdk-dev.primeorbit.ai";
148
+ }
149
+ this.baseProperties = {};
150
+ }
151
+ add_properties(props) {
152
+ this.baseProperties = {
153
+ ...this.baseProperties,
154
+ ...props
155
+ };
156
+ }
157
+ _headers() {
158
+ return {
159
+ Authorization: `Bearer ${this.apiKey}`,
160
+ "Content-Type": "application/json"
161
+ };
162
+ }
163
+ /**
164
+ * Records any agent interaction event such as user_question, agent_response, or user_feedback.
165
+ *
166
+ * @param eventType - Type of event. Can be:
167
+ * - 'user_question' – when the user asks a question
168
+ * - 'agent_response' – when the agent replies
169
+ * - 'user_feedback' – when the user gives feedback
170
+ *
171
+ * @param params - Object containing event details:
172
+ * - conversationId: string – Unique conversation identifier
173
+ * - agentId: string – Agent ID
174
+ * - userId: string – User ID
175
+ * - productId?: string – Optional product ID
176
+ * - content: string – Text content of the event (user question, agent reply, or feedback)
177
+ * - sessionId?: string – Optional session ID
178
+ * - messageId?: string – Optional message ID (for tracking within conversation)
179
+ * - inputMode?: string – Optional input mode (e.g., 'text', 'voice')
180
+ * - device?: string – Optional device name or model (e.g., 'iPhone 13')
181
+ * - country?: string – Optional country of the user (ISO country code, e.g., 'US')
182
+ * - platform?: string – Optional platform or OS (e.g., 'iOS', 'Android', 'Web')
183
+ * - language?: string – Optional language of the user (e.g., 'en-US')
184
+ * - Any additional properties will be captured in additional_properties
185
+ */
186
+ async record_raw_event(eventType, params) {
187
+ const finalParams = {
188
+ ...this.baseProperties,
189
+ ...params
190
+ };
191
+ try {
192
+ const {
193
+ conversationId,
194
+ messageId,
195
+ agentId,
196
+ userId,
197
+ appId,
198
+ content,
199
+ sessionId,
200
+ eventId,
201
+ inputMode,
202
+ device,
203
+ country,
204
+ platform,
205
+ experimentId,
206
+ ...extraProps
207
+ } = finalParams;
208
+ const requiredFields = ["conversationId", "userId", "content"];
209
+ const missingRequired = requiredFields.filter(
210
+ (field) => !(field in finalParams) || finalParams[field] === void 0
211
+ );
212
+ if (missingRequired.length > 0) {
213
+ throw new Error(
214
+ `Missing required fields: ${missingRequired.join(", ")}`
215
+ );
216
+ }
217
+ const optionalFields = [
218
+ "agentId",
219
+ "sessionId",
220
+ "eventId",
221
+ "messageId",
222
+ "experimentId",
223
+ "inputMode",
224
+ "device",
225
+ "country",
226
+ "platform",
227
+ "appId",
228
+ "model"
229
+ ];
230
+ const missingOptionals = optionalFields.filter(
231
+ (field) => !(field in finalParams) || finalParams[field] === void 0
232
+ );
233
+ if (missingOptionals.length > 0) {
234
+ if (this.verbose) {
235
+ console.warn(
236
+ `[PrimeOrbit Analytics Warning] Missing optional fields: ${missingOptionals.join(", ")}. Analytics may be less accurate or incomplete.`
237
+ );
238
+ }
239
+ }
240
+ const payload = {
241
+ event_type: eventType,
242
+ conversation_id: conversationId,
243
+ session_id: sessionId,
244
+ user_id: userId,
245
+ agent_id: agentId,
246
+ message_id: messageId,
247
+ event_id: eventId,
248
+ app_id: appId,
249
+ content,
250
+ input_mode: inputMode,
251
+ device,
252
+ country,
253
+ platform,
254
+ experiment_id: experimentId,
255
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
256
+ additional_properties: Object.keys(extraProps).length > 0 ? extraProps : void 0
257
+ };
258
+ console.log("[PrimeOrbit] Recording event:", payload);
259
+ await recordData(
260
+ `${this.baseUrl}${routes["raw-events"]}`,
261
+ payload,
262
+ this._headers()
263
+ );
264
+ } catch (err) {
265
+ console.error(
266
+ `[PrimeOrbit Error] recording_event failed}: ${err}`
267
+ );
268
+ }
269
+ }
270
+ };
271
+ export {
272
+ PrimeOrbitClient,
273
+ getNovaPhaseApiUrl,
274
+ record_star_rating,
275
+ record_thumbs_feedback,
276
+ setNovaPhaseApiUrl,
277
+ wrapToRecordLatency
278
+ };
package/package.json ADDED
@@ -0,0 +1,89 @@
1
+ {
2
+ "name": "primeorbit-sdk",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "license": "MIT",
6
+ "files": [
7
+ "build"
8
+ ],
9
+ "main": "build/index.js",
10
+ "module": "build/index.js",
11
+ "exports": {
12
+ "import": "./build/index.js",
13
+ "require": "./build/index.js"
14
+ },
15
+ "directories": {
16
+ "src": "src",
17
+ "tests": "tests"
18
+ },
19
+ "scripts": {
20
+ "build": "tsup src/index.ts --format esm,cjs --dts --out-dir build",
21
+ "prepare": "husky",
22
+ "test": "jest",
23
+ "bundle": "npm run build && npm pack",
24
+ "prepublishOnly": "npm run test && npm run build",
25
+ "version:patch": "npm version patch --no-git-tag-version",
26
+ "version:minor": "npm version minor --no-git-tag-version",
27
+ "version:major": "npm version major --no-git-tag-version",
28
+ "publish:latest": "npm run build && npm publish --tag latest",
29
+ "publish:patch": "npm run version:patch && npm run build && npm publish --tag latest",
30
+ "publish:minor": "npm run version:minor && npm run build && npm publish --tag latest",
31
+ "publish:major": "npm run version:major && npm run build && npm publish --tag latest",
32
+ "publish:beta": "npm run build && npm publish --tag beta",
33
+ "publish:beta:patch": "npm run version:patch && npm run build && npm publish --tag beta",
34
+ "publish:alpha": "npm run build && npm publish --tag alpha",
35
+ "publish:alpha:patch": "npm run version:patch && npm run build && npm publish --tag alpha",
36
+ "publish:next": "npm run build && npm publish --tag next",
37
+ "publish:next:patch": "npm run version:patch && npm run build && npm publish --tag next"
38
+ },
39
+ "husky": {
40
+ "hooks": {
41
+ "pre-commit": "lint-staged"
42
+ }
43
+ },
44
+ "lint-staged": {
45
+ "{src,tests}/**/*.{js,jsx,ts,tsx}": [
46
+ "npx eslint --fix",
47
+ "npx prettier --write --ignore-unknown",
48
+ "npx jest --findRelatedTests"
49
+ ],
50
+ "docs/**/*.md": "mdformat --wrap 80 --number",
51
+ "scripts/**/*.sh": "shellcheck -x"
52
+ },
53
+ "prettier": {
54
+ "proseWrap": "always",
55
+ "singleQuote": true
56
+ },
57
+ "devDependencies": {
58
+ "@eslint/js": "^9.34.0",
59
+ "@jest/globals": "^30.1.1",
60
+ "@types/jest": "^30.0.0",
61
+ "@types/node": "^24.3.0",
62
+ "@types/supertest": "^6.0.3",
63
+ "@typescript-eslint/eslint-plugin": "^8.41.0",
64
+ "@typescript-eslint/parser": "^8.41.0",
65
+ "eslint": "^9.34.0",
66
+ "eslint-config-love": "^122.0.0",
67
+ "eslint-config-prettier": "^10.1.8",
68
+ "eslint-plugin-import": "^2.32.0",
69
+ "eslint-plugin-n": "^17.21.3",
70
+ "eslint-plugin-promise": "^7.2.1",
71
+ "husky": "^9.1.7",
72
+ "jest": "^30.1.1",
73
+ "jest-fetch-mock": "^3.0.3",
74
+ "lint-staged": "^16.1.5",
75
+ "npm-check-updates": "^18.0.3",
76
+ "prettier": "^3.6.2",
77
+ "supertest": "^7.1.4",
78
+ "ts-jest": "^29.4.1",
79
+ "ts-node": "^10.9.2",
80
+ "tsup": "^8.5.1",
81
+ "tsx": "^4.20.5",
82
+ "typescript": "^5.9.3",
83
+ "vite": "^7.1.7",
84
+ "vite-tsconfig-paths": "^5.1.4"
85
+ },
86
+ "dependencies": {
87
+ "dotenv": "^17.2.3"
88
+ }
89
+ }