@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 +196 -0
- package/dist/index.d.ts +100 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +163 -0
- package/package.json +49 -0
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
|
package/dist/index.d.ts
ADDED
|
@@ -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
|
+
}
|