@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.
Files changed (67) hide show
  1. package/README.md +1162 -0
  2. package/dist/examples/chat.d.ts +2 -0
  3. package/dist/examples/chat.d.ts.map +1 -0
  4. package/dist/examples/chat.js +17 -0
  5. package/dist/examples/chat.js.map +1 -0
  6. package/dist/examples/custom-assistant.d.ts +2 -0
  7. package/dist/examples/custom-assistant.d.ts.map +1 -0
  8. package/dist/examples/custom-assistant.js +22 -0
  9. package/dist/examples/custom-assistant.js.map +1 -0
  10. package/dist/examples/game-ai.d.ts +2 -0
  11. package/dist/examples/game-ai.d.ts.map +1 -0
  12. package/dist/examples/game-ai.js +24 -0
  13. package/dist/examples/game-ai.js.map +1 -0
  14. package/dist/examples/providers.d.ts +2 -0
  15. package/dist/examples/providers.d.ts.map +1 -0
  16. package/dist/examples/providers.js +17 -0
  17. package/dist/examples/providers.js.map +1 -0
  18. package/dist/examples/streaming.d.ts +2 -0
  19. package/dist/examples/streaming.d.ts.map +1 -0
  20. package/dist/examples/streaming.js +10 -0
  21. package/dist/examples/streaming.js.map +1 -0
  22. package/dist/src/client.d.ts +34 -0
  23. package/dist/src/client.d.ts.map +1 -0
  24. package/dist/src/client.js +154 -0
  25. package/dist/src/client.js.map +1 -0
  26. package/dist/src/env.d.ts +11 -0
  27. package/dist/src/env.d.ts.map +1 -0
  28. package/dist/src/env.js +24 -0
  29. package/dist/src/env.js.map +1 -0
  30. package/dist/src/index.d.ts +11 -0
  31. package/dist/src/index.d.ts.map +1 -0
  32. package/dist/src/index.js +6 -0
  33. package/dist/src/index.js.map +1 -0
  34. package/dist/src/providers/base.d.ts +14 -0
  35. package/dist/src/providers/base.d.ts.map +1 -0
  36. package/dist/src/providers/base.js +13 -0
  37. package/dist/src/providers/base.js.map +1 -0
  38. package/dist/src/providers/gemini.d.ts +18 -0
  39. package/dist/src/providers/gemini.d.ts.map +1 -0
  40. package/dist/src/providers/gemini.js +102 -0
  41. package/dist/src/providers/gemini.js.map +1 -0
  42. package/dist/src/providers/openai.d.ts +19 -0
  43. package/dist/src/providers/openai.d.ts.map +1 -0
  44. package/dist/src/providers/openai.js +132 -0
  45. package/dist/src/providers/openai.js.map +1 -0
  46. package/dist/src/providers/xai.d.ts +19 -0
  47. package/dist/src/providers/xai.d.ts.map +1 -0
  48. package/dist/src/providers/xai.js +105 -0
  49. package/dist/src/providers/xai.js.map +1 -0
  50. package/dist/src/types/chat.d.ts +50 -0
  51. package/dist/src/types/chat.d.ts.map +1 -0
  52. package/dist/src/types/chat.js +2 -0
  53. package/dist/src/types/chat.js.map +1 -0
  54. package/dist/src/types/game.d.ts +30 -0
  55. package/dist/src/types/game.d.ts.map +1 -0
  56. package/dist/src/types/game.js +2 -0
  57. package/dist/src/types/game.js.map +1 -0
  58. package/dist/src/types/training.d.ts +28 -0
  59. package/dist/src/types/training.d.ts.map +1 -0
  60. package/dist/src/types/training.js +2 -0
  61. package/dist/src/types/training.js.map +1 -0
  62. package/examples/chat.ts +19 -0
  63. package/examples/custom-assistant.ts +25 -0
  64. package/examples/game-ai.ts +26 -0
  65. package/examples/providers.ts +21 -0
  66. package/examples/streaming.ts +12 -0
  67. package/package.json +46 -0
package/README.md ADDED
@@ -0,0 +1,1162 @@
1
+
2
+ # Lumora TypeScript SDK
3
+
4
+ ![enter image description here](https://olive-chemical-haddock-701.mypinata.cloud/ipfs/bafkreiejroy5o6reqsby3ds4mozzxu37tnirjiso2u47bb45evhijz3imy)
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.