@asklumora/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/README.md +1162 -0
- package/dist/examples/chat.d.ts +2 -0
- package/dist/examples/chat.d.ts.map +1 -0
- package/dist/examples/chat.js +17 -0
- package/dist/examples/chat.js.map +1 -0
- package/dist/examples/custom-assistant.d.ts +2 -0
- package/dist/examples/custom-assistant.d.ts.map +1 -0
- package/dist/examples/custom-assistant.js +22 -0
- package/dist/examples/custom-assistant.js.map +1 -0
- package/dist/examples/game-ai.d.ts +2 -0
- package/dist/examples/game-ai.d.ts.map +1 -0
- package/dist/examples/game-ai.js +24 -0
- package/dist/examples/game-ai.js.map +1 -0
- package/dist/examples/providers.d.ts +2 -0
- package/dist/examples/providers.d.ts.map +1 -0
- package/dist/examples/providers.js +17 -0
- package/dist/examples/providers.js.map +1 -0
- package/dist/examples/streaming.d.ts +2 -0
- package/dist/examples/streaming.d.ts.map +1 -0
- package/dist/examples/streaming.js +10 -0
- package/dist/examples/streaming.js.map +1 -0
- package/dist/src/client.d.ts +34 -0
- package/dist/src/client.d.ts.map +1 -0
- package/dist/src/client.js +154 -0
- package/dist/src/client.js.map +1 -0
- package/dist/src/env.d.ts +11 -0
- package/dist/src/env.d.ts.map +1 -0
- package/dist/src/env.js +24 -0
- package/dist/src/env.js.map +1 -0
- package/dist/src/index.d.ts +11 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +6 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/providers/base.d.ts +14 -0
- package/dist/src/providers/base.d.ts.map +1 -0
- package/dist/src/providers/base.js +13 -0
- package/dist/src/providers/base.js.map +1 -0
- package/dist/src/providers/gemini.d.ts +18 -0
- package/dist/src/providers/gemini.d.ts.map +1 -0
- package/dist/src/providers/gemini.js +102 -0
- package/dist/src/providers/gemini.js.map +1 -0
- package/dist/src/providers/openai.d.ts +19 -0
- package/dist/src/providers/openai.d.ts.map +1 -0
- package/dist/src/providers/openai.js +132 -0
- package/dist/src/providers/openai.js.map +1 -0
- package/dist/src/providers/xai.d.ts +19 -0
- package/dist/src/providers/xai.d.ts.map +1 -0
- package/dist/src/providers/xai.js +105 -0
- package/dist/src/providers/xai.js.map +1 -0
- package/dist/src/types/chat.d.ts +50 -0
- package/dist/src/types/chat.d.ts.map +1 -0
- package/dist/src/types/chat.js +2 -0
- package/dist/src/types/chat.js.map +1 -0
- package/dist/src/types/game.d.ts +30 -0
- package/dist/src/types/game.d.ts.map +1 -0
- package/dist/src/types/game.js +2 -0
- package/dist/src/types/game.js.map +1 -0
- package/dist/src/types/training.d.ts +28 -0
- package/dist/src/types/training.d.ts.map +1 -0
- package/dist/src/types/training.js +2 -0
- package/dist/src/types/training.js.map +1 -0
- package/examples/chat.ts +19 -0
- package/examples/custom-assistant.ts +25 -0
- package/examples/game-ai.ts +26 -0
- package/examples/providers.ts +21 -0
- package/examples/streaming.ts +12 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,1162 @@
|
|
|
1
|
+
|
|
2
|
+
# Lumora TypeScript SDK
|
|
3
|
+
|
|
4
|
+

|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
TypeScript SDK for building Lumora-powered AI chat, custom domain assistants, and game AI systems.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
The package is designed for Node.js applications that want one consistent interface over multiple model providers. OpenAI is the default provider, with optional xAI and Gemini support available per request.
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
|
|
18
|
+
npm i @asklumora/sdk
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
<div align="center">
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
### Multi-Provider AI SDK for Chat, Assistants, Training, and Game AI
|
|
27
|
+
|
|
28
|
+
<p>
|
|
29
|
+
<img src="https://img.shields.io/npm/v/lumora-sdk?style=for-the-badge" />
|
|
30
|
+
<img src="https://img.shields.io/npm/dm/lumora-sdk?style=for-the-badge" />
|
|
31
|
+
<img src="https://img.shields.io/github/license/your-org/lumora?style=for-the-badge" />
|
|
32
|
+
<img src="https://img.shields.io/github/stars/your-org/lumora?style=for-the-badge" />
|
|
33
|
+
</p>
|
|
34
|
+
|
|
35
|
+
## Tech Stack
|
|
36
|
+
|
|
37
|
+
<p>
|
|
38
|
+
<img src="https://img.shields.io/badge/TypeScript-3178C6?style=for-the-badge&logo=typescript&logoColor=white" />
|
|
39
|
+
<img src="https://img.shields.io/badge/Node.js-339933?style=for-the-badge&logo=node.js&logoColor=white" />
|
|
40
|
+
<img src="https://img.shields.io/badge/OpenAI-412991?style=for-the-badge&logo=openai&logoColor=white" />
|
|
41
|
+
<img src="https://img.shields.io/badge/Gemini-4285F4?style=for-the-badge&logo=google&logoColor=white" />
|
|
42
|
+
<img src="https://img.shields.io/badge/xAI-000000?style=for-the-badge&logo=x&logoColor=white" />
|
|
43
|
+
</p>
|
|
44
|
+
|
|
45
|
+
<p>
|
|
46
|
+
<img src="https://img.shields.io/badge/AI_SDK-Multi_Provider-blue?style=for-the-badge" />
|
|
47
|
+
<img src="https://img.shields.io/badge/Streaming-Supported-success?style=for-the-badge" />
|
|
48
|
+
<img src="https://img.shields.io/badge/Game_AI-Ready-orange?style=for-the-badge" />
|
|
49
|
+
<img src="https://img.shields.io/badge/Assistants-Customizable-purple?style=for-the-badge" />
|
|
50
|
+
</p>
|
|
51
|
+
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
## Core Capabilities
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
- Train custom AI assistants with your own documents, websites, datasets, or raw text
|
|
61
|
+
|
|
62
|
+
- Build streaming conversational experiences with provider-independent request types
|
|
63
|
+
|
|
64
|
+
- Use OpenAI by default, then switch to xAI or Gemini when a request needs it
|
|
65
|
+
|
|
66
|
+
- Inject long-term memory into chat calls
|
|
67
|
+
|
|
68
|
+
- Define function/tool schemas for tool-aware providers
|
|
69
|
+
|
|
70
|
+
- Generate NPC dialogue, companion behavior, quests, lore, and contextual game interactions
|
|
71
|
+
|
|
72
|
+
- Keep API keys out of source code with `dotenv`
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
## Runtime Requirements
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
- Node.js `>=18`
|
|
81
|
+
|
|
82
|
+
- TypeScript `>=5`
|
|
83
|
+
|
|
84
|
+
- ESM project support
|
|
85
|
+
|
|
86
|
+
- Provider API keys loaded from `.env`
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
Node 18 or newer is required because the SDK uses the native `fetch`, `ReadableStream`, and Web API primitives available in modern Node runtimes.
|
|
91
|
+
|
|
92
|
+
## Folder Structure
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
LUMORA/
|
|
96
|
+
├── examples/
|
|
97
|
+
│ ├── chat.ts
|
|
98
|
+
│ ├── custom-assistant.ts
|
|
99
|
+
│ ├── game-ai.ts
|
|
100
|
+
│ ├── providers.ts
|
|
101
|
+
│ └── streaming.ts
|
|
102
|
+
│
|
|
103
|
+
├── src/
|
|
104
|
+
│ ├── providers/
|
|
105
|
+
│ │ ├── base.ts
|
|
106
|
+
│ │ ├── gemini.ts
|
|
107
|
+
│ │ ├── openai.ts
|
|
108
|
+
│ │ └── xai.ts
|
|
109
|
+
│ │
|
|
110
|
+
│ ├── types/
|
|
111
|
+
│ │ ├── chat.ts
|
|
112
|
+
│ │ ├── game.ts
|
|
113
|
+
│ │ └── training.ts
|
|
114
|
+
│ │
|
|
115
|
+
│ ├── clients.ts
|
|
116
|
+
│ ├── env.ts
|
|
117
|
+
│ └── index.ts
|
|
118
|
+
│
|
|
119
|
+
├── .env
|
|
120
|
+
├── .env.example
|
|
121
|
+
├── .gitignore
|
|
122
|
+
├── package.json
|
|
123
|
+
├── package-lock.json
|
|
124
|
+
├── README.md
|
|
125
|
+
└── tsconfig.json
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
## Environment Configuration
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
Lumora always loads environment variables through `dotenv`. Create a `.env` file in your app root:
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
|
|
143
|
+
OPENAI_API_KEY=sk-your-openai-key
|
|
144
|
+
|
|
145
|
+
XAI_API_KEY=xai-your-xai-key
|
|
146
|
+
|
|
147
|
+
GEMINI_API_KEY=your-gemini-key
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
LUMORA_DEFAULT_PROVIDER=openai
|
|
152
|
+
|
|
153
|
+
LUMORA_DEFAULT_MODEL=gpt-4o-mini
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
Environment variables:
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
| Variable | Required | Description |
|
|
164
|
+
|
|
165
|
+
| --- | --- | --- |
|
|
166
|
+
|
|
167
|
+
| `OPENAI_API_KEY` | Required for OpenAI | Used by the default OpenAI provider. |
|
|
168
|
+
|
|
169
|
+
| `XAI_API_KEY` | Required for xAI | Used when `provider: "xai"` is selected. |
|
|
170
|
+
|
|
171
|
+
| `GEMINI_API_KEY` | Required for Gemini | Used when `provider: "gemini"` is selected. |
|
|
172
|
+
|
|
173
|
+
| `LUMORA_DEFAULT_PROVIDER` | Optional | One of `openai`, `xai`, or `gemini`. Defaults to `openai`. |
|
|
174
|
+
|
|
175
|
+
| `LUMORA_DEFAULT_MODEL` | Optional | Model used for the default provider when no request model is supplied. |
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
Provider-specific defaults are preserved. For example, if `LUMORA_DEFAULT_MODEL=gpt-4o-mini` and a request explicitly uses `provider: "gemini"`, the SDK uses Gemini's default model unless you pass a Gemini model manually.
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
## Quick Start
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
|
|
189
|
+
import "dotenv/config";
|
|
190
|
+
|
|
191
|
+
import { createLumoraClient } from "@asklumora/sdk";
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
const lumora = createLumoraClient();
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
const response = await lumora.chat({
|
|
200
|
+
|
|
201
|
+
messages: [
|
|
202
|
+
|
|
203
|
+
{
|
|
204
|
+
|
|
205
|
+
role: "system",
|
|
206
|
+
|
|
207
|
+
content: "You are Lumora, a precise and helpful assistant."
|
|
208
|
+
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
{
|
|
212
|
+
|
|
213
|
+
role: "user",
|
|
214
|
+
|
|
215
|
+
content: "Create a launch tagline for an AI game studio."
|
|
216
|
+
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
]
|
|
220
|
+
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
console.log(response.text);
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
## Client Initialization
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
The simplest client uses `.env`:
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
|
|
241
|
+
const lumora = createLumoraClient();
|
|
242
|
+
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
You can also override defaults in code:
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
|
|
253
|
+
const lumora = createLumoraClient({
|
|
254
|
+
|
|
255
|
+
defaultProvider: "openai",
|
|
256
|
+
|
|
257
|
+
defaultModel: "gpt-4o-mini"
|
|
258
|
+
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
API keys can be injected programmatically, although `.env` is recommended for normal application use:
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
|
|
271
|
+
const lumora = createLumoraClient({
|
|
272
|
+
|
|
273
|
+
apiKeys: {
|
|
274
|
+
|
|
275
|
+
openai: process.env.OPENAI_API_KEY,
|
|
276
|
+
|
|
277
|
+
xai: process.env.XAI_API_KEY,
|
|
278
|
+
|
|
279
|
+
gemini: process.env.GEMINI_API_KEY
|
|
280
|
+
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
## Chat API
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
`chat()` accepts a provider-independent request and returns normalized text output plus the raw provider response.
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
```ts
|
|
298
|
+
|
|
299
|
+
const result = await lumora.chat({
|
|
300
|
+
|
|
301
|
+
provider: "openai",
|
|
302
|
+
|
|
303
|
+
model: "gpt-4o-mini",
|
|
304
|
+
|
|
305
|
+
temperature: 0.4,
|
|
306
|
+
|
|
307
|
+
maxTokens: 600,
|
|
308
|
+
|
|
309
|
+
messages: [
|
|
310
|
+
|
|
311
|
+
{ role: "system", content: "Answer as a senior product engineer." },
|
|
312
|
+
|
|
313
|
+
{ role: "user", content: "Design an AI support workflow for a SaaS app." }
|
|
314
|
+
|
|
315
|
+
],
|
|
316
|
+
|
|
317
|
+
metadata: {
|
|
318
|
+
|
|
319
|
+
requestId: "support-workflow-001"
|
|
320
|
+
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
console.log(result.provider);
|
|
328
|
+
|
|
329
|
+
console.log(result.model);
|
|
330
|
+
|
|
331
|
+
console.log(result.text);
|
|
332
|
+
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
Request shape:
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
```ts
|
|
342
|
+
|
|
343
|
+
interface LumoraChatRequest {
|
|
344
|
+
|
|
345
|
+
messages: LumoraMessage[];
|
|
346
|
+
|
|
347
|
+
model?: string;
|
|
348
|
+
|
|
349
|
+
provider?: "openai" | "xai" | "gemini";
|
|
350
|
+
|
|
351
|
+
temperature?: number;
|
|
352
|
+
|
|
353
|
+
maxTokens?: number;
|
|
354
|
+
|
|
355
|
+
tools?: LumoraTool[];
|
|
356
|
+
|
|
357
|
+
memory?: LumoraMemoryEntry[];
|
|
358
|
+
|
|
359
|
+
metadata?: Record<string, unknown>;
|
|
360
|
+
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
Response shape:
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
```ts
|
|
372
|
+
|
|
373
|
+
interface LumoraChatResponse {
|
|
374
|
+
|
|
375
|
+
provider: "openai" | "xai" | "gemini";
|
|
376
|
+
|
|
377
|
+
model: string;
|
|
378
|
+
|
|
379
|
+
text: string;
|
|
380
|
+
|
|
381
|
+
toolCalls?: LumoraToolCall[];
|
|
382
|
+
|
|
383
|
+
raw?: unknown;
|
|
384
|
+
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
## Streaming API
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
`streamChat()` returns an async iterable. Each yielded chunk contains normalized text and provider metadata.
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
```ts
|
|
400
|
+
|
|
401
|
+
for await (const chunk of lumora.streamChat({
|
|
402
|
+
|
|
403
|
+
messages: [
|
|
404
|
+
|
|
405
|
+
{ role: "user", content: "Brainstorm five game mechanics using AI companions." }
|
|
406
|
+
|
|
407
|
+
]
|
|
408
|
+
|
|
409
|
+
})) {
|
|
410
|
+
|
|
411
|
+
process.stdout.write(chunk.text);
|
|
412
|
+
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
Chunk shape:
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
```ts
|
|
424
|
+
|
|
425
|
+
interface LumoraStreamChunk {
|
|
426
|
+
|
|
427
|
+
provider: "openai" | "xai" | "gemini";
|
|
428
|
+
|
|
429
|
+
model: string;
|
|
430
|
+
|
|
431
|
+
text: string;
|
|
432
|
+
|
|
433
|
+
done: boolean;
|
|
434
|
+
|
|
435
|
+
raw?: unknown;
|
|
436
|
+
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
## Provider Selection
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
OpenAI is the default:
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
```ts
|
|
452
|
+
|
|
453
|
+
await lumora.chat({
|
|
454
|
+
|
|
455
|
+
messages: [{ role: "user", content: "Use the default provider." }]
|
|
456
|
+
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
Select a provider per request:
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
```ts
|
|
468
|
+
|
|
469
|
+
await lumora.chat({
|
|
470
|
+
|
|
471
|
+
provider: "xai",
|
|
472
|
+
|
|
473
|
+
messages: [{ role: "user", content: "Use xAI for this request." }]
|
|
474
|
+
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
await lumora.chat({
|
|
480
|
+
|
|
481
|
+
provider: "gemini",
|
|
482
|
+
|
|
483
|
+
model: "gemini-1.5-flash",
|
|
484
|
+
|
|
485
|
+
messages: [{ role: "user", content: "Use Gemini for this request." }]
|
|
486
|
+
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
Built-in provider defaults:
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
| Provider | Default Model | API Base |
|
|
498
|
+
|
|
499
|
+
| --- | --- | --- |
|
|
500
|
+
|
|
501
|
+
| OpenAI | `gpt-4o-mini` | `https://api.openai.com/v1` |
|
|
502
|
+
|
|
503
|
+
| xAI | `grok-2-latest` | `https://api.x.ai/v1` |
|
|
504
|
+
|
|
505
|
+
| Gemini | `gemini-1.5-flash` | `https://generativelanguage.googleapis.com/v1beta` |
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
## Custom Provider Injection
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
You can register your own provider implementation if you want to proxy requests, add telemetry, or support another model API.
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
```ts
|
|
518
|
+
|
|
519
|
+
import type {
|
|
520
|
+
|
|
521
|
+
LumoraProvider,
|
|
522
|
+
|
|
523
|
+
LumoraChatRequest,
|
|
524
|
+
|
|
525
|
+
LumoraChatResponse,
|
|
526
|
+
|
|
527
|
+
LumoraStreamChunk
|
|
528
|
+
|
|
529
|
+
} from "@asklumora/sdk";
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
const customProvider: LumoraProvider = {
|
|
534
|
+
|
|
535
|
+
name: "openai",
|
|
536
|
+
|
|
537
|
+
defaultModel: "my-proxied-model",
|
|
538
|
+
|
|
539
|
+
async chat(request: LumoraChatRequest): Promise<LumoraChatResponse> {
|
|
540
|
+
|
|
541
|
+
return {
|
|
542
|
+
|
|
543
|
+
provider: "openai",
|
|
544
|
+
|
|
545
|
+
model: request.model ?? "my-proxied-model",
|
|
546
|
+
|
|
547
|
+
text: "Response from my custom provider."
|
|
548
|
+
|
|
549
|
+
};
|
|
550
|
+
|
|
551
|
+
},
|
|
552
|
+
|
|
553
|
+
async *streamChat(): AsyncIterable<LumoraStreamChunk> {
|
|
554
|
+
|
|
555
|
+
yield {
|
|
556
|
+
|
|
557
|
+
provider: "openai",
|
|
558
|
+
|
|
559
|
+
model: "my-proxied-model",
|
|
560
|
+
|
|
561
|
+
text: "Streaming response from my custom provider.",
|
|
562
|
+
|
|
563
|
+
done: false
|
|
564
|
+
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
yield {
|
|
568
|
+
|
|
569
|
+
provider: "openai",
|
|
570
|
+
|
|
571
|
+
model: "my-proxied-model",
|
|
572
|
+
|
|
573
|
+
text: "",
|
|
574
|
+
|
|
575
|
+
done: true
|
|
576
|
+
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
const lumora = createLumoraClient({
|
|
586
|
+
|
|
587
|
+
providers: {
|
|
588
|
+
|
|
589
|
+
openai: customProvider
|
|
590
|
+
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
## Long-Term Memory
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
Memory entries are injected into the system context before each chat request.
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
|
|
607
|
+
```ts
|
|
608
|
+
|
|
609
|
+
lumora.remember({
|
|
610
|
+
|
|
611
|
+
content: "The user prefers concise technical explanations.",
|
|
612
|
+
|
|
613
|
+
importance: 0.8,
|
|
614
|
+
|
|
615
|
+
metadata: {
|
|
616
|
+
|
|
617
|
+
source: "profile"
|
|
618
|
+
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
const answer = await lumora.chat({
|
|
626
|
+
|
|
627
|
+
messages: [
|
|
628
|
+
|
|
629
|
+
{ role: "user", content: "Explain embeddings in one paragraph." }
|
|
630
|
+
|
|
631
|
+
]
|
|
632
|
+
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
|
|
638
|
+
|
|
639
|
+
Per-request memory is also supported:
|
|
640
|
+
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
```ts
|
|
644
|
+
|
|
645
|
+
await lumora.chat({
|
|
646
|
+
|
|
647
|
+
memory: [
|
|
648
|
+
|
|
649
|
+
{
|
|
650
|
+
|
|
651
|
+
content: "The current project is a fantasy RPG with persistent NPC relationships."
|
|
652
|
+
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
],
|
|
656
|
+
|
|
657
|
+
messages: [
|
|
658
|
+
|
|
659
|
+
{ role: "user", content: "Generate a companion greeting." }
|
|
660
|
+
|
|
661
|
+
]
|
|
662
|
+
|
|
663
|
+
});
|
|
664
|
+
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
|
|
668
|
+
|
|
669
|
+
## Tool Calling Types
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
|
|
673
|
+
The SDK exposes provider-independent tool definitions. OpenAI-compatible tools are sent as function tools.
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
|
|
677
|
+
```ts
|
|
678
|
+
|
|
679
|
+
const response = await lumora.chat({
|
|
680
|
+
|
|
681
|
+
provider: "openai",
|
|
682
|
+
|
|
683
|
+
tools: [
|
|
684
|
+
|
|
685
|
+
{
|
|
686
|
+
|
|
687
|
+
name: "search_inventory",
|
|
688
|
+
|
|
689
|
+
description: "Search product inventory by SKU or keyword.",
|
|
690
|
+
|
|
691
|
+
parameters: {
|
|
692
|
+
|
|
693
|
+
type: "object",
|
|
694
|
+
|
|
695
|
+
properties: {
|
|
696
|
+
|
|
697
|
+
query: {
|
|
698
|
+
|
|
699
|
+
type: "string"
|
|
700
|
+
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
},
|
|
704
|
+
|
|
705
|
+
required: ["query"]
|
|
706
|
+
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
],
|
|
712
|
+
|
|
713
|
+
messages: [
|
|
714
|
+
|
|
715
|
+
{ role: "user", content: "Find waterproof boots under $150." }
|
|
716
|
+
|
|
717
|
+
]
|
|
718
|
+
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
|
|
722
|
+
|
|
723
|
+
console.log(response.toolCalls);
|
|
724
|
+
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
|
|
728
|
+
|
|
729
|
+
## Custom AI Assistants
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
|
|
733
|
+
Lumora includes a typed assistant layer for domain-specific behavior. This is useful when you want an application-level assistant object that carries instructions, knowledge references, tools, and provider settings.
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
|
|
737
|
+
```ts
|
|
738
|
+
|
|
739
|
+
const assistant = lumora.createAssistant({
|
|
740
|
+
|
|
741
|
+
name: "Retail Support Assistant",
|
|
742
|
+
|
|
743
|
+
instructions: "Answer using the provided business knowledge. Be accurate and concise.",
|
|
744
|
+
|
|
745
|
+
provider: "openai",
|
|
746
|
+
|
|
747
|
+
knowledge: [
|
|
748
|
+
|
|
749
|
+
{
|
|
750
|
+
|
|
751
|
+
type: "document",
|
|
752
|
+
|
|
753
|
+
name: "Support Handbook",
|
|
754
|
+
|
|
755
|
+
content: "Unused items can be returned within 30 days with proof of purchase."
|
|
756
|
+
|
|
757
|
+
},
|
|
758
|
+
|
|
759
|
+
{
|
|
760
|
+
|
|
761
|
+
type: "website",
|
|
762
|
+
|
|
763
|
+
name: "Help Center",
|
|
764
|
+
|
|
765
|
+
url: "https://example.com/help"
|
|
766
|
+
|
|
767
|
+
},
|
|
768
|
+
|
|
769
|
+
{
|
|
770
|
+
|
|
771
|
+
type: "dataset",
|
|
772
|
+
|
|
773
|
+
name: "Product Catalog",
|
|
774
|
+
|
|
775
|
+
content: "SKU-1001: Waterproof hiking boot. SKU-1002: Lightweight trail shoe."
|
|
776
|
+
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
],
|
|
780
|
+
|
|
781
|
+
tools: ["search_inventory", "create_return_label"],
|
|
782
|
+
|
|
783
|
+
metadata: {
|
|
784
|
+
|
|
785
|
+
tenantId: "tenant_123"
|
|
786
|
+
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
});
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
|
|
793
|
+
const answer = await lumora.chatWithAssistant(
|
|
794
|
+
|
|
795
|
+
assistant,
|
|
796
|
+
|
|
797
|
+
"Can I return hiking boots after two weeks?"
|
|
798
|
+
|
|
799
|
+
);
|
|
800
|
+
|
|
801
|
+
```
|
|
802
|
+
|
|
803
|
+
|
|
804
|
+
|
|
805
|
+
Knowledge source types:
|
|
806
|
+
|
|
807
|
+
|
|
808
|
+
|
|
809
|
+
| Type | Use Case |
|
|
810
|
+
|
|
811
|
+
| --- | --- |
|
|
812
|
+
|
|
813
|
+
| `document` | Uploaded manuals, PDFs, handbooks, support docs. |
|
|
814
|
+
|
|
815
|
+
| `website` | Public docs, help centers, knowledge base URLs. |
|
|
816
|
+
|
|
817
|
+
| `dataset` | Structured business data, catalogs, CSV-derived content. |
|
|
818
|
+
|
|
819
|
+
| `text` | Direct inline context. |
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
|
|
823
|
+
## AI for Games
|
|
824
|
+
|
|
825
|
+
|
|
826
|
+
|
|
827
|
+
Lumora has game-specific helpers for NPC dialogue and quest generation.
|
|
828
|
+
|
|
829
|
+
|
|
830
|
+
|
|
831
|
+
### NPC Dialogue
|
|
832
|
+
|
|
833
|
+
|
|
834
|
+
|
|
835
|
+
```ts
|
|
836
|
+
|
|
837
|
+
const dialogue = await lumora.npcDialogue({
|
|
838
|
+
|
|
839
|
+
character: {
|
|
840
|
+
|
|
841
|
+
id: "blacksmith-mira",
|
|
842
|
+
|
|
843
|
+
name: "Mira",
|
|
844
|
+
|
|
845
|
+
description: "A village blacksmith who remembers every blade she has forged.",
|
|
846
|
+
|
|
847
|
+
personality: "Warm, direct, and protective of the town.",
|
|
848
|
+
|
|
849
|
+
memory: [
|
|
850
|
+
|
|
851
|
+
{
|
|
852
|
+
|
|
853
|
+
content: "The player saved Mira's apprentice from the old mine."
|
|
854
|
+
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
]
|
|
858
|
+
|
|
859
|
+
},
|
|
860
|
+
|
|
861
|
+
context: {
|
|
862
|
+
|
|
863
|
+
world: "A coastal fantasy kingdom where storms reveal ancient ruins.",
|
|
864
|
+
|
|
865
|
+
scene: "The player enters Mira's forge at midnight.",
|
|
866
|
+
|
|
867
|
+
lore: [
|
|
868
|
+
|
|
869
|
+
"The lighthouse bell rings when sea spirits are near."
|
|
870
|
+
|
|
871
|
+
]
|
|
872
|
+
|
|
873
|
+
},
|
|
874
|
+
|
|
875
|
+
playerMessage: "I need a weapon before the tide rises."
|
|
876
|
+
|
|
877
|
+
});
|
|
878
|
+
|
|
879
|
+
|
|
880
|
+
|
|
881
|
+
console.log(dialogue.text);
|
|
882
|
+
|
|
883
|
+
```
|
|
884
|
+
|
|
885
|
+
|
|
886
|
+
|
|
887
|
+
### Dynamic Quest Generation
|
|
888
|
+
|
|
889
|
+
|
|
890
|
+
|
|
891
|
+
```ts
|
|
892
|
+
|
|
893
|
+
const quest = await lumora.generateQuest({
|
|
894
|
+
|
|
895
|
+
context: {
|
|
896
|
+
|
|
897
|
+
world: "A post-collapse city where factions control old transit tunnels.",
|
|
898
|
+
|
|
899
|
+
player: "Level 12 engineer with stealth upgrades.",
|
|
900
|
+
|
|
901
|
+
questState: {
|
|
902
|
+
|
|
903
|
+
factionTrust: "neutral",
|
|
904
|
+
|
|
905
|
+
discoveredTunnelMap: true
|
|
906
|
+
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
},
|
|
910
|
+
|
|
911
|
+
objective: "Create a morally ambiguous rescue mission."
|
|
912
|
+
|
|
913
|
+
});
|
|
914
|
+
|
|
915
|
+
|
|
916
|
+
|
|
917
|
+
console.log(quest.text);
|
|
918
|
+
|
|
919
|
+
```
|
|
920
|
+
|
|
921
|
+
|
|
922
|
+
|
|
923
|
+
## Error Handling
|
|
924
|
+
|
|
925
|
+
|
|
926
|
+
|
|
927
|
+
Provider failures throw `LumoraProviderError`.
|
|
928
|
+
|
|
929
|
+
|
|
930
|
+
|
|
931
|
+
```ts
|
|
932
|
+
|
|
933
|
+
import { LumoraProviderError } from "@asklumora/sdk";
|
|
934
|
+
|
|
935
|
+
|
|
936
|
+
|
|
937
|
+
try {
|
|
938
|
+
|
|
939
|
+
await lumora.chat({
|
|
940
|
+
|
|
941
|
+
provider: "gemini",
|
|
942
|
+
|
|
943
|
+
messages: [{ role: "user", content: "Hello." }]
|
|
944
|
+
|
|
945
|
+
});
|
|
946
|
+
|
|
947
|
+
} catch (error) {
|
|
948
|
+
|
|
949
|
+
if (error instanceof LumoraProviderError) {
|
|
950
|
+
|
|
951
|
+
console.error(error.provider);
|
|
952
|
+
|
|
953
|
+
console.error(error.status);
|
|
954
|
+
|
|
955
|
+
console.error(error.details);
|
|
956
|
+
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
|
|
960
|
+
|
|
961
|
+
throw error;
|
|
962
|
+
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
```
|
|
966
|
+
|
|
967
|
+
|
|
968
|
+
|
|
969
|
+
Common causes:
|
|
970
|
+
|
|
971
|
+
|
|
972
|
+
|
|
973
|
+
- Missing provider API key in `.env`
|
|
974
|
+
|
|
975
|
+
- Invalid model name for the selected provider
|
|
976
|
+
|
|
977
|
+
- Provider-side rate limit or quota error
|
|
978
|
+
|
|
979
|
+
- Network failure between your runtime and the provider API
|
|
980
|
+
|
|
981
|
+
- Passing an OpenAI model while explicitly selecting Gemini or xAI
|
|
982
|
+
|
|
983
|
+
|
|
984
|
+
|
|
985
|
+
## Running Examples
|
|
986
|
+
|
|
987
|
+
|
|
988
|
+
|
|
989
|
+
Install dependencies and build:
|
|
990
|
+
|
|
991
|
+
|
|
992
|
+
|
|
993
|
+
```bash
|
|
994
|
+
|
|
995
|
+
npm install
|
|
996
|
+
|
|
997
|
+
npm run build
|
|
998
|
+
|
|
999
|
+
```
|
|
1000
|
+
|
|
1001
|
+
|
|
1002
|
+
|
|
1003
|
+
Run examples from a Unix-like shell:
|
|
1004
|
+
|
|
1005
|
+
|
|
1006
|
+
|
|
1007
|
+
```bash
|
|
1008
|
+
|
|
1009
|
+
node ./dist/examples/chat.js
|
|
1010
|
+
|
|
1011
|
+
node ./dist/examples/streaming.js
|
|
1012
|
+
|
|
1013
|
+
node ./dist/examples/providers.js
|
|
1014
|
+
|
|
1015
|
+
node ./dist/examples/game-ai.js
|
|
1016
|
+
|
|
1017
|
+
node ./dist/examples/custom-assistant.js
|
|
1018
|
+
|
|
1019
|
+
```
|
|
1020
|
+
|
|
1021
|
+
|
|
1022
|
+
|
|
1023
|
+
Run examples from PowerShell:
|
|
1024
|
+
|
|
1025
|
+
|
|
1026
|
+
|
|
1027
|
+
```powershell
|
|
1028
|
+
|
|
1029
|
+
node .\dist\examples\chat.js
|
|
1030
|
+
|
|
1031
|
+
node .\dist\examples\streaming.js
|
|
1032
|
+
|
|
1033
|
+
node .\dist\examples\providers.js
|
|
1034
|
+
|
|
1035
|
+
node .\dist\examples\game-ai.js
|
|
1036
|
+
|
|
1037
|
+
node .\dist\examples\custom-assistant.js
|
|
1038
|
+
|
|
1039
|
+
```
|
|
1040
|
+
|
|
1041
|
+
|
|
1042
|
+
|
|
1043
|
+
## Project Structure
|
|
1044
|
+
|
|
1045
|
+
|
|
1046
|
+
|
|
1047
|
+
```text
|
|
1048
|
+
|
|
1049
|
+
src/
|
|
1050
|
+
|
|
1051
|
+
client.ts Main LumoraSDK client and high-level workflows
|
|
1052
|
+
|
|
1053
|
+
env.ts dotenv loading and environment validation helpers
|
|
1054
|
+
|
|
1055
|
+
index.ts Public package exports
|
|
1056
|
+
|
|
1057
|
+
providers/
|
|
1058
|
+
|
|
1059
|
+
base.ts Provider contract and provider error type
|
|
1060
|
+
|
|
1061
|
+
gemini.ts Gemini REST adapter
|
|
1062
|
+
|
|
1063
|
+
openai.ts OpenAI chat and streaming adapter
|
|
1064
|
+
|
|
1065
|
+
xai.ts xAI chat and streaming adapter
|
|
1066
|
+
|
|
1067
|
+
types/
|
|
1068
|
+
|
|
1069
|
+
chat.ts Chat, streaming, memory, and tool types
|
|
1070
|
+
|
|
1071
|
+
game.ts NPC and quest generation types
|
|
1072
|
+
|
|
1073
|
+
training.ts Assistant and knowledge source types
|
|
1074
|
+
|
|
1075
|
+
examples/
|
|
1076
|
+
|
|
1077
|
+
chat.ts Basic chat example
|
|
1078
|
+
|
|
1079
|
+
custom-assistant.ts Domain assistant example
|
|
1080
|
+
|
|
1081
|
+
game-ai.ts NPC dialogue example
|
|
1082
|
+
|
|
1083
|
+
providers.ts Multi-provider example
|
|
1084
|
+
|
|
1085
|
+
streaming.ts Streaming response example
|
|
1086
|
+
|
|
1087
|
+
```
|
|
1088
|
+
|
|
1089
|
+
|
|
1090
|
+
|
|
1091
|
+
## Build and Typecheck
|
|
1092
|
+
|
|
1093
|
+
|
|
1094
|
+
|
|
1095
|
+
```bash
|
|
1096
|
+
|
|
1097
|
+
npm run typecheck
|
|
1098
|
+
|
|
1099
|
+
npm run build
|
|
1100
|
+
|
|
1101
|
+
```
|
|
1102
|
+
|
|
1103
|
+
|
|
1104
|
+
|
|
1105
|
+
The package emits ESM JavaScript and TypeScript declarations into `dist/`.
|
|
1106
|
+
|
|
1107
|
+
|
|
1108
|
+
|
|
1109
|
+
```text
|
|
1110
|
+
|
|
1111
|
+
dist/
|
|
1112
|
+
├── src/
|
|
1113
|
+
├── examples/
|
|
1114
|
+
│ └── chat.js
|
|
1115
|
+
├── index.js
|
|
1116
|
+
└── index.d.ts
|
|
1117
|
+
|
|
1118
|
+
```
|
|
1119
|
+
|
|
1120
|
+
|
|
1121
|
+
|
|
1122
|
+
## Publishing Checklist
|
|
1123
|
+
|
|
1124
|
+
|
|
1125
|
+
|
|
1126
|
+
Before publishing `@asklumora/sdk`:
|
|
1127
|
+
|
|
1128
|
+
|
|
1129
|
+
|
|
1130
|
+
1. Confirm `package.json` version is correct.
|
|
1131
|
+
|
|
1132
|
+
2. Run `npm run typecheck`.
|
|
1133
|
+
|
|
1134
|
+
3. Run `npm run build`.
|
|
1135
|
+
|
|
1136
|
+
4. Inspect package contents with `npm pack --dry-run`.
|
|
1137
|
+
|
|
1138
|
+
5. Publish with `npm publish --access public`.
|
|
1139
|
+
|
|
1140
|
+
|
|
1141
|
+
|
|
1142
|
+
## Security Notes
|
|
1143
|
+
|
|
1144
|
+
|
|
1145
|
+
|
|
1146
|
+
- Never commit `.env` files.
|
|
1147
|
+
|
|
1148
|
+
- Use separate API keys for development, staging, and production.
|
|
1149
|
+
|
|
1150
|
+
- Route browser or mobile requests through your own backend if you need to protect provider keys.
|
|
1151
|
+
|
|
1152
|
+
- Treat uploaded documents, website content, datasets, and tool outputs as untrusted application data.
|
|
1153
|
+
|
|
1154
|
+
- Log provider errors carefully so raw responses do not leak user content or credentials.
|
|
1155
|
+
|
|
1156
|
+
|
|
1157
|
+
|
|
1158
|
+
## Current Scope
|
|
1159
|
+
|
|
1160
|
+
|
|
1161
|
+
|
|
1162
|
+
This SDK provides a typed provider abstraction and high-level Lumora workflows. It does not currently persist assistants, upload files to provider-specific fine-tuning APIs, manage vector indexes, or store long-term memory outside the current client instance. Those features can be layered behind the existing assistant, knowledge source, and provider interfaces.
|