@burtson-labs/bandit-engine 2.0.8
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/LICENSE +43 -0
- package/README.md +1235 -0
- package/dist/aiProviderStore-YWJHSWFA.mjs +9 -0
- package/dist/aiProviderStore-YWJHSWFA.mjs.map +1 -0
- package/dist/chat-QXB526NZ.mjs +11 -0
- package/dist/chat-QXB526NZ.mjs.map +1 -0
- package/dist/chunk-AVC6IZJQ.mjs +2157 -0
- package/dist/chunk-AVC6IZJQ.mjs.map +1 -0
- package/dist/chunk-BIPELT57.mjs +24183 -0
- package/dist/chunk-BIPELT57.mjs.map +1 -0
- package/dist/chunk-BJTO5JO5.mjs +11 -0
- package/dist/chunk-BJTO5JO5.mjs.map +1 -0
- package/dist/chunk-IXIM7BNO.mjs +39 -0
- package/dist/chunk-IXIM7BNO.mjs.map +1 -0
- package/dist/chunk-KCI46M23.mjs +106 -0
- package/dist/chunk-KCI46M23.mjs.map +1 -0
- package/dist/chunk-WYS5CZVG.mjs +843 -0
- package/dist/chunk-WYS5CZVG.mjs.map +1 -0
- package/dist/cli/cli.js +1808 -0
- package/dist/cli/cli.js.map +1 -0
- package/dist/index.d.mts +1636 -0
- package/dist/index.d.ts +1636 -0
- package/dist/index.js +40601 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +12477 -0
- package/dist/index.mjs.map +1 -0
- package/dist/memoryUtils-33TZKHSQ.mjs +223 -0
- package/dist/memoryUtils-33TZKHSQ.mjs.map +1 -0
- package/dist/modelStore-Y3LZWRQC.mjs +9 -0
- package/dist/modelStore-Y3LZWRQC.mjs.map +1 -0
- package/dist/shared/custom-element.js +73 -0
- package/dist/shared/custom-element.js.map +1 -0
- package/dist/shared/custom-element.mjs +8 -0
- package/dist/shared/custom-element.mjs.map +1 -0
- package/docs/00_intro.md +26 -0
- package/docs/01_quickstart.md +54 -0
- package/docs/02_gateway_api.md +64 -0
- package/docs/03_provider_integration.md +38 -0
- package/docs/04_local_dev.md +43 -0
- package/docs/05_cli_quickstart.md +89 -0
- package/docs/05_contributing.md +33 -0
- package/docs/06_busl_licensing.md +25 -0
- package/docs/README.md +9 -0
- package/docs/api_reference/.nojekyll +1 -0
- package/docs/api_reference/assets/highlight.css +141 -0
- package/docs/api_reference/assets/icons.js +18 -0
- package/docs/api_reference/assets/icons.svg +1 -0
- package/docs/api_reference/assets/main.js +60 -0
- package/docs/api_reference/assets/navigation.js +1 -0
- package/docs/api_reference/assets/search.js +1 -0
- package/docs/api_reference/assets/style.css +1493 -0
- package/docs/api_reference/classes/DebugLogger.html +29 -0
- package/docs/api_reference/classes/FeatureFlagService.html +28 -0
- package/docs/api_reference/classes/NotificationService.html +21 -0
- package/docs/api_reference/classes/StreamingTTSClient.html +19 -0
- package/docs/api_reference/classes/VectorDatabaseService.html +63 -0
- package/docs/api_reference/classes/VectorMigrationService.html +27 -0
- package/docs/api_reference/classes/VoiceService.html +4 -0
- package/docs/api_reference/enums/TTSState.html +6 -0
- package/docs/api_reference/functions/Chat.html +1 -0
- package/docs/api_reference/functions/ChatModal.html +29 -0
- package/docs/api_reference/functions/ChatProvider.html +29 -0
- package/docs/api_reference/functions/FeatureFlagProvider.html +30 -0
- package/docs/api_reference/functions/FeedbackButton.html +29 -0
- package/docs/api_reference/functions/FeedbackModal.html +29 -0
- package/docs/api_reference/functions/Management.html +1 -0
- package/docs/api_reference/functions/NotificationProvider.html +29 -0
- package/docs/api_reference/functions/SubscriptionExpiredGuard.html +31 -0
- package/docs/api_reference/functions/SubscriptionExpiredModal.html +31 -0
- package/docs/api_reference/functions/defineCustomElement.html +1 -0
- package/docs/api_reference/functions/getCriticalConfig.html +1 -0
- package/docs/api_reference/functions/getFeatureMatrix.html +1 -0
- package/docs/api_reference/functions/getStreamingTTSClient.html +1 -0
- package/docs/api_reference/functions/getSystemConstants.html +1 -0
- package/docs/api_reference/functions/getTTSState.html +1 -0
- package/docs/api_reference/functions/handleHttpError.html +2 -0
- package/docs/api_reference/functions/handleSubscriptionUpgrade.html +1 -0
- package/docs/api_reference/functions/handleValidationError.html +2 -0
- package/docs/api_reference/functions/initializeCoreSystem.html +1 -0
- package/docs/api_reference/functions/pauseTTS.html +1 -0
- package/docs/api_reference/functions/previewTierUpgrade.html +1 -0
- package/docs/api_reference/functions/resumeTTS.html +1 -0
- package/docs/api_reference/functions/showInfoNotification.html +2 -0
- package/docs/api_reference/functions/showSuccessNotification.html +2 -0
- package/docs/api_reference/functions/speakWithStreaming.html +1 -0
- package/docs/api_reference/functions/stopTTS.html +1 -0
- package/docs/api_reference/functions/syncSubscriptionWithAPI.html +1 -0
- package/docs/api_reference/functions/updateSubscriptionTier.html +2 -0
- package/docs/api_reference/functions/useFeatureFlag.html +2 -0
- package/docs/api_reference/functions/useFeatureVisibility.html +2 -0
- package/docs/api_reference/functions/useFeatures.html +2 -0
- package/docs/api_reference/functions/useGatewayHealth.html +1 -0
- package/docs/api_reference/functions/useGatewayMemory.html +1 -0
- package/docs/api_reference/functions/useGatewayModels.html +1 -0
- package/docs/api_reference/functions/useGlobalTTS.html +2 -0
- package/docs/api_reference/functions/useNotification.html +1 -0
- package/docs/api_reference/functions/useNotificationService.html +6 -0
- package/docs/api_reference/functions/useTTS.html +2 -0
- package/docs/api_reference/functions/useVectorStore.html +13 -0
- package/docs/api_reference/functions/useVoiceStore.html +8 -0
- package/docs/api_reference/functions/useVoices.html +3 -0
- package/docs/api_reference/functions/validateEnvironment.html +1 -0
- package/docs/api_reference/functions/validateSystemIntegrity.html +1 -0
- package/docs/api_reference/index.html +756 -0
- package/docs/api_reference/interfaces/AIChatRequest.html +8 -0
- package/docs/api_reference/interfaces/AIChatResponse.html +3 -0
- package/docs/api_reference/interfaces/AIGenerateRequest.html +5 -0
- package/docs/api_reference/interfaces/AIGenerateResponse.html +3 -0
- package/docs/api_reference/interfaces/AIMessage.html +4 -0
- package/docs/api_reference/interfaces/AIModel.html +6 -0
- package/docs/api_reference/interfaces/AIProviderConfig.html +9 -0
- package/docs/api_reference/interfaces/ChatConfig.html +5 -0
- package/docs/api_reference/interfaces/CreateMemoryOptions.html +7 -0
- package/docs/api_reference/interfaces/FeatureEvaluation.html +14 -0
- package/docs/api_reference/interfaces/FeatureFlagConfig.html +18 -0
- package/docs/api_reference/interfaces/FeatureFlagContextValue.html +16 -0
- package/docs/api_reference/interfaces/FeatureFlagProviderProps.html +4 -0
- package/docs/api_reference/interfaces/FeedbackButtonProps.html +19 -0
- package/docs/api_reference/interfaces/FeedbackCategories.html +6 -0
- package/docs/api_reference/interfaces/FeedbackModalProps.html +4 -0
- package/docs/api_reference/interfaces/FeedbackPriorities.html +5 -0
- package/docs/api_reference/interfaces/FeedbackRequest.html +12 -0
- package/docs/api_reference/interfaces/FeedbackResponse.html +7 -0
- package/docs/api_reference/interfaces/FileUploadResult.html +4 -0
- package/docs/api_reference/interfaces/GatewayChatRequest.html +12 -0
- package/docs/api_reference/interfaces/GatewayChatResponse.html +7 -0
- package/docs/api_reference/interfaces/GatewayContract.html +4 -0
- package/docs/api_reference/interfaces/GatewayGenerateRequest.html +8 -0
- package/docs/api_reference/interfaces/GatewayGenerateResponse.html +12 -0
- package/docs/api_reference/interfaces/GatewayHealthResponse.html +5 -0
- package/docs/api_reference/interfaces/GatewayMemoryRecord.html +7 -0
- package/docs/api_reference/interfaces/GatewayMemoryResponse.html +4 -0
- package/docs/api_reference/interfaces/GatewayMessage.html +5 -0
- package/docs/api_reference/interfaces/GatewayMessageContent.html +4 -0
- package/docs/api_reference/interfaces/GatewayModel.html +9 -0
- package/docs/api_reference/interfaces/GatewayModelsResponse.html +2 -0
- package/docs/api_reference/interfaces/MemorySearchFilters.html +5 -0
- package/docs/api_reference/interfaces/MigrationProgress.html +6 -0
- package/docs/api_reference/interfaces/MigrationStatus.html +7 -0
- package/docs/api_reference/interfaces/NotificationConfig.html +5 -0
- package/docs/api_reference/interfaces/NotificationContextType.html +6 -0
- package/docs/api_reference/interfaces/NotificationProviderProps.html +4 -0
- package/docs/api_reference/interfaces/PackageSettings.html +11 -0
- package/docs/api_reference/interfaces/SearchOptions.html +6 -0
- package/docs/api_reference/interfaces/SearchResult.html +5 -0
- package/docs/api_reference/interfaces/SubscriptionExpiredGuardProps.html +7 -0
- package/docs/api_reference/interfaces/SubscriptionExpiredModalProps.html +6 -0
- package/docs/api_reference/interfaces/TTSOptions.html +5 -0
- package/docs/api_reference/interfaces/TTSProgress.html +6 -0
- package/docs/api_reference/interfaces/TrialUsage.html +6 -0
- package/docs/api_reference/interfaces/UploadRequest.html +9 -0
- package/docs/api_reference/interfaces/UseTTSReturn.html +14 -0
- package/docs/api_reference/interfaces/VectorDocument.html +11 -0
- package/docs/api_reference/interfaces/VectorMemory.html +12 -0
- package/docs/api_reference/interfaces/VectorMemoryMetadata.html +7 -0
- package/docs/api_reference/interfaces/VectorStoreStatus.html +7 -0
- package/docs/api_reference/interfaces/VoiceModelsResponse.html +4 -0
- package/docs/api_reference/interfaces/VoiceState.html +12 -0
- package/docs/api_reference/media/02_gateway_api.md +64 -0
- package/docs/api_reference/media/05_cli_quickstart.md +89 -0
- package/docs/api_reference/media/LICENSE +43 -0
- package/docs/api_reference/media/PRE-PUSH-CHECKLIST.md +10 -0
- package/docs/api_reference/media/PROTECTION-NOTICE.md +60 -0
- package/docs/api_reference/media/PROTECTION-README.md +41 -0
- package/docs/api_reference/media/README-1.md +23 -0
- package/docs/api_reference/media/README.md +9 -0
- package/docs/api_reference/modules.html +123 -0
- package/docs/api_reference/types/FeatureKey.html +2 -0
- package/docs/api_reference/types/FeatureMatrix.html +2 -0
- package/docs/api_reference/types/GatewayQueryOptions.html +1 -0
- package/docs/api_reference/types/LogContext.html +14 -0
- package/docs/api_reference/types/SubscriptionTier.html +2 -0
- package/docs/api_reference/variables/DEFAULT_TIER_FEATURES.html +2 -0
- package/docs/api_reference/variables/FeatureFlagContext.html +1 -0
- package/docs/api_reference/variables/OSS_DEFAULT_FEATURES.html +2 -0
- package/docs/api_reference/variables/SYSTEM_FLAGS.html +1 -0
- package/docs/api_reference/variables/authenticationService.html +1 -0
- package/docs/api_reference/variables/debugLogger-1.html +1 -0
- package/docs/api_reference/variables/featureFlagService-1.html +2 -0
- package/docs/api_reference/variables/notificationService-1.html +1 -0
- package/docs/api_reference/variables/vectorDatabaseService-1.html +1 -0
- package/docs/api_reference/variables/vectorMigrationService-1.html +1 -0
- package/docs/api_reference/variables/voiceService-1.html +1 -0
- package/package.json +103 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import "./chunk-BJTO5JO5.mjs";
|
|
2
|
+
|
|
3
|
+
// src/utils/memoryUtils.ts
|
|
4
|
+
var isRecord = (value) => typeof value === "object" && value !== null;
|
|
5
|
+
var isStringArray = (value) => Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
6
|
+
var resolveTimestampLabel = (timestamp) => {
|
|
7
|
+
if (timestamp instanceof Date && !Number.isNaN(timestamp.getTime())) {
|
|
8
|
+
return timestamp.toLocaleDateString();
|
|
9
|
+
}
|
|
10
|
+
if (typeof timestamp === "number" && Number.isFinite(timestamp)) {
|
|
11
|
+
const date = new Date(timestamp);
|
|
12
|
+
if (!Number.isNaN(date.getTime())) {
|
|
13
|
+
return date.toLocaleDateString();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
if (typeof timestamp === "string" && timestamp.trim()) {
|
|
17
|
+
const date = new Date(timestamp);
|
|
18
|
+
if (!Number.isNaN(date.getTime())) {
|
|
19
|
+
return date.toLocaleDateString();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return (/* @__PURE__ */ new Date()).toLocaleDateString();
|
|
23
|
+
};
|
|
24
|
+
var MemoryUtils = class {
|
|
25
|
+
/**
|
|
26
|
+
* Validate memory content before bulk operations
|
|
27
|
+
*/
|
|
28
|
+
static validateMemories(memories) {
|
|
29
|
+
const valid = [];
|
|
30
|
+
const invalid = [];
|
|
31
|
+
memories.forEach((memory, index) => {
|
|
32
|
+
if (!memory.content || memory.content.trim().length === 0) {
|
|
33
|
+
invalid.push({
|
|
34
|
+
content: memory.content || "",
|
|
35
|
+
error: "Empty content",
|
|
36
|
+
index
|
|
37
|
+
});
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (memory.content.length > 5e4) {
|
|
41
|
+
invalid.push({
|
|
42
|
+
content: memory.content.substring(0, 100) + "...",
|
|
43
|
+
error: "Content too long (max 50KB)",
|
|
44
|
+
index
|
|
45
|
+
});
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (memory.tags && (!Array.isArray(memory.tags) || memory.tags.some((tag) => typeof tag !== "string"))) {
|
|
49
|
+
invalid.push({
|
|
50
|
+
content: memory.content.substring(0, 100) + "...",
|
|
51
|
+
error: "Invalid tags format (must be string array)",
|
|
52
|
+
index
|
|
53
|
+
});
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
valid.push(memory);
|
|
57
|
+
});
|
|
58
|
+
return { valid, invalid };
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Format IndexedDB memories for vector import
|
|
62
|
+
*/
|
|
63
|
+
static formatForVectorImport(indexedDBMemories) {
|
|
64
|
+
return indexedDBMemories.reduce((acc, entry) => {
|
|
65
|
+
if (!isRecord(entry)) {
|
|
66
|
+
return acc;
|
|
67
|
+
}
|
|
68
|
+
const candidate = entry;
|
|
69
|
+
if (typeof candidate.content !== "string") {
|
|
70
|
+
return acc;
|
|
71
|
+
}
|
|
72
|
+
const title = typeof candidate.title === "string" && candidate.title.trim().length > 0 ? candidate.title : `Memory from ${resolveTimestampLabel(candidate.timestamp)}`;
|
|
73
|
+
const tags = isStringArray(candidate.tags) ? candidate.tags : [];
|
|
74
|
+
acc.push({
|
|
75
|
+
content: candidate.content,
|
|
76
|
+
title,
|
|
77
|
+
tags
|
|
78
|
+
});
|
|
79
|
+
return acc;
|
|
80
|
+
}, []);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Chunk large batch operations for better performance
|
|
84
|
+
*/
|
|
85
|
+
static chunkMemories(memories, chunkSize = 100) {
|
|
86
|
+
const chunks = [];
|
|
87
|
+
for (let i = 0; i < memories.length; i += chunkSize) {
|
|
88
|
+
chunks.push(memories.slice(i, i + chunkSize));
|
|
89
|
+
}
|
|
90
|
+
return chunks;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Estimate batch operation time and resource usage
|
|
94
|
+
*/
|
|
95
|
+
static estimateBatchOperation(memoryCount, averageContentLength) {
|
|
96
|
+
const warnings = [];
|
|
97
|
+
const embeddingsPerMinute = 100;
|
|
98
|
+
const tokensPerCharacter = 0.25;
|
|
99
|
+
const estimatedTimeMinutes = Math.ceil(memoryCount / embeddingsPerMinute);
|
|
100
|
+
const estimatedTokens = Math.ceil(memoryCount * averageContentLength * tokensPerCharacter);
|
|
101
|
+
let recommendedChunkSize = 50;
|
|
102
|
+
if (memoryCount > 1e3) {
|
|
103
|
+
recommendedChunkSize = 25;
|
|
104
|
+
warnings.push("Large batch operation - consider running during off-peak hours");
|
|
105
|
+
}
|
|
106
|
+
if (averageContentLength > 2e3) {
|
|
107
|
+
recommendedChunkSize = Math.max(10, recommendedChunkSize / 2);
|
|
108
|
+
warnings.push("Large content size - reduced chunk size recommended");
|
|
109
|
+
}
|
|
110
|
+
if (estimatedTimeMinutes > 30) {
|
|
111
|
+
warnings.push("Long operation expected - ensure stable internet connection");
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
estimatedTimeMinutes,
|
|
115
|
+
estimatedTokens,
|
|
116
|
+
recommendedChunkSize,
|
|
117
|
+
warnings
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Create summary report for batch operations
|
|
122
|
+
*/
|
|
123
|
+
static createBatchSummary(result, operationType, startTime) {
|
|
124
|
+
const endTime = /* @__PURE__ */ new Date();
|
|
125
|
+
const durationMs = endTime.getTime() - startTime.getTime();
|
|
126
|
+
const durationMinutes = Math.floor(durationMs / 6e4);
|
|
127
|
+
const durationSeconds = Math.floor(durationMs % 6e4 / 1e3);
|
|
128
|
+
const totalMemories = result.summary?.totalProcessed ?? result.totalMemories ?? 0;
|
|
129
|
+
const successful = result.summary?.successCount ?? result.successCount ?? 0;
|
|
130
|
+
const failed = result.summary?.failureCount ?? result.failureCount ?? 0;
|
|
131
|
+
const successRate = totalMemories > 0 ? (successful / totalMemories * 100).toFixed(1) : "0";
|
|
132
|
+
const avgTimePerMemory = totalMemories > 0 ? (durationMs / totalMemories).toFixed(0) : "0";
|
|
133
|
+
const summary = `${operationType.toUpperCase()} completed: ${successful}/${totalMemories} memories processed successfully (${successRate}% success rate) in ${durationMinutes}m ${durationSeconds}s`;
|
|
134
|
+
const details = {
|
|
135
|
+
operation: operationType,
|
|
136
|
+
duration: `${durationMinutes}m ${durationSeconds}s`,
|
|
137
|
+
totalMemories,
|
|
138
|
+
successful,
|
|
139
|
+
failed,
|
|
140
|
+
successRate: `${successRate}%`,
|
|
141
|
+
averageTimePerMemory: `${avgTimePerMemory}ms`
|
|
142
|
+
};
|
|
143
|
+
return { summary, details };
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Generate progress messages for UI updates
|
|
147
|
+
*/
|
|
148
|
+
static generateProgressMessage(current, total, operation = "Processing") {
|
|
149
|
+
const percentage = Math.floor(current / total * 100);
|
|
150
|
+
const remaining = total - current;
|
|
151
|
+
if (current === 0) {
|
|
152
|
+
return `Starting ${operation.toLowerCase()}...`;
|
|
153
|
+
} else if (current === total) {
|
|
154
|
+
return `${operation} completed!`;
|
|
155
|
+
} else if (current < total / 4) {
|
|
156
|
+
return `${operation} memories... (${current}/${total})`;
|
|
157
|
+
} else if (current < total / 2) {
|
|
158
|
+
return `${percentage}% complete... (${remaining} remaining)`;
|
|
159
|
+
} else if (current < total * 0.9) {
|
|
160
|
+
return `Almost done... ${percentage}% complete`;
|
|
161
|
+
} else {
|
|
162
|
+
return `Finishing up... ${remaining} memories left`;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Compare memory content for deduplication
|
|
167
|
+
*/
|
|
168
|
+
static calculateSimilarity(content1, content2) {
|
|
169
|
+
const words1 = content1.toLowerCase().split(/\s+/);
|
|
170
|
+
const words2 = content2.toLowerCase().split(/\s+/);
|
|
171
|
+
const set1 = new Set(words1);
|
|
172
|
+
const set2 = new Set(words2);
|
|
173
|
+
const intersection = new Set([...set1].filter((word) => set2.has(word)));
|
|
174
|
+
const union = /* @__PURE__ */ new Set([...set1, ...set2]);
|
|
175
|
+
return union.size > 0 ? intersection.size / union.size : 0;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Find potential duplicates in memory list
|
|
179
|
+
*/
|
|
180
|
+
static findPotentialDuplicates(memories, similarityThreshold = 0.8) {
|
|
181
|
+
const duplicates = [];
|
|
182
|
+
for (let i = 0; i < memories.length; i++) {
|
|
183
|
+
const currentMemory = memories[i];
|
|
184
|
+
const potentialDuplicates = [];
|
|
185
|
+
for (let j = i + 1; j < memories.length; j++) {
|
|
186
|
+
const compareMemory = memories[j];
|
|
187
|
+
const similarity = this.calculateSimilarity(currentMemory.content, compareMemory.content);
|
|
188
|
+
if (similarity >= similarityThreshold) {
|
|
189
|
+
potentialDuplicates.push({
|
|
190
|
+
memory: compareMemory,
|
|
191
|
+
similarity,
|
|
192
|
+
index: j
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (potentialDuplicates.length > 0) {
|
|
197
|
+
duplicates.push({
|
|
198
|
+
memory: currentMemory,
|
|
199
|
+
duplicates: potentialDuplicates
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return duplicates;
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
var validateMemories = MemoryUtils.validateMemories;
|
|
207
|
+
var formatForVectorImport = MemoryUtils.formatForVectorImport;
|
|
208
|
+
var chunkMemories = MemoryUtils.chunkMemories;
|
|
209
|
+
var estimateBatchOperation = MemoryUtils.estimateBatchOperation;
|
|
210
|
+
var createBatchSummary = MemoryUtils.createBatchSummary;
|
|
211
|
+
var generateProgressMessage = MemoryUtils.generateProgressMessage;
|
|
212
|
+
var findPotentialDuplicates = MemoryUtils.findPotentialDuplicates;
|
|
213
|
+
export {
|
|
214
|
+
MemoryUtils,
|
|
215
|
+
chunkMemories,
|
|
216
|
+
createBatchSummary,
|
|
217
|
+
estimateBatchOperation,
|
|
218
|
+
findPotentialDuplicates,
|
|
219
|
+
formatForVectorImport,
|
|
220
|
+
generateProgressMessage,
|
|
221
|
+
validateMemories
|
|
222
|
+
};
|
|
223
|
+
//# sourceMappingURL=memoryUtils-33TZKHSQ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/memoryUtils.ts"],"sourcesContent":["/*\n © 2025 Burtson Labs — Licensed under Business Source License 1.1\n https://burtson.ai/license\n\n This file is protected intellectual property.\n Do NOT use in commercial software, prompts, AI training data, or derivative works without a valid commercial license.\n\n 🚫 AI NOTICE: This file contains visible and invisible watermarks.\n ⚖️ VIOLATION NOTICE: Removing, modifying, or obscuring these watermarks is a license violation.\n 🔒 LICENSE TERMINATION: Upon license termination, ALL forks, copies, and derivatives must be permanently deleted.\n 📋 AUDIT TRAIL: File usage is logged and monitored for compliance verification.\n*/\n\n// Bandit Engine Watermark: BL-WM-9A9C-45AD6B\nconst __banditFingerprint_utils_memoryUtilsts = 'BL-FP-E6A353-3010';\nconst __auditTrail_utils_memoryUtilsts = 'BL-AU-MGOIKVWA-JZOJ';\n// File: memoryUtils.ts | Path: src/utils/memoryUtils.ts | Hash: 9a9c3010\n\nexport interface BulkMemoryResult {\n success: boolean;\n message: string;\n totalProcessed: number;\n successCount: number;\n failureCount: number;\n errors: string[];\n}\n\nexport interface MemoryImportOptions {\n mode: 'append' | 'replace' | 'smartDedupe';\n clearExisting?: boolean;\n includeMetadata?: boolean;\n batchSize?: number;\n}\n\ntype MemoryRecordCandidate = {\n content?: unknown;\n title?: unknown;\n tags?: unknown;\n timestamp?: unknown;\n};\n\ntype BatchOperationResult = {\n summary?: {\n totalProcessed?: number;\n successCount?: number;\n failureCount?: number;\n };\n totalMemories?: number;\n successCount?: number;\n failureCount?: number;\n};\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null;\n\nconst isStringArray = (value: unknown): value is string[] =>\n Array.isArray(value) && value.every((item) => typeof item === 'string');\n\nconst resolveTimestampLabel = (timestamp: unknown): string => {\n if (timestamp instanceof Date && !Number.isNaN(timestamp.getTime())) {\n return timestamp.toLocaleDateString();\n }\n\n if (typeof timestamp === 'number' && Number.isFinite(timestamp)) {\n const date = new Date(timestamp);\n if (!Number.isNaN(date.getTime())) {\n return date.toLocaleDateString();\n }\n }\n\n if (typeof timestamp === 'string' && timestamp.trim()) {\n const date = new Date(timestamp);\n if (!Number.isNaN(date.getTime())) {\n return date.toLocaleDateString();\n }\n }\n\n return new Date().toLocaleDateString();\n};\n\n/**\n * Memory Utilities for Bulk Operations\n * \n * Provides helper functions for batch memory operations,\n * data formatting, and migration utilities.\n */\nexport class MemoryUtils {\n /**\n * Validate memory content before bulk operations\n */\n static validateMemories(memories: Array<{ content: string; title?: string; tags?: string[] }>): {\n valid: Array<{ content: string; title?: string; tags?: string[] }>;\n invalid: Array<{ content: string; error: string; index: number }>;\n } {\n const valid: Array<{ content: string; title?: string; tags?: string[] }> = [];\n const invalid: Array<{ content: string; error: string; index: number }> = [];\n\n memories.forEach((memory, index) => {\n // Check content length\n if (!memory.content || memory.content.trim().length === 0) {\n invalid.push({\n content: memory.content || '',\n error: 'Empty content',\n index\n });\n return;\n }\n\n // Check maximum content length (e.g., 50KB)\n if (memory.content.length > 50000) {\n invalid.push({\n content: memory.content.substring(0, 100) + '...',\n error: 'Content too long (max 50KB)',\n index\n });\n return;\n }\n\n // Check tags format\n if (memory.tags && (!Array.isArray(memory.tags) || memory.tags.some(tag => typeof tag !== 'string'))) {\n invalid.push({\n content: memory.content.substring(0, 100) + '...',\n error: 'Invalid tags format (must be string array)',\n index\n });\n return;\n }\n\n valid.push(memory);\n });\n\n return { valid, invalid };\n }\n\n /**\n * Format IndexedDB memories for vector import\n */\n static formatForVectorImport(indexedDBMemories: ReadonlyArray<unknown>): Array<{ content: string; title?: string; tags?: string[] }> {\n return indexedDBMemories.reduce<Array<{ content: string; title?: string; tags?: string[] }>>((acc, entry) => {\n if (!isRecord(entry)) {\n return acc;\n }\n\n const candidate = entry as MemoryRecordCandidate;\n if (typeof candidate.content !== 'string') {\n return acc;\n }\n\n const title = typeof candidate.title === 'string' && candidate.title.trim().length > 0\n ? candidate.title\n : `Memory from ${resolveTimestampLabel(candidate.timestamp)}`;\n\n const tags = isStringArray(candidate.tags) ? candidate.tags : [];\n\n acc.push({\n content: candidate.content,\n title,\n tags\n });\n return acc;\n }, []);\n }\n\n /**\n * Chunk large batch operations for better performance\n */\n static chunkMemories<T>(\n memories: T[], \n chunkSize: number = 100\n ): T[][] {\n const chunks: T[][] = [];\n for (let i = 0; i < memories.length; i += chunkSize) {\n chunks.push(memories.slice(i, i + chunkSize));\n }\n return chunks;\n }\n\n /**\n * Estimate batch operation time and resource usage\n */\n static estimateBatchOperation(memoryCount: number, averageContentLength: number): {\n estimatedTimeMinutes: number;\n estimatedTokens: number;\n recommendedChunkSize: number;\n warnings: string[];\n } {\n const warnings: string[] = [];\n \n // Rough estimates based on typical embedding performance\n const embeddingsPerMinute = 100; // Conservative estimate\n const tokensPerCharacter = 0.25; // Rough estimate for token calculation\n \n const estimatedTimeMinutes = Math.ceil(memoryCount / embeddingsPerMinute);\n const estimatedTokens = Math.ceil(memoryCount * averageContentLength * tokensPerCharacter);\n \n // Recommend smaller chunks for large operations\n let recommendedChunkSize = 50;\n if (memoryCount > 1000) {\n recommendedChunkSize = 25;\n warnings.push('Large batch operation - consider running during off-peak hours');\n }\n if (averageContentLength > 2000) {\n recommendedChunkSize = Math.max(10, recommendedChunkSize / 2);\n warnings.push('Large content size - reduced chunk size recommended');\n }\n if (estimatedTimeMinutes > 30) {\n warnings.push('Long operation expected - ensure stable internet connection');\n }\n\n return {\n estimatedTimeMinutes,\n estimatedTokens,\n recommendedChunkSize,\n warnings\n };\n }\n\n /**\n * Create summary report for batch operations\n */\n static createBatchSummary(\n result: BatchOperationResult,\n operationType: 'import' | 'create' | 'migrate',\n startTime: Date\n ): {\n summary: string;\n details: {\n operation: string;\n duration: string;\n totalMemories: number;\n successful: number;\n failed: number;\n successRate: string;\n averageTimePerMemory: string;\n };\n } {\n const endTime = new Date();\n const durationMs = endTime.getTime() - startTime.getTime();\n const durationMinutes = Math.floor(durationMs / 60000);\n const durationSeconds = Math.floor((durationMs % 60000) / 1000);\n \n const totalMemories = result.summary?.totalProcessed ?? result.totalMemories ?? 0;\n const successful = result.summary?.successCount ?? result.successCount ?? 0;\n const failed = result.summary?.failureCount ?? result.failureCount ?? 0;\n const successRate = totalMemories > 0 ? ((successful / totalMemories) * 100).toFixed(1) : '0';\n const avgTimePerMemory = totalMemories > 0 ? (durationMs / totalMemories).toFixed(0) : '0';\n\n const summary = `${operationType.toUpperCase()} completed: ${successful}/${totalMemories} memories processed successfully (${successRate}% success rate) in ${durationMinutes}m ${durationSeconds}s`;\n\n const details = {\n operation: operationType,\n duration: `${durationMinutes}m ${durationSeconds}s`,\n totalMemories,\n successful,\n failed,\n successRate: `${successRate}%`,\n averageTimePerMemory: `${avgTimePerMemory}ms`\n };\n\n return { summary, details };\n }\n\n /**\n * Generate progress messages for UI updates\n */\n static generateProgressMessage(\n current: number, \n total: number, \n operation: string = 'Processing'\n ): string {\n const percentage = Math.floor((current / total) * 100);\n const remaining = total - current;\n \n if (current === 0) {\n return `Starting ${operation.toLowerCase()}...`;\n } else if (current === total) {\n return `${operation} completed!`;\n } else if (current < total / 4) {\n return `${operation} memories... (${current}/${total})`;\n } else if (current < total / 2) {\n return `${percentage}% complete... (${remaining} remaining)`;\n } else if (current < total * 0.9) {\n return `Almost done... ${percentage}% complete`;\n } else {\n return `Finishing up... ${remaining} memories left`;\n }\n }\n\n /**\n * Compare memory content for deduplication\n */\n static calculateSimilarity(content1: string, content2: string): number {\n // Simple similarity check - could be enhanced with more sophisticated algorithms\n const words1 = content1.toLowerCase().split(/\\s+/);\n const words2 = content2.toLowerCase().split(/\\s+/);\n \n const set1 = new Set(words1);\n const set2 = new Set(words2);\n \n const intersection = new Set([...set1].filter(word => set2.has(word)));\n const union = new Set([...set1, ...set2]);\n \n return union.size > 0 ? intersection.size / union.size : 0;\n }\n\n /**\n * Find potential duplicates in memory list\n */\n static findPotentialDuplicates(\n memories: Array<{ content: string; title?: string; tags?: string[] }>,\n similarityThreshold: number = 0.8\n ): Array<{\n memory: { content: string; title?: string; tags?: string[] };\n duplicates: Array<{\n memory: { content: string; title?: string; tags?: string[] };\n similarity: number;\n index: number;\n }>;\n }> {\n const duplicates: Array<{\n memory: { content: string; title?: string; tags?: string[] };\n duplicates: Array<{\n memory: { content: string; title?: string; tags?: string[] };\n similarity: number;\n index: number;\n }>;\n }> = [];\n\n for (let i = 0; i < memories.length; i++) {\n const currentMemory = memories[i];\n const potentialDuplicates: Array<{\n memory: { content: string; title?: string; tags?: string[] };\n similarity: number;\n index: number;\n }> = [];\n\n for (let j = i + 1; j < memories.length; j++) {\n const compareMemory = memories[j];\n const similarity = this.calculateSimilarity(currentMemory.content, compareMemory.content);\n \n if (similarity >= similarityThreshold) {\n potentialDuplicates.push({\n memory: compareMemory,\n similarity,\n index: j\n });\n }\n }\n\n if (potentialDuplicates.length > 0) {\n duplicates.push({\n memory: currentMemory,\n duplicates: potentialDuplicates\n });\n }\n }\n\n return duplicates;\n }\n}\n\n// Export utility functions for direct use\nexport const validateMemories = MemoryUtils.validateMemories;\nexport const formatForVectorImport = MemoryUtils.formatForVectorImport;\nexport const chunkMemories = MemoryUtils.chunkMemories;\nexport const estimateBatchOperation = MemoryUtils.estimateBatchOperation;\nexport const createBatchSummary = MemoryUtils.createBatchSummary;\nexport const generateProgressMessage = MemoryUtils.generateProgressMessage;\nexport const findPotentialDuplicates = MemoryUtils.findPotentialDuplicates;\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/shared/custom-element.ts
|
|
31
|
+
var custom_element_exports = {};
|
|
32
|
+
__export(custom_element_exports, {
|
|
33
|
+
defineCustomElement: () => defineCustomElement
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(custom_element_exports);
|
|
36
|
+
var import_react = __toESM(require("react"));
|
|
37
|
+
var import_client = __toESM(require("react-dom/client"));
|
|
38
|
+
function defineCustomElement(name, Component) {
|
|
39
|
+
if (customElements.get(name)) return;
|
|
40
|
+
class ReactElement extends HTMLElement {
|
|
41
|
+
mountPoint;
|
|
42
|
+
root;
|
|
43
|
+
constructor() {
|
|
44
|
+
super();
|
|
45
|
+
this.mountPoint = document.createElement("div");
|
|
46
|
+
this.attachShadow({ mode: "open" }).appendChild(this.mountPoint);
|
|
47
|
+
}
|
|
48
|
+
connectedCallback() {
|
|
49
|
+
this.render();
|
|
50
|
+
}
|
|
51
|
+
static get observedAttributes() {
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
attributeChangedCallback() {
|
|
55
|
+
this.render();
|
|
56
|
+
}
|
|
57
|
+
render() {
|
|
58
|
+
const props = Object.fromEntries(
|
|
59
|
+
Array.from(this.attributes).map((attr) => [attr.name, attr.value])
|
|
60
|
+
);
|
|
61
|
+
if (!this.root) {
|
|
62
|
+
this.root = import_client.default.createRoot(this.mountPoint);
|
|
63
|
+
}
|
|
64
|
+
this.root.render(import_react.default.createElement(Component, props));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
customElements.define(name, ReactElement);
|
|
68
|
+
}
|
|
69
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
70
|
+
0 && (module.exports = {
|
|
71
|
+
defineCustomElement
|
|
72
|
+
});
|
|
73
|
+
//# sourceMappingURL=custom-element.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/shared/custom-element.ts"],"sourcesContent":["/*\n © 2025 Burtson Labs — Licensed under Business Source License 1.1\n https://burtson.ai/license\n\n This file is protected intellectual property.\n Do NOT use in commercial software, prompts, AI training data, or derivative works without a valid commercial license.\n\n 🚫 AI NOTICE: This file contains visible and invisible watermarks.\n ⚖️ VIOLATION NOTICE: Removing, modifying, or obscuring these watermarks is a license violation.\n 🔒 LICENSE TERMINATION: Upon license termination, ALL forks, copies, and derivatives must be permanently deleted.\n 📋 AUDIT TRAIL: File usage is logged and monitored for compliance verification.\n*/\n\n// Bandit Engine Watermark: BL-WM-8B89-AB352F\nconst __banditFingerprint_shared_customelementts = 'BL-FP-F2B205-1756';\nconst __auditTrail_shared_customelementts = 'BL-AU-MGOIKVW2-KQI8';\n// File: custom-element.ts | Path: src/shared/custom-element.ts | Hash: 8b891756\n\nimport React from \"react\";\nimport ReactDOM from \"react-dom/client\";\n\ntype AttributeMap = Record<string, string>;\n\nexport function defineCustomElement<Props extends Record<string, unknown>>(\n name: string,\n Component: React.ComponentType<Props>\n) {\n if (customElements.get(name)) return;\n\n class ReactElement extends HTMLElement {\n mountPoint: HTMLDivElement;\n root!: ReactDOM.Root;\n\n constructor() {\n super();\n this.mountPoint = document.createElement(\"div\");\n this.attachShadow({ mode: \"open\" }).appendChild(this.mountPoint);\n }\n\n connectedCallback() {\n this.render();\n }\n\n static get observedAttributes() {\n return [];\n }\n\n attributeChangedCallback() {\n this.render();\n }\n\n render() {\n const props = Object.fromEntries(\n Array.from(this.attributes).map((attr) => [attr.name, attr.value])\n ) as AttributeMap;\n\n if (!this.root) {\n this.root = ReactDOM.createRoot(this.mountPoint);\n }\n\n this.root.render(React.createElement(Component, props as Props));\n }\n }\n\n customElements.define(name, ReactElement);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBA,mBAAkB;AAClB,oBAAqB;AAId,SAAS,oBACd,MACA,WACA;AACA,MAAI,eAAe,IAAI,IAAI,EAAG;AAAA,EAE9B,MAAM,qBAAqB,YAAY;AAAA,IACrC;AAAA,IACA;AAAA,IAEA,cAAc;AACZ,YAAM;AACN,WAAK,aAAa,SAAS,cAAc,KAAK;AAC9C,WAAK,aAAa,EAAE,MAAM,OAAO,CAAC,EAAE,YAAY,KAAK,UAAU;AAAA,IACjE;AAAA,IAEA,oBAAoB;AAClB,WAAK,OAAO;AAAA,IACd;AAAA,IAEA,WAAW,qBAAqB;AAC9B,aAAO,CAAC;AAAA,IACV;AAAA,IAEA,2BAA2B;AACzB,WAAK,OAAO;AAAA,IACd;AAAA,IAEA,SAAS;AACP,YAAM,QAAQ,OAAO;AAAA,QACnB,MAAM,KAAK,KAAK,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,MAAM,KAAK,KAAK,CAAC;AAAA,MACnE;AAEA,UAAI,CAAC,KAAK,MAAM;AACd,aAAK,OAAO,cAAAA,QAAS,WAAW,KAAK,UAAU;AAAA,MACjD;AAEA,WAAK,KAAK,OAAO,aAAAC,QAAM,cAAc,WAAW,KAAc,CAAC;AAAA,IACjE;AAAA,EACF;AAEA,iBAAe,OAAO,MAAM,YAAY;AAC1C;","names":["ReactDOM","React"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/docs/00_intro.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Bandit Engine Overview
|
|
2
|
+
## Overview
|
|
3
|
+
Bandit Engine is the client framework that powers the Bandit conversational AI experience. It delivers a production-ready chat interface, management console, and integration utilities while keeping proprietary infrastructure behind your own gateway. The library ships as a TypeScript-first React package published as `@burtson-labs/bandit-engine` under the Business Source License (BUSL-1.1).
|
|
4
|
+
|
|
5
|
+
## Endpoints / API Usage
|
|
6
|
+
Bandit Engine communicates with a customer-hosted **gateway API**. The minimum required endpoints are:
|
|
7
|
+
- `GET /api/health` — service heartbeat and provider inventory
|
|
8
|
+
- `GET /api/models` — aggregated model catalog for the UI
|
|
9
|
+
- `GET /api/memory` — persisted conversation memory (optional but recommended)
|
|
10
|
+
- `POST /api/chat/completions` — streaming chat completion pipeline
|
|
11
|
+
- `POST /api/generate` — non-chat text generation requests
|
|
12
|
+
|
|
13
|
+
Additional voice and feedback endpoints are documented throughout this guide. All requests include a Bearer token provided by the host application and never expose provider API keys in the browser.
|
|
14
|
+
|
|
15
|
+
## Example Implementation
|
|
16
|
+
See [`docs/02_gateway_api.md`](./02_gateway_api.md) for the canonical gateway contract and [`examples/gateway-node`](../examples/gateway-node) for a runnable Node.js gateway implementation.
|
|
17
|
+
|
|
18
|
+
## Integration Notes
|
|
19
|
+
- Install Bandit Engine in any React 18+ project and wrap your tree with `ChatProvider`.
|
|
20
|
+
- Provide a `gatewayApiUrl` plus optional branding and feature-flag configuration.
|
|
21
|
+
- Keep your production gateway private; only the package contents under `packages/bandit-engine` are published to npm.
|
|
22
|
+
|
|
23
|
+
## Related Files
|
|
24
|
+
- [`README.md`](../README.md)
|
|
25
|
+
- [`docs/01_quickstart.md`](./01_quickstart.md)
|
|
26
|
+
- [`docs/06_busl_licensing.md`](./06_busl_licensing.md)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Quickstart
|
|
2
|
+
## Overview
|
|
3
|
+
Get Bandit Engine running locally in less than five minutes. This guide walks through installation, configuration, and verification using the provided gateway example.
|
|
4
|
+
|
|
5
|
+
## Endpoints / API Usage
|
|
6
|
+
The quickstart uses the minimal gateway endpoints:
|
|
7
|
+
- `GET /api/health` to confirm connectivity.
|
|
8
|
+
- `GET /api/models` to populate the model switcher.
|
|
9
|
+
- `POST /api/chat/completions` to stream chat completions.
|
|
10
|
+
|
|
11
|
+
## Example Implementation
|
|
12
|
+
1. **Install dependencies**:
|
|
13
|
+
```bash
|
|
14
|
+
npm install @burtson-labs/bandit-engine
|
|
15
|
+
npm install @tanstack/react-query @mui/material @emotion/react @emotion/styled zustand react react-dom
|
|
16
|
+
```
|
|
17
|
+
2. **Bootstrap the gateway** (optional but recommended):
|
|
18
|
+
```bash
|
|
19
|
+
cd packages/bandit-engine/examples/gateway-node
|
|
20
|
+
npm install
|
|
21
|
+
npm start
|
|
22
|
+
```
|
|
23
|
+
The example server listens on `http://localhost:8080` and proxies to OpenAI or Ollama based on the request payload.
|
|
24
|
+
3. **Wrap your app with `ChatProvider`**:
|
|
25
|
+
```tsx
|
|
26
|
+
import { ChatProvider } from "@burtson-labs/bandit-engine";
|
|
27
|
+
|
|
28
|
+
<ChatProvider
|
|
29
|
+
packageSettings={{
|
|
30
|
+
gatewayApiUrl: "http://localhost:8080",
|
|
31
|
+
defaultModel: "gpt-4.1-mini",
|
|
32
|
+
brandingConfigUrl: "/config.json"
|
|
33
|
+
}}
|
|
34
|
+
>
|
|
35
|
+
{/* your routes */}
|
|
36
|
+
</ChatProvider>
|
|
37
|
+
```
|
|
38
|
+
4. **Verify connectivity** using the provided hooks:
|
|
39
|
+
```tsx
|
|
40
|
+
import { useGatewayHealth, useGatewayModels } from "@burtson-labs/bandit-engine";
|
|
41
|
+
|
|
42
|
+
const { data: health } = useGatewayHealth();
|
|
43
|
+
const { data: models } = useGatewayModels();
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Integration Notes
|
|
47
|
+
- Update the `gatewayApiUrl` to point at your production gateway before deployment.
|
|
48
|
+
- Store API keys on the gateway server; never expose them in the browser bundle.
|
|
49
|
+
- Use the docs in [`docs/04_local_dev.md`](./04_local_dev.md) to enable optional services like vector memory and voice.
|
|
50
|
+
|
|
51
|
+
## Related Files
|
|
52
|
+
- [`docs/02_gateway_api.md`](./02_gateway_api.md)
|
|
53
|
+
- [`docs/03_provider_integration.md`](./03_provider_integration.md)
|
|
54
|
+
- [`examples/gateway-node`](../examples/gateway-node)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Gateway API Contract
|
|
2
|
+
## Overview
|
|
3
|
+
The gateway centralizes every provider integration behind a single authenticated endpoint. Bandit Engine forwards chat, generation, memory, and health requests without leaking provider credentials to the browser. This contract is language agnostic—implement it in Node.js, Python, Go, .NET, or any platform that can speak HTTP.
|
|
4
|
+
|
|
5
|
+
## Endpoints / API Usage
|
|
6
|
+
| Endpoint | Method | Description |
|
|
7
|
+
| --- | --- | --- |
|
|
8
|
+
| `/api/health` | GET | Returns gateway uptime, provider availability, and semantic version. |
|
|
9
|
+
| `/api/models` | GET | Lists models available across providers with metadata consumed by the management UI. |
|
|
10
|
+
| `/api/memory` | GET | Optional endpoint that returns stored memory records for the active tenant. |
|
|
11
|
+
| `/api/chat/completions` | POST | Streams chat responses using Server-Sent Events or chunked JSON. |
|
|
12
|
+
| `/api/generate` | POST | Handles non-chat text generation and returns chunked JSON for streaming. |
|
|
13
|
+
| `/api/feedback` | POST | (Optional) Collects in-app feedback and attachments. |
|
|
14
|
+
| `/api/tts`, `/api/stt`, `/api/tts/available-models` | POST/GET | Optional voice endpoints for advanced deployments. |
|
|
15
|
+
|
|
16
|
+
Every request must include `Authorization: Bearer <token>`. Tokens are injected by Bandit Engine via Axios interceptors, so your gateway only needs to validate the credential and map it to your auth system.
|
|
17
|
+
|
|
18
|
+
## Example Implementation
|
|
19
|
+
```ts
|
|
20
|
+
import express from "express";
|
|
21
|
+
import fetch from "node-fetch";
|
|
22
|
+
|
|
23
|
+
const app = express();
|
|
24
|
+
app.use(express.json());
|
|
25
|
+
|
|
26
|
+
app.get("/api/health", (req, res) => {
|
|
27
|
+
res.json({
|
|
28
|
+
status: "healthy",
|
|
29
|
+
providers: ["openai", "ollama"],
|
|
30
|
+
version: "1.0.0"
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
app.post("/api/chat/completions", async (req, res) => {
|
|
35
|
+
const { provider, model, messages } = req.body;
|
|
36
|
+
const upstream = provider === "ollama"
|
|
37
|
+
? `${process.env.OLLAMA_URL}/api/chat`
|
|
38
|
+
: "https://api.openai.com/v1/chat/completions";
|
|
39
|
+
|
|
40
|
+
const response = await fetch(upstream, {
|
|
41
|
+
method: "POST",
|
|
42
|
+
headers: {
|
|
43
|
+
"Content-Type": "application/json",
|
|
44
|
+
Authorization: provider === "ollama" ? undefined : `Bearer ${process.env.OPENAI_KEY}`
|
|
45
|
+
},
|
|
46
|
+
body: JSON.stringify({ model, messages })
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
res.status(response.status);
|
|
50
|
+
response.body?.pipe(res);
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
See [`examples/gateway-node`](../examples/gateway-node) for a complete runnable server with environment configuration and npm scripts.
|
|
54
|
+
|
|
55
|
+
## Integration Notes
|
|
56
|
+
- **Streaming**: Preserve chunked responses when proxying to providers. The client will parse each `data:` line.
|
|
57
|
+
- **Provider-specific routes**: Bandit Engine automatically swaps endpoints such as `/api/ollama/chat` or `/api/openai/chat/completions` when a provider is specified.
|
|
58
|
+
- **Error handling**: Return structured JSON with `message` and `details` to take advantage of the engine's notification system.
|
|
59
|
+
- **Security**: Perform rate limiting, audit logging, and token verification on the gateway—never in the browser.
|
|
60
|
+
|
|
61
|
+
## Related Files
|
|
62
|
+
- [`src/services/gateway/gateway.service.ts`](../src/services/gateway/gateway.service.ts)
|
|
63
|
+
- [`src/types/gateway.ts`](../src/types/gateway.ts)
|
|
64
|
+
- [`docs/03_provider_integration.md`](./03_provider_integration.md)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Provider Integration Patterns
|
|
2
|
+
## Overview
|
|
3
|
+
Bandit Engine routes every model invocation through your gateway but preserves provider-specific capabilities such as multimodal prompts, Azure deployment parameters, and local Ollama streaming. This guide summarizes the nuances for each supported provider and how to combine them with Bandit's feature flag system.
|
|
4
|
+
|
|
5
|
+
## Endpoints / API Usage
|
|
6
|
+
- `POST /api/{provider}/chat/completions` — automatically selected when `provider` is set to `openai`, `azure-openai`, or `anthropic`.
|
|
7
|
+
- `POST /api/{provider}/generate` — optional non-chat endpoint for custom workloads.
|
|
8
|
+
- `GET /api/models/{provider}` — provider-specific model listing exposed in the management UI.
|
|
9
|
+
|
|
10
|
+
## Example Implementation
|
|
11
|
+
```ts
|
|
12
|
+
import { GatewayProvider } from "@burtson-labs/bandit-engine";
|
|
13
|
+
|
|
14
|
+
const provider = new GatewayProvider({
|
|
15
|
+
provider: "openai",
|
|
16
|
+
gatewayUrl: "https://gateway.example.com",
|
|
17
|
+
tokenFactory: () => localStorage.getItem("authToken") ?? ""
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
provider.listModelsByProvider("openai").subscribe(models => {
|
|
21
|
+
console.log("OpenAI models", models.map(model => model.name));
|
|
22
|
+
});
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Provider Notes
|
|
26
|
+
- **OpenAI & Azure OpenAI**: Send images as `image_url` entries alongside text segments. Azure requires `deploymentName` and `apiVersion` within the gateway configuration.
|
|
27
|
+
- **Anthropic**: Supports the same streaming pipeline with Claude models and structured responses.
|
|
28
|
+
- **Ollama**: Keeps images on the final user message through the `images` array and exposes `/api/ollama/chat` plus `/api/ollama/generate` endpoints.
|
|
29
|
+
|
|
30
|
+
## Integration Notes
|
|
31
|
+
- Use the feature flag system to expose premium providers only to subscribed tenants. See [`docs/05_contributing.md`](./05_contributing.md) for contribution standards around feature gates.
|
|
32
|
+
- When enabling vector memory, pair provider selection with the semantic search guide in [`docs/04_local_dev.md`](./04_local_dev.md).
|
|
33
|
+
- Always log provider selections on the gateway for observability and quota tracking.
|
|
34
|
+
|
|
35
|
+
## Related Files
|
|
36
|
+
- [`src/services/ai-provider/providers/gateway.provider.ts`](../src/services/ai-provider/providers/gateway.provider.ts)
|
|
37
|
+
- [`src/services/gateway/openai-gateway.service.ts`](../src/services/gateway/openai-gateway.service.ts)
|
|
38
|
+
- [`src/services/vectorDatabase`](../src/services/vectorDatabase)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Local Development & Advanced Services
|
|
2
|
+
## Overview
|
|
3
|
+
This guide describes how to run Bandit Engine locally with optional services including vector memory, document ingestion, and voice features. Use it to simulate production behaviour while keeping sensitive credentials on your machine.
|
|
4
|
+
|
|
5
|
+
## Endpoints / API Usage
|
|
6
|
+
- `GET /api/memory` — synchronize long-term memory between IndexedDB and your gateway or vector database.
|
|
7
|
+
- `POST /api/tts` & `POST /api/stt` — enable voice experiences.
|
|
8
|
+
- `POST /api/vector/migrate` — optional endpoint to migrate stored knowledge to a managed vector index.
|
|
9
|
+
|
|
10
|
+
## Example Implementation
|
|
11
|
+
```bash
|
|
12
|
+
# Clone the repository and install dependencies
|
|
13
|
+
npm install
|
|
14
|
+
|
|
15
|
+
# Start the example gateway
|
|
16
|
+
cd packages/bandit-engine/examples/gateway-node
|
|
17
|
+
npm install
|
|
18
|
+
npm run dev
|
|
19
|
+
|
|
20
|
+
# Launch the Bandit site in development mode (private app)
|
|
21
|
+
npm run dev:development
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Within your app, enable vector support when available:
|
|
25
|
+
```ts
|
|
26
|
+
import { useVectorStore } from "@burtson-labs/bandit-engine";
|
|
27
|
+
|
|
28
|
+
const { isVectorEnabled, performMigration } = useVectorStore();
|
|
29
|
+
|
|
30
|
+
if (!isVectorEnabled) {
|
|
31
|
+
await performMigration();
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Integration Notes
|
|
36
|
+
- Configure environment variables such as `VITE_GATEWAY_API_URL`, `VITE_S3_API_URL`, and `VITE_DEFAULT_MODEL` in `.env.local`.
|
|
37
|
+
- Feature flags can be toggled per tier to expose advanced services only to entitled users.
|
|
38
|
+
- Vector migrations fall back to IndexedDB when the gateway is unavailable, ensuring your teams never lose data.
|
|
39
|
+
|
|
40
|
+
## Related Files
|
|
41
|
+
- [`src/services/vectorDatabase`](../src/services/vectorDatabase)
|
|
42
|
+
- [`src/hooks/useVoices.ts`](../src/hooks/useVoices.ts)
|
|
43
|
+
- [`docs/03_provider_integration.md`](./03_provider_integration.md)
|