prepia 1.0.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/LICENSE +21 -0
- package/README.md +312 -0
- package/bin/prepia.mjs +119 -0
- package/package.json +53 -0
- package/skill/SKILL.md +148 -0
- package/skill/config.json +29 -0
- package/src/analytics/dashboard.mjs +84 -0
- package/src/analytics/tracker.mjs +131 -0
- package/src/api/middleware.mjs +219 -0
- package/src/api/routes.mjs +142 -0
- package/src/api/server.mjs +150 -0
- package/src/cache/disk-store.mjs +199 -0
- package/src/cache/manager.mjs +142 -0
- package/src/cache/memory-store.mjs +205 -0
- package/src/chain/dag.mjs +209 -0
- package/src/chain/executor.mjs +103 -0
- package/src/chain/scheduler.mjs +89 -0
- package/src/client/adapters.mjs +483 -0
- package/src/client/connector.mjs +391 -0
- package/src/client/index.mjs +483 -0
- package/src/client/websocket.mjs +353 -0
- package/src/core/context-packager.mjs +169 -0
- package/src/core/engine.mjs +338 -0
- package/src/core/event-bus.mjs +84 -0
- package/src/core/prepimshot.mjs +120 -0
- package/src/core/task-decomposer.mjs +158 -0
- package/src/edge/lite.mjs +90 -0
- package/src/guard/checker.mjs +123 -0
- package/src/guard/fact-checker.mjs +105 -0
- package/src/guard/hallucination.mjs +108 -0
- package/src/index.mjs +67 -0
- package/src/models/local-model.mjs +171 -0
- package/src/models/provider.mjs +192 -0
- package/src/models/router.mjs +156 -0
- package/src/morph/optimizer.mjs +142 -0
- package/src/network/p2p.mjs +146 -0
- package/src/persona/detector.mjs +118 -0
- package/src/plugins/loader.mjs +120 -0
- package/src/plugins/registry.mjs +164 -0
- package/src/plugins/sandbox.mjs +79 -0
- package/src/rate/limiter.mjs +145 -0
- package/src/rate/shield.mjs +150 -0
- package/src/script/executor.mjs +164 -0
- package/src/script/parser.mjs +134 -0
- package/src/security/privacy.mjs +108 -0
- package/src/security/sanitizer.mjs +133 -0
- package/src/shadow/daemon.mjs +128 -0
- package/src/stream/handler.mjs +204 -0
- package/src/tools/calculator.mjs +312 -0
- package/src/tools/file-ops.mjs +138 -0
- package/src/tools/http-client.mjs +127 -0
- package/src/tools/orchestrator.mjs +205 -0
- package/src/tools/web-scraper.mjs +159 -0
- package/src/tools/web-search.mjs +129 -0
- package/src/vault/knowledge-base.mjs +207 -0
- package/src/vault/pattern-learner.mjs +192 -0
- package/workflows/analyze.json +32 -0
- package/workflows/automate.json +32 -0
- package/workflows/research.json +37 -0
- package/workflows/summarize.json +32 -0
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prepia Universal Client SDK
|
|
3
|
+
* Drop-in client for ANY AI agent to connect to Prepia
|
|
4
|
+
* Works with: OpenClaw, AutoGPT, CrewAI, LangChain, custom bots, anything
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* import { PrepiClient } from 'prepia/client';
|
|
8
|
+
* const prepi = new PrepiClient({ host: 'localhost', port: 4710 });
|
|
9
|
+
* const result = await prepi.task('Research top 5 phones and make a table');
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { EventEmitter } from 'events';
|
|
13
|
+
import http from 'http';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Simple WebSocket client using net.Socket
|
|
17
|
+
* No external dependencies — connects via raw TCP + WebSocket handshake
|
|
18
|
+
*/
|
|
19
|
+
class SimpleWebSocket extends EventEmitter {
|
|
20
|
+
constructor(url, options = {}) {
|
|
21
|
+
super();
|
|
22
|
+
this.url = url;
|
|
23
|
+
this.options = options;
|
|
24
|
+
this.socket = null;
|
|
25
|
+
this.connected = false;
|
|
26
|
+
this.buffer = Buffer.alloc(0);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
connect() {
|
|
30
|
+
const { hostname, port, pathname } = this._parseUrl(this.url);
|
|
31
|
+
const net = require('net');
|
|
32
|
+
const crypto = require('crypto');
|
|
33
|
+
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
this.socket = net.createConnection(port, hostname, () => {
|
|
36
|
+
const key = crypto.randomBytes(16).toString('base64');
|
|
37
|
+
const headers = [
|
|
38
|
+
`GET ${pathname} HTTP/1.1`,
|
|
39
|
+
`Host: ${hostname}:${port}`,
|
|
40
|
+
'Upgrade: websocket',
|
|
41
|
+
'Connection: Upgrade',
|
|
42
|
+
`Sec-WebSocket-Key: ${key}`,
|
|
43
|
+
'Sec-WebSocket-Version: 13',
|
|
44
|
+
'',
|
|
45
|
+
'',
|
|
46
|
+
].join('\r\n');
|
|
47
|
+
this.socket.write(headers);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
let handshakeDone = false;
|
|
51
|
+
this.socket.on('data', (chunk) => {
|
|
52
|
+
if (!handshakeDone) {
|
|
53
|
+
const str = chunk.toString();
|
|
54
|
+
if (str.includes('101 Switching Protocols')) {
|
|
55
|
+
handshakeDone = true;
|
|
56
|
+
this.connected = true;
|
|
57
|
+
this.emit('open');
|
|
58
|
+
resolve();
|
|
59
|
+
}
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
this._handleFrame(chunk);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
this.socket.on('close', () => {
|
|
66
|
+
this.connected = false;
|
|
67
|
+
this.emit('close');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
this.socket.on('error', (err) => {
|
|
71
|
+
this.emit('error', err);
|
|
72
|
+
if (!this.connected) reject(err);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
send(data) {
|
|
78
|
+
if (!this.connected || !this.socket) return;
|
|
79
|
+
const payload = typeof data === 'object' ? JSON.stringify(data) : String(data);
|
|
80
|
+
const mask = require('crypto').randomBytes(4);
|
|
81
|
+
const payloadBuf = Buffer.from(payload);
|
|
82
|
+
let header;
|
|
83
|
+
if (payloadBuf.length < 126) {
|
|
84
|
+
header = Buffer.alloc(2);
|
|
85
|
+
header[0] = 0x81;
|
|
86
|
+
header[1] = 0x80 | payloadBuf.length;
|
|
87
|
+
} else {
|
|
88
|
+
header = Buffer.alloc(4);
|
|
89
|
+
header[0] = 0x81;
|
|
90
|
+
header[1] = 0x80 | 126;
|
|
91
|
+
header.writeUInt16BE(payloadBuf.length, 2);
|
|
92
|
+
}
|
|
93
|
+
const masked = Buffer.alloc(payloadBuf.length);
|
|
94
|
+
for (let i = 0; i < payloadBuf.length; i++) masked[i] = payloadBuf[i] ^ mask[i % 4];
|
|
95
|
+
this.socket.write(Buffer.concat([header, mask, masked]));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
close() {
|
|
99
|
+
if (this.socket) this.socket.end();
|
|
100
|
+
this.connected = false;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
_handleFrame(chunk) {
|
|
104
|
+
// Simplified frame parsing for client
|
|
105
|
+
if (chunk.length < 2) return;
|
|
106
|
+
const opcode = chunk[0] & 0x0f;
|
|
107
|
+
if (opcode === 0x08) { this.close(); return; }
|
|
108
|
+
if (opcode === 0x09) { /* ping → send pong */ return; }
|
|
109
|
+
let offset = 2;
|
|
110
|
+
let len = chunk[1] & 0x7f;
|
|
111
|
+
if (len === 126) { len = chunk.readUInt16BE(2); offset = 4; }
|
|
112
|
+
const payload = chunk.slice(offset, offset + len).toString();
|
|
113
|
+
try { this.emit('message', JSON.parse(payload)); } catch { this.emit('message', payload); }
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
_parseUrl(url) {
|
|
117
|
+
const u = new URL(url);
|
|
118
|
+
return { hostname: u.hostname, port: parseInt(u.port) || 80, pathname: u.pathname || '/' };
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @typedef {Object} PrepiClientOptions
|
|
124
|
+
* @property {string} [host='localhost'] - Prepia server host
|
|
125
|
+
* @property {number} [port=4710] - Prepia server port
|
|
126
|
+
* @property {string} [apiKey] - API key for authentication
|
|
127
|
+
* @property {string} [protocol='http'] - 'http' or 'https'
|
|
128
|
+
* @property {number} [timeout=300000] - Default task timeout in ms
|
|
129
|
+
* @property {number} [retries=3] - Default retry count
|
|
130
|
+
* @property {boolean} [stream=false] - Enable streaming by default
|
|
131
|
+
* @property {string} [agentId] - Identifier for the connecting agent
|
|
132
|
+
* @property {string} [agentType='generic'] - Agent framework type
|
|
133
|
+
*/
|
|
134
|
+
|
|
135
|
+
export class PrepiClient extends EventEmitter {
|
|
136
|
+
/** @param {PrepiClientOptions} options */
|
|
137
|
+
constructor(options = {}) {
|
|
138
|
+
super();
|
|
139
|
+
this.host = options.host || 'localhost';
|
|
140
|
+
this.port = options.port || 4710;
|
|
141
|
+
this.apiKey = options.apiKey || null;
|
|
142
|
+
this.protocol = options.protocol || 'http';
|
|
143
|
+
this.timeout = options.timeout || 300000;
|
|
144
|
+
this.retries = options.retries || 3;
|
|
145
|
+
this.stream = options.stream || false;
|
|
146
|
+
this.agentId = options.agentId || `agent-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
147
|
+
this.agentType = options.agentType || 'generic';
|
|
148
|
+
this.baseUrl = `${this.protocol}://${this.host}:${this.port}`;
|
|
149
|
+
this.ws = null;
|
|
150
|
+
this.connected = false;
|
|
151
|
+
this._taskId = 0;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Get request headers
|
|
156
|
+
* @returns {Object}
|
|
157
|
+
*/
|
|
158
|
+
_headers() {
|
|
159
|
+
const h = {
|
|
160
|
+
'Content-Type': 'application/json',
|
|
161
|
+
'X-Prepia-Agent-Id': this.agentId,
|
|
162
|
+
'X-Prepia-Agent-Type': this.agentType,
|
|
163
|
+
};
|
|
164
|
+
if (this.apiKey) h['Authorization'] = `Bearer ${this.apiKey}`;
|
|
165
|
+
return h;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Make an HTTP request to Prepia
|
|
170
|
+
* @param {string} method
|
|
171
|
+
* @param {string} path
|
|
172
|
+
* @param {Object} [body]
|
|
173
|
+
* @returns {Promise<Object>}
|
|
174
|
+
*/
|
|
175
|
+
async _request(method, path, body = null) {
|
|
176
|
+
const url = `${this.baseUrl}${path}`;
|
|
177
|
+
const opts = {
|
|
178
|
+
method,
|
|
179
|
+
headers: this._headers(),
|
|
180
|
+
signal: AbortSignal.timeout(this.timeout),
|
|
181
|
+
};
|
|
182
|
+
if (body) opts.body = JSON.stringify(body);
|
|
183
|
+
|
|
184
|
+
let lastError;
|
|
185
|
+
for (let attempt = 1; attempt <= this.retries; attempt++) {
|
|
186
|
+
try {
|
|
187
|
+
const res = await fetch(url, opts);
|
|
188
|
+
const data = await res.json();
|
|
189
|
+
if (!res.ok) {
|
|
190
|
+
const err = new Error(data.error || `HTTP ${res.status}`);
|
|
191
|
+
err.status = res.status;
|
|
192
|
+
err.data = data;
|
|
193
|
+
throw err;
|
|
194
|
+
}
|
|
195
|
+
return data;
|
|
196
|
+
} catch (err) {
|
|
197
|
+
lastError = err;
|
|
198
|
+
if (attempt < this.retries && (err.code === 'ECONNREFUSED' || err.code === 'ETIMEDOUT' || err.status >= 500)) {
|
|
199
|
+
await new Promise(r => setTimeout(r, 1000 * attempt));
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
throw err;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
throw lastError;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Connect via WebSocket for real-time streaming
|
|
210
|
+
* @returns {Promise<void>}
|
|
211
|
+
*/
|
|
212
|
+
async connect() {
|
|
213
|
+
if (this.connected) return;
|
|
214
|
+
return new Promise((resolve, reject) => {
|
|
215
|
+
const wsUrl = this.baseUrl.replace(/^http/, 'ws') + '/ws';
|
|
216
|
+
this.ws = new SimpleWebSocket(wsUrl, {
|
|
217
|
+
headers: this._headers(),
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
this.ws.on('open', () => {
|
|
221
|
+
this.connected = true;
|
|
222
|
+
this.emit('connected');
|
|
223
|
+
resolve();
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
this.ws.on('message', (data) => {
|
|
227
|
+
try {
|
|
228
|
+
const msg = JSON.parse(data.toString());
|
|
229
|
+
this.emit(msg.event, msg.data);
|
|
230
|
+
this.emit('message', msg);
|
|
231
|
+
} catch {
|
|
232
|
+
this.emit('raw', data);
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
this.ws.on('close', () => {
|
|
237
|
+
this.connected = false;
|
|
238
|
+
this.emit('disconnected');
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
this.ws.on('error', (err) => {
|
|
242
|
+
this.emit('error', err);
|
|
243
|
+
if (!this.connected) reject(err);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Disconnect WebSocket
|
|
250
|
+
*/
|
|
251
|
+
disconnect() {
|
|
252
|
+
if (this.ws) {
|
|
253
|
+
this.ws.close();
|
|
254
|
+
this.ws = null;
|
|
255
|
+
this.connected = false;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Submit a task to Prepia (the main method agents use)
|
|
261
|
+
* @param {string|Object} task - Task description or task object
|
|
262
|
+
* @param {Object} [options] - Task options
|
|
263
|
+
* @returns {Promise<Object>} Task result
|
|
264
|
+
*
|
|
265
|
+
* @example
|
|
266
|
+
* // Simple string task
|
|
267
|
+
* const result = await prepi.task('What is the capital of France?');
|
|
268
|
+
*
|
|
269
|
+
* @example
|
|
270
|
+
* // Detailed task with options
|
|
271
|
+
* const result = await prepi.task({
|
|
272
|
+
* description: 'Research top phones and compare',
|
|
273
|
+
* mode: 'shot', // 'flash', 'shot', 'stream'
|
|
274
|
+
* tools: ['web-search', 'calculator'],
|
|
275
|
+
* cache: true,
|
|
276
|
+
* maxTokens: 2000,
|
|
277
|
+
* });
|
|
278
|
+
*/
|
|
279
|
+
async task(task, options = {}) {
|
|
280
|
+
const taskObj = typeof task === 'string' ? { description: task } : task;
|
|
281
|
+
const payload = {
|
|
282
|
+
...taskObj,
|
|
283
|
+
agentId: this.agentId,
|
|
284
|
+
agentType: this.agentType,
|
|
285
|
+
...options,
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
if (this.stream || payload.mode === 'stream') {
|
|
289
|
+
return this._streamTask(payload);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return this._request('POST', '/api/task', payload);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Submit task with streaming progress
|
|
297
|
+
* @param {Object} payload
|
|
298
|
+
* @returns {Promise<Object>}
|
|
299
|
+
*/
|
|
300
|
+
async _streamTask(payload) {
|
|
301
|
+
if (!this.connected) await this.connect();
|
|
302
|
+
|
|
303
|
+
return new Promise((resolve, reject) => {
|
|
304
|
+
const taskId = `task-${++this._taskId}-${Date.now()}`;
|
|
305
|
+
const result = { phases: [], final: null };
|
|
306
|
+
|
|
307
|
+
const onMessage = (msg) => {
|
|
308
|
+
if (msg.taskId !== taskId) return;
|
|
309
|
+
|
|
310
|
+
switch (msg.event) {
|
|
311
|
+
case 'task:progress':
|
|
312
|
+
result.phases.push(msg.data);
|
|
313
|
+
this.emit('progress', msg.data);
|
|
314
|
+
break;
|
|
315
|
+
case 'task:complete':
|
|
316
|
+
result.final = msg.data;
|
|
317
|
+
cleanup();
|
|
318
|
+
resolve(result);
|
|
319
|
+
break;
|
|
320
|
+
case 'task:error':
|
|
321
|
+
cleanup();
|
|
322
|
+
reject(new Error(msg.data.error));
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
const cleanup = () => {
|
|
328
|
+
this.removeListener('message', onMessage);
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
this.on('message', onMessage);
|
|
332
|
+
|
|
333
|
+
this.ws.send(JSON.stringify({
|
|
334
|
+
event: 'task:submit',
|
|
335
|
+
taskId,
|
|
336
|
+
data: payload,
|
|
337
|
+
}));
|
|
338
|
+
|
|
339
|
+
// Timeout safety
|
|
340
|
+
setTimeout(() => {
|
|
341
|
+
cleanup();
|
|
342
|
+
reject(new Error('Task timeout'));
|
|
343
|
+
}, this.timeout);
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Quick query — instant answers (PrepiFlash mode)
|
|
349
|
+
* @param {string} query
|
|
350
|
+
* @returns {Promise<Object>}
|
|
351
|
+
*
|
|
352
|
+
* @example
|
|
353
|
+
* const r = await prepi.quick('What is 2+2?');
|
|
354
|
+
* console.log(r.answer); // 4
|
|
355
|
+
*/
|
|
356
|
+
async quick(query) {
|
|
357
|
+
return this._request('POST', '/api/task', {
|
|
358
|
+
description: query,
|
|
359
|
+
mode: 'flash',
|
|
360
|
+
agentId: this.agentId,
|
|
361
|
+
agentType: this.agentType,
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Optimized single-LLM-call task (PrepiShot mode)
|
|
367
|
+
* @param {string} description
|
|
368
|
+
* @param {Object} [options]
|
|
369
|
+
* @returns {Promise<Object>}
|
|
370
|
+
*/
|
|
371
|
+
async shot(description, options = {}) {
|
|
372
|
+
return this._request('POST', '/api/task', {
|
|
373
|
+
description,
|
|
374
|
+
mode: 'shot',
|
|
375
|
+
agentId: this.agentId,
|
|
376
|
+
agentType: this.agentType,
|
|
377
|
+
...options,
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Check Prepia server health
|
|
383
|
+
* @returns {Promise<Object>}
|
|
384
|
+
*/
|
|
385
|
+
async health() {
|
|
386
|
+
return this._request('GET', '/api/health');
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Get usage analytics
|
|
391
|
+
* @param {Object} [filters]
|
|
392
|
+
* @returns {Promise<Object>}
|
|
393
|
+
*/
|
|
394
|
+
async analytics(filters = {}) {
|
|
395
|
+
const params = new URLSearchParams(filters).toString();
|
|
396
|
+
return this._request('GET', `/api/analytics${params ? '?' + params : ''}`);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Clear cache
|
|
401
|
+
* @param {string} [key] - Specific key, or all if omitted
|
|
402
|
+
* @returns {Promise<Object>}
|
|
403
|
+
*/
|
|
404
|
+
async clearCache(key) {
|
|
405
|
+
const path = key ? `/api/cache/${encodeURIComponent(key)}` : '/api/cache';
|
|
406
|
+
return this._request('DELETE', path);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* List installed plugins
|
|
411
|
+
* @returns {Promise<Object>}
|
|
412
|
+
*/
|
|
413
|
+
async plugins() {
|
|
414
|
+
return this._request('GET', '/api/plugins');
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Get/set configuration
|
|
419
|
+
* @param {Object} [config]
|
|
420
|
+
* @returns {Promise<Object>}
|
|
421
|
+
*/
|
|
422
|
+
async config(config) {
|
|
423
|
+
if (config) return this._request('POST', '/api/config', config);
|
|
424
|
+
return this._request('GET', '/api/config');
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Execute a PrepiScript
|
|
429
|
+
* @param {string} script
|
|
430
|
+
* @returns {Promise<Object>}
|
|
431
|
+
*/
|
|
432
|
+
async script(script) {
|
|
433
|
+
return this._request('POST', '/api/script', { script });
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Get knowledge base entries
|
|
438
|
+
* @param {string} [query]
|
|
439
|
+
* @returns {Promise<Object>}
|
|
440
|
+
*/
|
|
441
|
+
async knowledge(query) {
|
|
442
|
+
const params = query ? `?q=${encodeURIComponent(query)}` : '';
|
|
443
|
+
return this._request('GET', `/api/knowledge${params}`);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Store something in the knowledge base
|
|
448
|
+
* @param {string} key
|
|
449
|
+
* @param {*} value
|
|
450
|
+
* @param {Object} [meta]
|
|
451
|
+
* @returns {Promise<Object>}
|
|
452
|
+
*/
|
|
453
|
+
async store(key, value, meta = {}) {
|
|
454
|
+
return this._request('POST', '/api/knowledge', { key, value, ...meta });
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Create a Prepia client with minimal config
|
|
460
|
+
* @param {string|Object} [config] - URL string or options object
|
|
461
|
+
* @returns {PrepiClient}
|
|
462
|
+
*
|
|
463
|
+
* @example
|
|
464
|
+
* // From URL string
|
|
465
|
+
* const prepi = prepiConnect('http://localhost:4710');
|
|
466
|
+
*
|
|
467
|
+
* @example
|
|
468
|
+
* // Simple options
|
|
469
|
+
* const prepi = prepiConnect({ port: 4710, apiKey: 'my-key' });
|
|
470
|
+
*/
|
|
471
|
+
export function prepiConnect(config = {}) {
|
|
472
|
+
if (typeof config === 'string') {
|
|
473
|
+
const url = new URL(config);
|
|
474
|
+
return new PrepiClient({
|
|
475
|
+
protocol: url.protocol.replace(':', ''),
|
|
476
|
+
host: url.hostname,
|
|
477
|
+
port: parseInt(url.port) || 4710,
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
return new PrepiClient(config);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
export default PrepiClient;
|