waterlight 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 +169 -0
- package/dist/client.d.ts +103 -0
- package/dist/client.js +132 -0
- package/dist/errors.d.ts +16 -0
- package/dist/errors.js +39 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +23 -0
- package/dist/streaming.d.ts +17 -0
- package/dist/streaming.js +73 -0
- package/dist/types.d.ts +106 -0
- package/dist/types.js +2 -0
- package/package.json +35 -0
package/README.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# Waterlight Node.js SDK
|
|
2
|
+
|
|
3
|
+
OpenAI-compatible TypeScript/JavaScript client for the [Waterlight API](https://waterlight.ai). Zero dependencies — uses only the built-in `fetch` API.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install waterlight
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { Waterlight } from 'waterlight';
|
|
15
|
+
|
|
16
|
+
const client = new Waterlight({ apiKey: 'wl-...' });
|
|
17
|
+
|
|
18
|
+
const response = await client.chat.completions.create({
|
|
19
|
+
model: 'mist-1-turbo',
|
|
20
|
+
messages: [{ role: 'user', content: 'Hello!' }],
|
|
21
|
+
});
|
|
22
|
+
console.log(response.choices[0].message.content);
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Drop-in OpenAI Replacement
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
// Before
|
|
29
|
+
import OpenAI from 'openai';
|
|
30
|
+
const client = new OpenAI({ apiKey: 'sk-...' });
|
|
31
|
+
|
|
32
|
+
// After
|
|
33
|
+
import { Waterlight } from 'waterlight';
|
|
34
|
+
const client = new Waterlight({ apiKey: 'wl-...' });
|
|
35
|
+
|
|
36
|
+
// Same API — no other code changes needed
|
|
37
|
+
const response = await client.chat.completions.create({
|
|
38
|
+
model: 'mist-1-turbo',
|
|
39
|
+
messages: [{ role: 'user', content: 'Hello!' }],
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Streaming
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
const stream = client.chat.completions.create({
|
|
47
|
+
model: 'mist-1-turbo',
|
|
48
|
+
messages: [{ role: 'user', content: 'Tell me a story' }],
|
|
49
|
+
stream: true,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
for await (const chunk of stream) {
|
|
53
|
+
process.stdout.write(chunk.choices[0]?.delta?.content ?? '');
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Tool Calling
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
const response = await client.chat.completions.create({
|
|
61
|
+
model: 'mist-1-turbo',
|
|
62
|
+
messages: [{ role: 'user', content: "What's the weather in Austin?" }],
|
|
63
|
+
tools: [{
|
|
64
|
+
type: 'function',
|
|
65
|
+
function: {
|
|
66
|
+
name: 'get_weather',
|
|
67
|
+
description: 'Get current weather',
|
|
68
|
+
parameters: {
|
|
69
|
+
type: 'object',
|
|
70
|
+
properties: {
|
|
71
|
+
location: { type: 'string' },
|
|
72
|
+
},
|
|
73
|
+
required: ['location'],
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
}],
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
if (response.choices[0].message.tool_calls) {
|
|
80
|
+
for (const call of response.choices[0].message.tool_calls) {
|
|
81
|
+
console.log(call);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Embeddings
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
const result = await client.embeddings.create({
|
|
90
|
+
input: 'Hello world',
|
|
91
|
+
});
|
|
92
|
+
console.log(result.data[0].embedding.length); // dimension count
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Models
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
const models = await client.models.list();
|
|
99
|
+
for (const model of models.data) {
|
|
100
|
+
console.log(model.id);
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Billing
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
import { Waterlight, BillingInfo } from 'waterlight';
|
|
108
|
+
|
|
109
|
+
const billing: BillingInfo = await client.billing.get();
|
|
110
|
+
console.log(billing); // plan, spent_usd, balance, limits
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Error Handling
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
import {
|
|
117
|
+
Waterlight,
|
|
118
|
+
AuthenticationError,
|
|
119
|
+
RateLimitError,
|
|
120
|
+
InsufficientCreditsError,
|
|
121
|
+
APIError,
|
|
122
|
+
} from 'waterlight';
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
const response = await client.chat.completions.create({
|
|
126
|
+
model: 'mist-1-turbo',
|
|
127
|
+
messages: [{ role: 'user', content: 'Hello' }],
|
|
128
|
+
});
|
|
129
|
+
} catch (e) {
|
|
130
|
+
if (e instanceof AuthenticationError) {
|
|
131
|
+
console.error('Invalid API key');
|
|
132
|
+
} else if (e instanceof RateLimitError) {
|
|
133
|
+
console.error('Rate limited');
|
|
134
|
+
} else if (e instanceof InsufficientCreditsError) {
|
|
135
|
+
console.error('Add credits at https://waterlight.ai');
|
|
136
|
+
} else if (e instanceof APIError) {
|
|
137
|
+
console.error(`API error ${e.statusCode}: ${e.message}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Configuration
|
|
143
|
+
|
|
144
|
+
| Parameter | Env Var | Default |
|
|
145
|
+
|-----------|---------|---------|
|
|
146
|
+
| `apiKey` | `WATERLIGHT_API_KEY` | — (required) |
|
|
147
|
+
| `baseUrl` | `WATERLIGHT_BASE_URL` | `https://api.waterlight.ai` |
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
// Using env var
|
|
151
|
+
process.env.WATERLIGHT_API_KEY = 'wl-...';
|
|
152
|
+
const client = new Waterlight(); // picks up from env
|
|
153
|
+
|
|
154
|
+
// Explicit
|
|
155
|
+
const client = new Waterlight({
|
|
156
|
+
apiKey: 'wl-...',
|
|
157
|
+
baseUrl: 'https://custom.endpoint.com',
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Requirements
|
|
162
|
+
|
|
163
|
+
- Node.js 18+ (uses built-in `fetch`)
|
|
164
|
+
- TypeScript 5+ (for type definitions)
|
|
165
|
+
- Zero runtime dependencies
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
MIT
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { ChatCompletionCreateParams, ChatCompletion, EmbeddingCreateParams, EmbeddingResponse, ModelList } from './types';
|
|
2
|
+
import { Stream } from './streaming';
|
|
3
|
+
/** Chat completions namespace. */
|
|
4
|
+
declare class Completions {
|
|
5
|
+
private readonly client;
|
|
6
|
+
constructor(client: Waterlight);
|
|
7
|
+
/**
|
|
8
|
+
* Create a chat completion.
|
|
9
|
+
*
|
|
10
|
+
* @param params - Chat completion parameters
|
|
11
|
+
* @returns ChatCompletion if stream is false/undefined, Stream if stream is true
|
|
12
|
+
*/
|
|
13
|
+
create(params: ChatCompletionCreateParams & {
|
|
14
|
+
stream: true;
|
|
15
|
+
}): Stream;
|
|
16
|
+
create(params: ChatCompletionCreateParams & {
|
|
17
|
+
stream?: false;
|
|
18
|
+
}): Promise<ChatCompletion>;
|
|
19
|
+
create(params: ChatCompletionCreateParams): Promise<ChatCompletion> | Stream;
|
|
20
|
+
}
|
|
21
|
+
/** Chat namespace — mirrors openai.chat. */
|
|
22
|
+
declare class Chat {
|
|
23
|
+
readonly completions: Completions;
|
|
24
|
+
constructor(client: Waterlight);
|
|
25
|
+
}
|
|
26
|
+
/** Embeddings namespace. */
|
|
27
|
+
declare class Embeddings {
|
|
28
|
+
private readonly client;
|
|
29
|
+
constructor(client: Waterlight);
|
|
30
|
+
create(params: EmbeddingCreateParams): Promise<EmbeddingResponse>;
|
|
31
|
+
}
|
|
32
|
+
/** Models namespace. */
|
|
33
|
+
declare class Models {
|
|
34
|
+
private readonly client;
|
|
35
|
+
constructor(client: Waterlight);
|
|
36
|
+
list(): Promise<ModelList>;
|
|
37
|
+
}
|
|
38
|
+
/** Billing info response. */
|
|
39
|
+
export interface BillingInfo {
|
|
40
|
+
plan: string;
|
|
41
|
+
billing_mode: string;
|
|
42
|
+
spent_usd: number;
|
|
43
|
+
total_requests: number;
|
|
44
|
+
total_tokens: number;
|
|
45
|
+
rpm_limit: number;
|
|
46
|
+
tpm_limit: number;
|
|
47
|
+
balance_usd?: number;
|
|
48
|
+
min_deposit_usd?: number;
|
|
49
|
+
budget_usd?: number;
|
|
50
|
+
remaining_usd?: number;
|
|
51
|
+
monthly_usd?: number;
|
|
52
|
+
daily_limit?: number;
|
|
53
|
+
daily_used?: number;
|
|
54
|
+
allowed_models?: string[];
|
|
55
|
+
}
|
|
56
|
+
/** Billing namespace — Waterlight-specific (not in OpenAI SDK). */
|
|
57
|
+
declare class Billing {
|
|
58
|
+
private readonly client;
|
|
59
|
+
constructor(client: Waterlight);
|
|
60
|
+
get(): Promise<BillingInfo>;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Waterlight API client — OpenAI-compatible interface.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* import { Waterlight } from 'waterlight';
|
|
68
|
+
*
|
|
69
|
+
* const client = new Waterlight({ apiKey: 'wl-...' });
|
|
70
|
+
*
|
|
71
|
+
* // Non-streaming
|
|
72
|
+
* const response = await client.chat.completions.create({
|
|
73
|
+
* model: 'mist-1-turbo',
|
|
74
|
+
* messages: [{ role: 'user', content: 'Hello!' }],
|
|
75
|
+
* });
|
|
76
|
+
* console.log(response.choices[0].message.content);
|
|
77
|
+
*
|
|
78
|
+
* // Streaming
|
|
79
|
+
* const stream = client.chat.completions.create({
|
|
80
|
+
* model: 'mist-1-turbo',
|
|
81
|
+
* messages: [{ role: 'user', content: 'Tell me a story' }],
|
|
82
|
+
* stream: true,
|
|
83
|
+
* });
|
|
84
|
+
* for await (const chunk of stream) {
|
|
85
|
+
* process.stdout.write(chunk.choices[0]?.delta?.content ?? '');
|
|
86
|
+
* }
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export declare class Waterlight {
|
|
90
|
+
readonly apiKey: string;
|
|
91
|
+
readonly baseUrl: string;
|
|
92
|
+
readonly chat: Chat;
|
|
93
|
+
readonly embeddings: Embeddings;
|
|
94
|
+
readonly models: Models;
|
|
95
|
+
readonly billing: Billing;
|
|
96
|
+
constructor(opts?: {
|
|
97
|
+
apiKey?: string;
|
|
98
|
+
baseUrl?: string;
|
|
99
|
+
});
|
|
100
|
+
private _post;
|
|
101
|
+
private _get;
|
|
102
|
+
}
|
|
103
|
+
export {};
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Waterlight = void 0;
|
|
4
|
+
const errors_1 = require("./errors");
|
|
5
|
+
const streaming_1 = require("./streaming");
|
|
6
|
+
const DEFAULT_BASE_URL = 'https://api.waterlight.ai';
|
|
7
|
+
function handleError(status, body) {
|
|
8
|
+
const errObj = body?.error;
|
|
9
|
+
const msg = (typeof errObj === 'object' ? errObj?.message : errObj) ?? 'Request failed';
|
|
10
|
+
if (status === 401)
|
|
11
|
+
throw new errors_1.AuthenticationError(msg);
|
|
12
|
+
if (status === 429)
|
|
13
|
+
throw new errors_1.RateLimitError(msg);
|
|
14
|
+
if (status === 402)
|
|
15
|
+
throw new errors_1.InsufficientCreditsError(msg);
|
|
16
|
+
throw new errors_1.APIError(msg, status);
|
|
17
|
+
}
|
|
18
|
+
/** Chat completions namespace. */
|
|
19
|
+
class Completions {
|
|
20
|
+
constructor(client) {
|
|
21
|
+
this.client = client;
|
|
22
|
+
}
|
|
23
|
+
create(params) {
|
|
24
|
+
if (params.stream) {
|
|
25
|
+
return new streaming_1.Stream(`${this.client.baseUrl}/v1/chat/completions`, this.client.apiKey, params);
|
|
26
|
+
}
|
|
27
|
+
return this.client['_post']('/v1/chat/completions', { ...params, stream: false });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Chat namespace — mirrors openai.chat. */
|
|
31
|
+
class Chat {
|
|
32
|
+
constructor(client) {
|
|
33
|
+
this.completions = new Completions(client);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/** Embeddings namespace. */
|
|
37
|
+
class Embeddings {
|
|
38
|
+
constructor(client) {
|
|
39
|
+
this.client = client;
|
|
40
|
+
}
|
|
41
|
+
async create(params) {
|
|
42
|
+
return this.client['_post']('/v1/embeddings', params);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** Models namespace. */
|
|
46
|
+
class Models {
|
|
47
|
+
constructor(client) {
|
|
48
|
+
this.client = client;
|
|
49
|
+
}
|
|
50
|
+
async list() {
|
|
51
|
+
return this.client['_get']('/v1/models');
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/** Billing namespace — Waterlight-specific (not in OpenAI SDK). */
|
|
55
|
+
class Billing {
|
|
56
|
+
constructor(client) {
|
|
57
|
+
this.client = client;
|
|
58
|
+
}
|
|
59
|
+
async get() {
|
|
60
|
+
return this.client['_get']('/v1/billing');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Waterlight API client — OpenAI-compatible interface.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* import { Waterlight } from 'waterlight';
|
|
69
|
+
*
|
|
70
|
+
* const client = new Waterlight({ apiKey: 'wl-...' });
|
|
71
|
+
*
|
|
72
|
+
* // Non-streaming
|
|
73
|
+
* const response = await client.chat.completions.create({
|
|
74
|
+
* model: 'mist-1-turbo',
|
|
75
|
+
* messages: [{ role: 'user', content: 'Hello!' }],
|
|
76
|
+
* });
|
|
77
|
+
* console.log(response.choices[0].message.content);
|
|
78
|
+
*
|
|
79
|
+
* // Streaming
|
|
80
|
+
* const stream = client.chat.completions.create({
|
|
81
|
+
* model: 'mist-1-turbo',
|
|
82
|
+
* messages: [{ role: 'user', content: 'Tell me a story' }],
|
|
83
|
+
* stream: true,
|
|
84
|
+
* });
|
|
85
|
+
* for await (const chunk of stream) {
|
|
86
|
+
* process.stdout.write(chunk.choices[0]?.delta?.content ?? '');
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
class Waterlight {
|
|
91
|
+
constructor(opts = {}) {
|
|
92
|
+
const key = opts.apiKey ?? process.env.WATERLIGHT_API_KEY;
|
|
93
|
+
if (!key) {
|
|
94
|
+
throw new errors_1.WaterlightError('API key required. Pass apiKey or set WATERLIGHT_API_KEY env var. ' +
|
|
95
|
+
'Get your key at https://waterlight.ai');
|
|
96
|
+
}
|
|
97
|
+
this.apiKey = key;
|
|
98
|
+
this.baseUrl = (opts.baseUrl ?? process.env.WATERLIGHT_BASE_URL ?? DEFAULT_BASE_URL).replace(/\/+$/, '');
|
|
99
|
+
this.chat = new Chat(this);
|
|
100
|
+
this.embeddings = new Embeddings(this);
|
|
101
|
+
this.models = new Models(this);
|
|
102
|
+
this.billing = new Billing(this);
|
|
103
|
+
}
|
|
104
|
+
async _post(path, body) {
|
|
105
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
106
|
+
method: 'POST',
|
|
107
|
+
headers: {
|
|
108
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
109
|
+
'Content-Type': 'application/json',
|
|
110
|
+
'User-Agent': 'waterlight-node/0.1.0',
|
|
111
|
+
},
|
|
112
|
+
body: JSON.stringify(body),
|
|
113
|
+
});
|
|
114
|
+
const data = await res.json();
|
|
115
|
+
if (!res.ok)
|
|
116
|
+
handleError(res.status, data);
|
|
117
|
+
return data;
|
|
118
|
+
}
|
|
119
|
+
async _get(path) {
|
|
120
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
121
|
+
headers: {
|
|
122
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
123
|
+
'User-Agent': 'waterlight-node/0.1.0',
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
const data = await res.json();
|
|
127
|
+
if (!res.ok)
|
|
128
|
+
handleError(res.status, data);
|
|
129
|
+
return data;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
exports.Waterlight = Waterlight;
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare class WaterlightError extends Error {
|
|
2
|
+
readonly status?: number;
|
|
3
|
+
constructor(message: string, status?: number);
|
|
4
|
+
}
|
|
5
|
+
export declare class AuthenticationError extends WaterlightError {
|
|
6
|
+
constructor(message: string);
|
|
7
|
+
}
|
|
8
|
+
export declare class RateLimitError extends WaterlightError {
|
|
9
|
+
constructor(message: string);
|
|
10
|
+
}
|
|
11
|
+
export declare class InsufficientCreditsError extends WaterlightError {
|
|
12
|
+
constructor(message: string);
|
|
13
|
+
}
|
|
14
|
+
export declare class APIError extends WaterlightError {
|
|
15
|
+
constructor(message: string, status?: number);
|
|
16
|
+
}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.APIError = exports.InsufficientCreditsError = exports.RateLimitError = exports.AuthenticationError = exports.WaterlightError = void 0;
|
|
4
|
+
class WaterlightError extends Error {
|
|
5
|
+
constructor(message, status) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = 'WaterlightError';
|
|
8
|
+
this.status = status;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
exports.WaterlightError = WaterlightError;
|
|
12
|
+
class AuthenticationError extends WaterlightError {
|
|
13
|
+
constructor(message) {
|
|
14
|
+
super(message, 401);
|
|
15
|
+
this.name = 'AuthenticationError';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.AuthenticationError = AuthenticationError;
|
|
19
|
+
class RateLimitError extends WaterlightError {
|
|
20
|
+
constructor(message) {
|
|
21
|
+
super(message, 429);
|
|
22
|
+
this.name = 'RateLimitError';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.RateLimitError = RateLimitError;
|
|
26
|
+
class InsufficientCreditsError extends WaterlightError {
|
|
27
|
+
constructor(message) {
|
|
28
|
+
super(message, 402);
|
|
29
|
+
this.name = 'InsufficientCreditsError';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.InsufficientCreditsError = InsufficientCreditsError;
|
|
33
|
+
class APIError extends WaterlightError {
|
|
34
|
+
constructor(message, status) {
|
|
35
|
+
super(message, status);
|
|
36
|
+
this.name = 'APIError';
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.APIError = APIError;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.Stream = exports.Waterlight = void 0;
|
|
18
|
+
var client_1 = require("./client");
|
|
19
|
+
Object.defineProperty(exports, "Waterlight", { enumerable: true, get: function () { return client_1.Waterlight; } });
|
|
20
|
+
__exportStar(require("./types"), exports);
|
|
21
|
+
__exportStar(require("./errors"), exports);
|
|
22
|
+
var streaming_1 = require("./streaming");
|
|
23
|
+
Object.defineProperty(exports, "Stream", { enumerable: true, get: function () { return streaming_1.Stream; } });
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ChatCompletionChunk } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* SSE stream that implements AsyncIterable<ChatCompletionChunk>.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* const stream = client.chat.completions.create({ ..., stream: true });
|
|
7
|
+
* for await (const chunk of stream) {
|
|
8
|
+
* process.stdout.write(chunk.choices[0]?.delta?.content ?? '');
|
|
9
|
+
* }
|
|
10
|
+
*/
|
|
11
|
+
export declare class Stream implements AsyncIterable<ChatCompletionChunk> {
|
|
12
|
+
private readonly url;
|
|
13
|
+
private readonly apiKey;
|
|
14
|
+
private readonly body;
|
|
15
|
+
constructor(url: string, apiKey: string, params: object);
|
|
16
|
+
[Symbol.asyncIterator](): AsyncIterator<ChatCompletionChunk>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Stream = void 0;
|
|
4
|
+
const errors_1 = require("./errors");
|
|
5
|
+
/**
|
|
6
|
+
* SSE stream that implements AsyncIterable<ChatCompletionChunk>.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* const stream = client.chat.completions.create({ ..., stream: true });
|
|
10
|
+
* for await (const chunk of stream) {
|
|
11
|
+
* process.stdout.write(chunk.choices[0]?.delta?.content ?? '');
|
|
12
|
+
* }
|
|
13
|
+
*/
|
|
14
|
+
class Stream {
|
|
15
|
+
constructor(url, apiKey, params) {
|
|
16
|
+
this.url = url;
|
|
17
|
+
this.apiKey = apiKey;
|
|
18
|
+
this.body = JSON.stringify({ ...params, stream: true });
|
|
19
|
+
}
|
|
20
|
+
async *[Symbol.asyncIterator]() {
|
|
21
|
+
const res = await fetch(this.url, {
|
|
22
|
+
method: 'POST',
|
|
23
|
+
headers: {
|
|
24
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
25
|
+
'Content-Type': 'application/json',
|
|
26
|
+
'Accept': 'text/event-stream',
|
|
27
|
+
},
|
|
28
|
+
body: this.body,
|
|
29
|
+
});
|
|
30
|
+
if (!res.ok) {
|
|
31
|
+
let errMsg = '';
|
|
32
|
+
try {
|
|
33
|
+
errMsg = await res.text();
|
|
34
|
+
}
|
|
35
|
+
catch { }
|
|
36
|
+
throw new errors_1.WaterlightError(`Streaming error: ${res.status} ${errMsg}`, res.status);
|
|
37
|
+
}
|
|
38
|
+
const reader = res.body.getReader();
|
|
39
|
+
const decoder = new TextDecoder();
|
|
40
|
+
let buffer = '';
|
|
41
|
+
try {
|
|
42
|
+
while (true) {
|
|
43
|
+
const { value, done } = await reader.read();
|
|
44
|
+
if (done)
|
|
45
|
+
break;
|
|
46
|
+
buffer += decoder.decode(value, { stream: true });
|
|
47
|
+
// Process complete SSE events (double newline delimited)
|
|
48
|
+
let boundary;
|
|
49
|
+
while ((boundary = buffer.indexOf('\n\n')) !== -1) {
|
|
50
|
+
const rawEvent = buffer.slice(0, boundary);
|
|
51
|
+
buffer = buffer.slice(boundary + 2);
|
|
52
|
+
for (const line of rawEvent.split('\n')) {
|
|
53
|
+
if (!line.startsWith('data:'))
|
|
54
|
+
continue;
|
|
55
|
+
const data = line.slice(5).trim();
|
|
56
|
+
if (data === '[DONE]')
|
|
57
|
+
return;
|
|
58
|
+
try {
|
|
59
|
+
yield JSON.parse(data);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// skip malformed chunks
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
reader.releaseLock();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
exports.Stream = Stream;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
export type Role = 'system' | 'user' | 'assistant' | 'tool';
|
|
2
|
+
export interface Message {
|
|
3
|
+
role: Role;
|
|
4
|
+
content: string | null;
|
|
5
|
+
name?: string;
|
|
6
|
+
tool_call_id?: string;
|
|
7
|
+
tool_calls?: ToolCall[];
|
|
8
|
+
}
|
|
9
|
+
export interface FunctionCall {
|
|
10
|
+
name: string;
|
|
11
|
+
arguments: string;
|
|
12
|
+
}
|
|
13
|
+
export interface ToolCall {
|
|
14
|
+
id: string;
|
|
15
|
+
type: 'function';
|
|
16
|
+
function: FunctionCall;
|
|
17
|
+
}
|
|
18
|
+
export interface Tool {
|
|
19
|
+
type: 'function';
|
|
20
|
+
function: {
|
|
21
|
+
name: string;
|
|
22
|
+
description?: string;
|
|
23
|
+
parameters?: Record<string, unknown>;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export type ToolChoice = 'none' | 'auto' | {
|
|
27
|
+
type: 'function';
|
|
28
|
+
function: {
|
|
29
|
+
name: string;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
export interface ChatCompletionCreateParams {
|
|
33
|
+
model: string;
|
|
34
|
+
messages: Message[];
|
|
35
|
+
stream?: boolean;
|
|
36
|
+
tools?: Tool[];
|
|
37
|
+
tool_choice?: ToolChoice;
|
|
38
|
+
max_tokens?: number;
|
|
39
|
+
temperature?: number;
|
|
40
|
+
top_p?: number;
|
|
41
|
+
stop?: string | string[];
|
|
42
|
+
presence_penalty?: number;
|
|
43
|
+
frequency_penalty?: number;
|
|
44
|
+
user?: string;
|
|
45
|
+
}
|
|
46
|
+
export interface Choice {
|
|
47
|
+
index: number;
|
|
48
|
+
message: Message;
|
|
49
|
+
finish_reason: string | null;
|
|
50
|
+
}
|
|
51
|
+
export interface Usage {
|
|
52
|
+
prompt_tokens: number;
|
|
53
|
+
completion_tokens: number;
|
|
54
|
+
total_tokens: number;
|
|
55
|
+
}
|
|
56
|
+
export interface ChatCompletion {
|
|
57
|
+
id: string;
|
|
58
|
+
object: 'chat.completion';
|
|
59
|
+
created: number;
|
|
60
|
+
model: string;
|
|
61
|
+
choices: Choice[];
|
|
62
|
+
usage: Usage;
|
|
63
|
+
}
|
|
64
|
+
export interface Delta {
|
|
65
|
+
role?: Role;
|
|
66
|
+
content?: string | null;
|
|
67
|
+
tool_calls?: ToolCall[];
|
|
68
|
+
}
|
|
69
|
+
export interface StreamChoice {
|
|
70
|
+
index: number;
|
|
71
|
+
delta: Delta;
|
|
72
|
+
finish_reason: string | null;
|
|
73
|
+
}
|
|
74
|
+
export interface ChatCompletionChunk {
|
|
75
|
+
id: string;
|
|
76
|
+
object: 'chat.completion.chunk';
|
|
77
|
+
created: number;
|
|
78
|
+
model: string;
|
|
79
|
+
choices: StreamChoice[];
|
|
80
|
+
}
|
|
81
|
+
export interface EmbeddingCreateParams {
|
|
82
|
+
input: string | string[];
|
|
83
|
+
model?: string;
|
|
84
|
+
encoding_format?: string;
|
|
85
|
+
}
|
|
86
|
+
export interface Embedding {
|
|
87
|
+
object: 'embedding';
|
|
88
|
+
index: number;
|
|
89
|
+
embedding: number[];
|
|
90
|
+
}
|
|
91
|
+
export interface EmbeddingResponse {
|
|
92
|
+
object: 'list';
|
|
93
|
+
data: Embedding[];
|
|
94
|
+
model: string;
|
|
95
|
+
usage: Usage;
|
|
96
|
+
}
|
|
97
|
+
export interface Model {
|
|
98
|
+
id: string;
|
|
99
|
+
object: 'model';
|
|
100
|
+
created: number;
|
|
101
|
+
owned_by: string;
|
|
102
|
+
}
|
|
103
|
+
export interface ModelList {
|
|
104
|
+
object: 'list';
|
|
105
|
+
data: Model[];
|
|
106
|
+
}
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "waterlight",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "OpenAI-compatible SDK for the Waterlight API",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"prepublishOnly": "npm run build"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/node": "^25.3.0",
|
|
16
|
+
"typescript": "^5.0.0"
|
|
17
|
+
},
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=18.0.0"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"openai",
|
|
23
|
+
"waterlight",
|
|
24
|
+
"ai",
|
|
25
|
+
"llm",
|
|
26
|
+
"sdk",
|
|
27
|
+
"typescript"
|
|
28
|
+
],
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"homepage": "https://waterlight.ai",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/waterlight-ai/waterlight-node"
|
|
34
|
+
}
|
|
35
|
+
}
|