@nvsudo/sdk-js 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/README.md ADDED
@@ -0,0 +1,196 @@
1
+ # @behavr/sdk
2
+
3
+ Official SDK for **Behavr** — Calibration-as-a-service for AI agent communication.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @behavr/sdk
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { Behavr } from '@behavr/sdk';
15
+
16
+ // Initialize with your API key
17
+ const behavr = new Behavr({
18
+ apiKey: 'bvr_your_api_key_here',
19
+ });
20
+
21
+ // Capture a message after sending it (async, non-blocking)
22
+ await behavr.capture({
23
+ messageId: 'msg_123',
24
+ content: 'Following up on our conversation from last week...',
25
+ channel: 'email',
26
+ interactionType: 'followup',
27
+ conversationId: 'conv_456',
28
+ });
29
+
30
+ // Record an outcome when you receive a reply
31
+ await behavr.outcome({
32
+ messageId: 'msg_123',
33
+ type: 'reply',
34
+ delay: '2 hours',
35
+ sentiment: 'positive',
36
+ });
37
+ ```
38
+
39
+ ## Features
40
+
41
+ - ✅ **Async & Non-blocking** — Fire-and-forget, never blocks your app
42
+ - ✅ **Automatic Retries** — Handles transient failures gracefully
43
+ - ✅ **Rate Limiting** — Respects API quotas automatically
44
+ - ✅ **TypeScript** — Full type safety out of the box
45
+ - ✅ **Framework Agnostic** — Works with any stack
46
+
47
+ ## API Reference
48
+
49
+ ### `new Behavr(config)`
50
+
51
+ Create a new Behavr client.
52
+
53
+ **Options:**
54
+ - `apiKey` (required) — Your Behavr API key
55
+ - `baseUrl` (optional) — Custom API endpoint (defaults to `https://api.behavr.dev`)
56
+ - `retryAttempts` (optional) — Number of retry attempts (default: 3)
57
+ - `retryDelay` (optional) — Base retry delay in ms (default: 1000)
58
+ - `debug` (optional) — Enable debug logging (default: false)
59
+
60
+ ### `behavr.capture(options)`
61
+
62
+ Capture a message sent by your AI agent (async, returns immediately).
63
+
64
+ **Options:**
65
+ - `messageId` (required) — Unique identifier for this message
66
+ - `content` (required) — The actual message content
67
+ - `channel` (optional) — `email | slack | sms | chat | whatsapp | other`
68
+ - `interactionType` (optional) — `followup | decline | escalation | cold_outreach | support | other`
69
+ - `conversationId` (optional) — Group messages into conversations
70
+ - `metadata` (optional) — Additional custom data
71
+
72
+ ### `behavr.outcome(options)`
73
+
74
+ Record an outcome for a previously captured message (async).
75
+
76
+ **Options:**
77
+ - `messageId` (required) — The message ID this outcome relates to
78
+ - `type` (required) — `reply | no_reply | escalation | churn | positive | negative`
79
+ - `delay` (optional) — Time between message and outcome (e.g., `'2 hours'`)
80
+ - `sentiment` (optional) — `positive | neutral | negative | unknown`
81
+ - `metadata` (optional) — Additional custom data
82
+
83
+ ### `behavr.flush()`
84
+
85
+ Wait for all queued operations to complete. Useful for graceful shutdown.
86
+
87
+ ```typescript
88
+ await behavr.flush();
89
+ ```
90
+
91
+ ## Use Cases
92
+
93
+ ### Sales SDR Follow-ups
94
+
95
+ ```typescript
96
+ const behavr = new Behavr({ apiKey: process.env.BEHAVR_API_KEY });
97
+
98
+ // After sending follow-up
99
+ await behavr.capture({
100
+ messageId: outboundEmail.id,
101
+ content: outboundEmail.body,
102
+ channel: 'email',
103
+ interactionType: 'followup',
104
+ metadata: {
105
+ prospectId: prospect.id,
106
+ sequence: 'cold-outreach-v2',
107
+ },
108
+ });
109
+
110
+ // When they reply
111
+ await behavr.outcome({
112
+ messageId: outboundEmail.id,
113
+ type: 'reply',
114
+ delay: '4 hours',
115
+ sentiment: 'positive',
116
+ });
117
+ ```
118
+
119
+ ### Customer Support
120
+
121
+ ```typescript
122
+ // After sending support response
123
+ await behavr.capture({
124
+ messageId: ticket.lastMessageId,
125
+ content: agent.response,
126
+ channel: 'chat',
127
+ interactionType: 'support',
128
+ conversationId: ticket.id,
129
+ });
130
+
131
+ // If escalated
132
+ await behavr.outcome({
133
+ messageId: ticket.lastMessageId,
134
+ type: 'escalation',
135
+ delay: '10 minutes',
136
+ });
137
+ ```
138
+
139
+ ### Consumer Apps (Boundaries)
140
+
141
+ ```typescript
142
+ // When handling sensitive requests
143
+ await behavr.capture({
144
+ messageId: messageId,
145
+ content: agentResponse,
146
+ channel: 'chat',
147
+ interactionType: 'decline',
148
+ metadata: {
149
+ requestType: 'inappropriate-dating',
150
+ },
151
+ });
152
+ ```
153
+
154
+ ## Environment Variables
155
+
156
+ ```bash
157
+ BEHAVR_API_KEY=bvr_your_api_key_here
158
+ ```
159
+
160
+ ## Debug Mode
161
+
162
+ Enable debug logging to troubleshoot integration issues:
163
+
164
+ ```typescript
165
+ const behavr = new Behavr({
166
+ apiKey: 'bvr_...',
167
+ debug: true, // Logs all API calls and errors
168
+ });
169
+ ```
170
+
171
+ ## Error Handling
172
+
173
+ The SDK automatically retries on transient failures (network errors, 5xx responses). It will **not** retry on client errors (4xx) except rate limits (429).
174
+
175
+ If you need to handle errors explicitly, use the sync methods:
176
+
177
+ ```typescript
178
+ try {
179
+ await behavr.captureSync({
180
+ messageId: 'msg_123',
181
+ content: 'Hello world',
182
+ });
183
+ } catch (error) {
184
+ console.error('Failed to capture message:', error);
185
+ }
186
+ ```
187
+
188
+ ## License
189
+
190
+ MIT
191
+
192
+ ## Support
193
+
194
+ - 📖 Documentation: https://docs.behavr.dev
195
+ - 💬 Discord: https://discord.gg/behavr
196
+ - 📧 Email: support@behavr.dev
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @behavr/sdk - Official SDK for Behavr
3
+ * Calibration-as-a-service for AI agent communication
4
+ */
5
+ export interface BehavrConfig {
6
+ apiKey: string;
7
+ baseUrl?: string;
8
+ retryAttempts?: number;
9
+ retryDelay?: number;
10
+ debug?: boolean;
11
+ }
12
+ export interface BehavrReservedMetadata {
13
+ segmentKey?: string;
14
+ modelFamily?: string;
15
+ modelName?: string;
16
+ modelVersion?: string;
17
+ configId?: string;
18
+ configVersionId?: string;
19
+ deploymentId?: string;
20
+ sdr?: {
21
+ sequenceStep?: number;
22
+ daysSinceLastContact?: number;
23
+ prospectState?: 'cold' | 'warm' | 'engaged' | 'soft_decline' | 'hard_decline' | 'unknown';
24
+ replyIntent?: 'none' | 'positive' | 'neutral' | 'negative' | 'unknown';
25
+ };
26
+ proxyEvidence?: {
27
+ humanEdited?: boolean;
28
+ humanEditDistancePct?: number;
29
+ regenerationCount?: number;
30
+ rollbackFlag?: boolean;
31
+ timeToSendSeconds?: number;
32
+ };
33
+ }
34
+ export type BehavrMetadata = Record<string, any> & {
35
+ behavr?: BehavrReservedMetadata;
36
+ };
37
+ export interface CaptureMessageOptions {
38
+ messageId: string;
39
+ content: string;
40
+ channel?: 'email' | 'slack' | 'sms' | 'chat' | 'whatsapp' | 'other';
41
+ interactionType?: 'followup' | 'decline' | 'escalation' | 'cold_outreach' | 'support' | 'other';
42
+ conversationId?: string;
43
+ metadata?: BehavrMetadata;
44
+ }
45
+ export interface RecordOutcomeOptions {
46
+ messageId: string;
47
+ type: 'reply' | 'no_reply' | 'escalation' | 'churn' | 'positive' | 'negative';
48
+ delay?: string;
49
+ sentiment?: 'positive' | 'neutral' | 'negative' | 'unknown';
50
+ metadata?: BehavrMetadata;
51
+ }
52
+ export interface CaptureResponse {
53
+ success: boolean;
54
+ messageId: string;
55
+ id: string;
56
+ }
57
+ export interface OutcomeResponse {
58
+ success: boolean;
59
+ outcomeId: string;
60
+ messageId: string;
61
+ }
62
+ export declare class Behavr {
63
+ private client;
64
+ private config;
65
+ private queue;
66
+ private processing;
67
+ constructor(config: BehavrConfig);
68
+ /**
69
+ * Capture a message sent by your AI agent (async, non-blocking)
70
+ * This method queues the message and returns immediately
71
+ */
72
+ capture(options: CaptureMessageOptions): Promise<void>;
73
+ /**
74
+ * Record an outcome for a previously captured message (async, non-blocking)
75
+ */
76
+ outcome(options: RecordOutcomeOptions): Promise<void>;
77
+ /**
78
+ * Capture a message synchronously (blocks until complete)
79
+ * Use this only if you need confirmation that the message was captured
80
+ */
81
+ captureSync(options: CaptureMessageOptions): Promise<CaptureResponse>;
82
+ /**
83
+ * Record an outcome synchronously (blocks until complete)
84
+ */
85
+ outcomeSync(options: RecordOutcomeOptions): Promise<OutcomeResponse>;
86
+ /**
87
+ * Wait for all queued operations to complete
88
+ * Useful for graceful shutdown
89
+ */
90
+ flush(): Promise<void>;
91
+ private enqueue;
92
+ private processQueue;
93
+ private captureWithRetry;
94
+ private outcomeWithRetry;
95
+ private handleError;
96
+ private log;
97
+ }
98
+ export default Behavr;
99
+ export { Behavr as BehavrClient };
100
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ /**
3
+ * @behavr/sdk - Official SDK for Behavr
4
+ * Calibration-as-a-service for AI agent communication
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.BehavrClient = exports.Behavr = void 0;
11
+ const axios_1 = __importDefault(require("axios"));
12
+ // ============================================================================
13
+ // SDK CLASS
14
+ // ============================================================================
15
+ class Behavr {
16
+ constructor(config) {
17
+ this.queue = [];
18
+ this.processing = false;
19
+ if (!config.apiKey) {
20
+ throw new Error('Behavr: apiKey is required');
21
+ }
22
+ this.config = {
23
+ apiKey: config.apiKey,
24
+ baseUrl: config.baseUrl || 'https://api.behavr.dev',
25
+ retryAttempts: config.retryAttempts ?? 3,
26
+ retryDelay: config.retryDelay ?? 1000,
27
+ debug: config.debug ?? false,
28
+ };
29
+ this.client = axios_1.default.create({
30
+ baseURL: this.config.baseUrl,
31
+ headers: {
32
+ 'Authorization': `Bearer ${this.config.apiKey}`,
33
+ 'Content-Type': 'application/json',
34
+ },
35
+ timeout: 10000, // 10 second timeout
36
+ });
37
+ }
38
+ // ============================================================================
39
+ // PUBLIC METHODS
40
+ // ============================================================================
41
+ /**
42
+ * Capture a message sent by your AI agent (async, non-blocking)
43
+ * This method queues the message and returns immediately
44
+ */
45
+ async capture(options) {
46
+ this.log('Capturing message:', options.messageId);
47
+ this.enqueue(async () => {
48
+ await this.captureWithRetry(options);
49
+ });
50
+ }
51
+ /**
52
+ * Record an outcome for a previously captured message (async, non-blocking)
53
+ */
54
+ async outcome(options) {
55
+ this.log('Recording outcome:', options.messageId, options.type);
56
+ this.enqueue(async () => {
57
+ await this.outcomeWithRetry(options);
58
+ });
59
+ }
60
+ /**
61
+ * Capture a message synchronously (blocks until complete)
62
+ * Use this only if you need confirmation that the message was captured
63
+ */
64
+ async captureSync(options) {
65
+ this.log('Capturing message (sync):', options.messageId);
66
+ return await this.captureWithRetry(options);
67
+ }
68
+ /**
69
+ * Record an outcome synchronously (blocks until complete)
70
+ */
71
+ async outcomeSync(options) {
72
+ this.log('Recording outcome (sync):', options.messageId, options.type);
73
+ return await this.outcomeWithRetry(options);
74
+ }
75
+ /**
76
+ * Wait for all queued operations to complete
77
+ * Useful for graceful shutdown
78
+ */
79
+ async flush() {
80
+ this.log('Flushing queue...');
81
+ while (this.queue.length > 0 || this.processing) {
82
+ await new Promise(resolve => setTimeout(resolve, 100));
83
+ }
84
+ this.log('Queue flushed');
85
+ }
86
+ // ============================================================================
87
+ // PRIVATE METHODS
88
+ // ============================================================================
89
+ enqueue(fn) {
90
+ this.queue.push(fn);
91
+ this.processQueue();
92
+ }
93
+ async processQueue() {
94
+ if (this.processing || this.queue.length === 0) {
95
+ return;
96
+ }
97
+ this.processing = true;
98
+ while (this.queue.length > 0) {
99
+ const fn = this.queue.shift();
100
+ if (fn) {
101
+ try {
102
+ await fn();
103
+ }
104
+ catch (error) {
105
+ this.log('Queue processing error:', error);
106
+ }
107
+ }
108
+ }
109
+ this.processing = false;
110
+ }
111
+ async captureWithRetry(options, attempt = 1) {
112
+ try {
113
+ const response = await this.client.post('/v1/ingest/message', options);
114
+ this.log('Message captured successfully:', options.messageId);
115
+ return response.data;
116
+ }
117
+ catch (error) {
118
+ return this.handleError(error, attempt, () => this.captureWithRetry(options, attempt + 1));
119
+ }
120
+ }
121
+ async outcomeWithRetry(options, attempt = 1) {
122
+ try {
123
+ const response = await this.client.post('/v1/ingest/outcome', options);
124
+ this.log('Outcome recorded successfully:', options.messageId, options.type);
125
+ return response.data;
126
+ }
127
+ catch (error) {
128
+ return this.handleError(error, attempt, () => this.outcomeWithRetry(options, attempt + 1));
129
+ }
130
+ }
131
+ async handleError(error, attempt, retryFn) {
132
+ const isAxiosError = axios_1.default.isAxiosError(error);
133
+ const statusCode = isAxiosError ? error.response?.status : null;
134
+ const errorMessage = isAxiosError
135
+ ? error.response?.data || error.message
136
+ : String(error);
137
+ this.log(`Error (attempt ${attempt}/${this.config.retryAttempts}):`, errorMessage);
138
+ // Don't retry client errors (4xx) except 429 (rate limit)
139
+ if (statusCode && statusCode >= 400 && statusCode < 500 && statusCode !== 429) {
140
+ throw new Error(`Behavr: ${errorMessage}`);
141
+ }
142
+ // Retry if we haven't exhausted attempts
143
+ if (attempt < this.config.retryAttempts) {
144
+ const delay = this.config.retryDelay * attempt; // Exponential backoff
145
+ this.log(`Retrying in ${delay}ms...`);
146
+ await new Promise(resolve => setTimeout(resolve, delay));
147
+ return retryFn();
148
+ }
149
+ // Exhausted retries
150
+ throw new Error(`Behavr: Failed after ${attempt} attempts: ${errorMessage}`);
151
+ }
152
+ log(...args) {
153
+ if (this.config.debug) {
154
+ console.log('[Behavr]', ...args);
155
+ }
156
+ }
157
+ }
158
+ exports.Behavr = Behavr;
159
+ exports.BehavrClient = Behavr;
160
+ // ============================================================================
161
+ // EXPORTS
162
+ // ============================================================================
163
+ exports.default = Behavr;
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@nvsudo/sdk-js",
3
+ "version": "0.1.0",
4
+ "description": "Official SDK for Behavr - Calibration-as-a-service for AI agent communication",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "files": [
11
+ "dist/**/*"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "check": "tsc --noEmit",
16
+ "prepublishOnly": "npm run build",
17
+ "test": "echo \"Tests coming soon\" && exit 0"
18
+ },
19
+ "keywords": [
20
+ "ai",
21
+ "agent",
22
+ "communication",
23
+ "behavioral",
24
+ "scoring",
25
+ "calibration"
26
+ ],
27
+ "author": "Behavr Team",
28
+ "license": "MIT",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/behavr/behavr-oss"
32
+ },
33
+ "bugs": {
34
+ "url": "https://github.com/behavr/behavr-oss/issues"
35
+ },
36
+ "homepage": "https://behavr.dev",
37
+ "dependencies": {
38
+ "axios": "^1.13.5"
39
+ },
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "https://github.com/nvsudo/behavr-oss.git"
43
+ },
44
+ "devDependencies": {
45
+ "@types/node": "^25.3.0",
46
+ "ts-node": "^10.9.2",
47
+ "typescript": "^5.9.3"
48
+ }
49
+ }