@orchata-ai/sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +420 -0
- package/dist/ai.cjs +266 -0
- package/dist/ai.cjs.map +1 -0
- package/dist/ai.d.cts +95 -0
- package/dist/ai.d.ts +95 -0
- package/dist/ai.js +263 -0
- package/dist/ai.js.map +1 -0
- package/dist/client-Bs_xoN9p.d.cts +752 -0
- package/dist/client-Bs_xoN9p.d.ts +752 -0
- package/dist/index.cjs +704 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +84 -0
- package/dist/index.d.ts +84 -0
- package/dist/index.js +688 -0
- package/dist/index.js.map +1 -0
- package/package.json +83 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Orchata
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://cdn.orchata.ai/img/orchata-logo-dark.svg">
|
|
4
|
+
<img alt="Orchata Logo" src="https://cdn.orchata.ai/img/orchata-logo-light.svg">
|
|
5
|
+
</picture>
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
<div align="center">
|
|
9
|
+
|
|
10
|
+
**Infrastructure for intelligent applications**
|
|
11
|
+
|
|
12
|
+
[](https://orchata.ai)
|
|
13
|
+
[](https://github.com/orchata-ai)
|
|
14
|
+
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
## Orchata TypeScript SDK
|
|
18
|
+
|
|
19
|
+
The official TypeScript/JavaScript SDK for [Orchata](https://orchata.ai).
|
|
20
|
+
|
|
21
|
+
## Features
|
|
22
|
+
|
|
23
|
+
- **Type-safe** - Full TypeScript support with auto-completion
|
|
24
|
+
- **Universal** - Works with Node.js 18+, Deno, Bun, and browsers
|
|
25
|
+
- **Zero runtime dependencies** - Uses native `fetch` for HTTP requests
|
|
26
|
+
- **Modern** - ESM-first with CommonJS fallback
|
|
27
|
+
- **AI-ready** - Built-in tools for Vercel AI SDK v5+ integration
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# npm
|
|
33
|
+
npm install @orchata-ai/sdk
|
|
34
|
+
|
|
35
|
+
# pnpm
|
|
36
|
+
pnpm add @orchata-ai/sdk
|
|
37
|
+
|
|
38
|
+
# yarn
|
|
39
|
+
yarn add @orchata-ai/sdk
|
|
40
|
+
|
|
41
|
+
# bun
|
|
42
|
+
bun add @orchata-ai/sdk
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Optional: AI SDK Integration
|
|
46
|
+
|
|
47
|
+
If you want to use the Vercel AI SDK tools (`@orchata-ai/sdk/ai`), also install:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm install ai@^5.0.0 zod@^3.22.0
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Quick Start
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { Orchata } from '@orchata-ai/sdk';
|
|
57
|
+
|
|
58
|
+
const client = new Orchata({
|
|
59
|
+
apiKey: 'oai_your_api_key' // Get one at https://app.orchata.ai
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Query your knowledge base
|
|
63
|
+
const { results } = await client.query({
|
|
64
|
+
spaceIds: 'space_123',
|
|
65
|
+
query: 'How do I reset my password?'
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
console.log(results[0].chunk.content);
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Usage
|
|
72
|
+
|
|
73
|
+
### Spaces
|
|
74
|
+
|
|
75
|
+
Spaces are knowledge bases that contain your documents.
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
// List all spaces
|
|
79
|
+
const { spaces, total } = await client.spaces.list();
|
|
80
|
+
|
|
81
|
+
// Create a new space
|
|
82
|
+
const { space } = await client.spaces.create({
|
|
83
|
+
name: 'Documentation',
|
|
84
|
+
description: 'Product documentation and guides',
|
|
85
|
+
icon: 'book'
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Get a specific space
|
|
89
|
+
const { space } = await client.spaces.get('space_123');
|
|
90
|
+
|
|
91
|
+
// Update a space
|
|
92
|
+
const { space } = await client.spaces.update('space_123', {
|
|
93
|
+
name: 'Updated Name',
|
|
94
|
+
description: 'New description'
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Delete a space
|
|
98
|
+
await client.spaces.delete('space_123');
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Documents
|
|
102
|
+
|
|
103
|
+
Documents are the content you want to query.
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
// List documents in a space
|
|
107
|
+
const { documents } = await client.documents.list({
|
|
108
|
+
spaceId: 'space_123'
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Upload a document (raw content)
|
|
112
|
+
const { document } = await client.documents.upload({
|
|
113
|
+
spaceId: 'space_123',
|
|
114
|
+
content: '# My Document\n\nSome markdown content...',
|
|
115
|
+
filename: 'my-doc.md',
|
|
116
|
+
metadata: { category: 'guides' }
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// Upload a file (browser)
|
|
120
|
+
const { document } = await client.documents.uploadFile({
|
|
121
|
+
spaceId: 'space_123',
|
|
122
|
+
file: fileInput.files[0]
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Batch upload multiple documents
|
|
126
|
+
const result = await client.documents.batchUpload({
|
|
127
|
+
spaceId: 'space_123',
|
|
128
|
+
documents: [
|
|
129
|
+
{ filename: 'doc1.md', content: '# Doc 1\n\nContent...' },
|
|
130
|
+
{ filename: 'doc2.md', content: '# Doc 2\n\nContent...' },
|
|
131
|
+
]
|
|
132
|
+
});
|
|
133
|
+
console.log(`Uploaded: ${result.totalSuccessful}, Failed: ${result.totalFailed}`);
|
|
134
|
+
|
|
135
|
+
// Get processed content
|
|
136
|
+
const { content } = await client.documents.getContent('doc_123', 'space_123');
|
|
137
|
+
|
|
138
|
+
// Delete a document
|
|
139
|
+
await client.documents.delete('doc_123', 'space_123');
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Queries
|
|
143
|
+
|
|
144
|
+
Query your knowledge base using semantic search.
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
// Simple query
|
|
148
|
+
const { results } = await client.query({
|
|
149
|
+
spaceIds: 'space_123',
|
|
150
|
+
query: 'How do I authenticate?'
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Query multiple spaces
|
|
154
|
+
const { results } = await client.query({
|
|
155
|
+
spaceIds: ['space_123', 'space_456'],
|
|
156
|
+
query: 'authentication',
|
|
157
|
+
topK: 5 // Return top 5 results
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Filter by metadata
|
|
161
|
+
const { results } = await client.query({
|
|
162
|
+
spaceIds: 'space_123',
|
|
163
|
+
query: 'API reference',
|
|
164
|
+
metadata: { category: 'docs' }
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// Group results by space
|
|
168
|
+
const { groupedBySpace } = await client.query({
|
|
169
|
+
spaceIds: ['space_123', 'space_456'],
|
|
170
|
+
query: 'authentication',
|
|
171
|
+
groupBySpace: true
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Process results
|
|
175
|
+
for (const result of results) {
|
|
176
|
+
console.log(`Score: ${result.similarity}`);
|
|
177
|
+
console.log(`Content: ${result.chunk.content}`);
|
|
178
|
+
console.log(`Document: ${result.document.filename}`);
|
|
179
|
+
console.log(`Space: ${result.space.name}`);
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Smart Query
|
|
184
|
+
|
|
185
|
+
Discover which spaces are most relevant for a query.
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
// Find relevant spaces
|
|
189
|
+
const { relevantSpaces } = await client.smartQuery({
|
|
190
|
+
query: 'How do I authenticate users?',
|
|
191
|
+
maxSpaces: 3
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// Use different relevance methods
|
|
195
|
+
const { relevantSpaces } = await client.smartQuery({
|
|
196
|
+
query: 'authentication',
|
|
197
|
+
relevanceMethod: 'hybrid', // 'keyword', 'embedding', or 'hybrid'
|
|
198
|
+
keywordWeight: 0.5
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// Full workflow: discover then query
|
|
202
|
+
const { relevantSpaces } = await client.smartQuery({
|
|
203
|
+
query: 'user authentication'
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
const { results } = await client.query({
|
|
207
|
+
spaceIds: relevantSpaces.map(s => s.space.id),
|
|
208
|
+
query: 'user authentication'
|
|
209
|
+
});
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Vercel AI SDK Integration
|
|
213
|
+
|
|
214
|
+
The SDK includes tools for the [Vercel AI SDK](https://sdk.vercel.ai/) v5+, allowing AI models to query your knowledge base.
|
|
215
|
+
|
|
216
|
+
### Installation
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
# Install the SDK with AI SDK dependencies
|
|
220
|
+
npm install @orchata-ai/sdk ai zod
|
|
221
|
+
|
|
222
|
+
# Or with specific versions
|
|
223
|
+
npm install @orchata-ai/sdk ai@^5.0.0 zod@^3.22.0
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
> **Note:** The AI tools require `ai` v5.0.0+ and `zod` v3.22.0+ as peer dependencies. These are optional - if you don't need AI SDK integration, you can use the core SDK without them.
|
|
227
|
+
|
|
228
|
+
### Basic Usage
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
import { Orchata } from '@orchata-ai/sdk';
|
|
232
|
+
import { createOrchataTools } from '@orchata-ai/sdk/ai';
|
|
233
|
+
import { generateText } from 'ai';
|
|
234
|
+
import { openai } from '@ai-sdk/openai';
|
|
235
|
+
|
|
236
|
+
const client = new Orchata({ apiKey: 'oai_xxx' });
|
|
237
|
+
const tools = createOrchataTools(client);
|
|
238
|
+
|
|
239
|
+
const { text } = await generateText({
|
|
240
|
+
model: openai('gpt-4-turbo'),
|
|
241
|
+
tools,
|
|
242
|
+
prompt: 'What does our documentation say about authentication?'
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Available Tools
|
|
247
|
+
|
|
248
|
+
The `createOrchataTools` function creates these tools:
|
|
249
|
+
|
|
250
|
+
| Tool | Description |
|
|
251
|
+
|------|-------------|
|
|
252
|
+
| `queryKnowledge` | Search the knowledge base for relevant information |
|
|
253
|
+
| `findRelevantSpaces` | Discover which spaces are most relevant for a query |
|
|
254
|
+
| `listSpaces` | List all available knowledge spaces |
|
|
255
|
+
| `getDocumentContent` | Get the full content of a specific document |
|
|
256
|
+
| `uploadDocument` | Upload new content (disabled by default) |
|
|
257
|
+
| `createSpace` | Create a new space (disabled by default) |
|
|
258
|
+
|
|
259
|
+
### Simple Query Tool
|
|
260
|
+
|
|
261
|
+
For simple use cases, use the `createQueryTool` helper:
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
import { Orchata } from '@orchata-ai/sdk';
|
|
265
|
+
import { createQueryTool } from '@orchata-ai/sdk/ai';
|
|
266
|
+
import { generateText } from 'ai';
|
|
267
|
+
import { openai } from '@ai-sdk/openai';
|
|
268
|
+
|
|
269
|
+
const client = new Orchata({ apiKey: 'oai_xxx' });
|
|
270
|
+
|
|
271
|
+
// Create a tool that queries a specific space
|
|
272
|
+
const queryTool = createQueryTool(client, 'space_123');
|
|
273
|
+
|
|
274
|
+
const { text } = await generateText({
|
|
275
|
+
model: openai('gpt-4-turbo'),
|
|
276
|
+
tools: { query: queryTool },
|
|
277
|
+
prompt: 'What is our refund policy?'
|
|
278
|
+
});
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Configuration Options
|
|
282
|
+
|
|
283
|
+
```typescript
|
|
284
|
+
const tools = createOrchataTools(client, {
|
|
285
|
+
// Restrict which spaces the AI can access
|
|
286
|
+
allowedSpaceIds: ['space_123', 'space_456'],
|
|
287
|
+
|
|
288
|
+
// Default number of results (default: 5)
|
|
289
|
+
defaultTopK: 10,
|
|
290
|
+
|
|
291
|
+
// Enable document upload (default: false)
|
|
292
|
+
enableUpload: true,
|
|
293
|
+
|
|
294
|
+
// Enable space creation (default: false)
|
|
295
|
+
enableSpaceCreation: true,
|
|
296
|
+
});
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### With Streaming
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
import { streamText } from 'ai';
|
|
303
|
+
|
|
304
|
+
const result = streamText({
|
|
305
|
+
model: openai('gpt-4-turbo'),
|
|
306
|
+
tools,
|
|
307
|
+
prompt: 'Summarize our API documentation'
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
for await (const chunk of result.textStream) {
|
|
311
|
+
process.stdout.write(chunk);
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## Error Handling
|
|
316
|
+
|
|
317
|
+
The SDK throws typed errors for different scenarios:
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
import {
|
|
321
|
+
Orchata,
|
|
322
|
+
OrchataError,
|
|
323
|
+
AuthenticationError,
|
|
324
|
+
NotFoundError,
|
|
325
|
+
RateLimitError
|
|
326
|
+
} from '@orchata-ai/sdk';
|
|
327
|
+
|
|
328
|
+
try {
|
|
329
|
+
const { results } = await client.query({
|
|
330
|
+
spaceIds: 'space_123',
|
|
331
|
+
query: 'test'
|
|
332
|
+
});
|
|
333
|
+
} catch (error) {
|
|
334
|
+
if (error instanceof AuthenticationError) {
|
|
335
|
+
console.error('Invalid API key');
|
|
336
|
+
} else if (error instanceof NotFoundError) {
|
|
337
|
+
console.error('Space not found');
|
|
338
|
+
} else if (error instanceof RateLimitError) {
|
|
339
|
+
console.error(`Rate limited. Retry after ${error.retryAfter} seconds`);
|
|
340
|
+
} else if (error instanceof OrchataError) {
|
|
341
|
+
console.error(`API error: ${error.message} (${error.status})`);
|
|
342
|
+
} else {
|
|
343
|
+
throw error;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Error Types
|
|
349
|
+
|
|
350
|
+
| Error | Status | Description |
|
|
351
|
+
|-------|--------|-------------|
|
|
352
|
+
| `BadRequestError` | 400 | Invalid request parameters |
|
|
353
|
+
| `AuthenticationError` | 401 | Missing or invalid API key |
|
|
354
|
+
| `PermissionDeniedError` | 403 | Insufficient permissions |
|
|
355
|
+
| `NotFoundError` | 404 | Resource not found |
|
|
356
|
+
| `ConflictError` | 409 | Resource conflict |
|
|
357
|
+
| `UnprocessableEntityError` | 422 | Validation error |
|
|
358
|
+
| `RateLimitError` | 429 | Too many requests |
|
|
359
|
+
| `InternalServerError` | 5xx | Server error |
|
|
360
|
+
| `TimeoutError` | - | Request timeout |
|
|
361
|
+
| `ConnectionError` | - | Network connectivity issue |
|
|
362
|
+
|
|
363
|
+
## Configuration
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
const client = new Orchata({
|
|
367
|
+
// Required: Your API key
|
|
368
|
+
apiKey: 'oai_xxx',
|
|
369
|
+
|
|
370
|
+
// Optional: Custom base URL (default: https://api.orchata.ai)
|
|
371
|
+
baseUrl: 'https://api.orchata.ai',
|
|
372
|
+
|
|
373
|
+
// Optional: Request timeout in ms (default: 30000)
|
|
374
|
+
timeout: 30000,
|
|
375
|
+
|
|
376
|
+
// Optional: Custom fetch implementation
|
|
377
|
+
fetch: customFetch
|
|
378
|
+
});
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
## Runtime Support
|
|
382
|
+
|
|
383
|
+
| Runtime | Supported | Notes |
|
|
384
|
+
|---------|-----------|-------|
|
|
385
|
+
| Node.js 18+ | ✅ | Uses native fetch |
|
|
386
|
+
| Node.js 16-17 | ⚠️ | Requires fetch polyfill |
|
|
387
|
+
| Deno | ✅ | Full support |
|
|
388
|
+
| Bun | ✅ | Full support |
|
|
389
|
+
| Browsers | ✅ | Modern browsers |
|
|
390
|
+
| Cloudflare Workers | ✅ | Full support |
|
|
391
|
+
|
|
392
|
+
## TypeScript
|
|
393
|
+
|
|
394
|
+
The SDK is written in TypeScript and provides full type definitions:
|
|
395
|
+
|
|
396
|
+
```typescript
|
|
397
|
+
import type {
|
|
398
|
+
Space,
|
|
399
|
+
Document,
|
|
400
|
+
QueryParams,
|
|
401
|
+
QueryResponse,
|
|
402
|
+
QueryResultItem
|
|
403
|
+
} from '@orchata-ai/sdk';
|
|
404
|
+
|
|
405
|
+
// Types are automatically inferred
|
|
406
|
+
const { spaces } = await client.spaces.list();
|
|
407
|
+
// ^? Space[]
|
|
408
|
+
|
|
409
|
+
const { results } = await client.query({ spaceIds: 'x', query: 'test' });
|
|
410
|
+
// ^? QueryResultItem[]
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
## Contributing
|
|
414
|
+
|
|
415
|
+
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
416
|
+
|
|
417
|
+
## License
|
|
418
|
+
|
|
419
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
420
|
+
|
package/dist/ai.cjs
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var ai = require('ai');
|
|
4
|
+
var zod = require('zod');
|
|
5
|
+
|
|
6
|
+
// src/ai/tools.ts
|
|
7
|
+
function createOrchataTools(client, options = {}) {
|
|
8
|
+
const {
|
|
9
|
+
allowedSpaceIds,
|
|
10
|
+
defaultTopK = 5,
|
|
11
|
+
enableUpload = false,
|
|
12
|
+
enableSpaceCreation = false
|
|
13
|
+
} = options;
|
|
14
|
+
const tools = {};
|
|
15
|
+
tools.queryKnowledge = ai.tool({
|
|
16
|
+
description: "Search the knowledge base for relevant information. Returns the most similar content chunks from documents. Use this when you need to find specific information or answer questions based on stored knowledge.",
|
|
17
|
+
inputSchema: zod.z.object({
|
|
18
|
+
query: zod.z.string().describe("The search query or question to find relevant content for"),
|
|
19
|
+
spaceIds: zod.z.union([zod.z.string(), zod.z.array(zod.z.string())]).optional().describe(
|
|
20
|
+
"Space ID(s) to search in. If not provided, searches all accessible spaces."
|
|
21
|
+
),
|
|
22
|
+
topK: zod.z.number().int().min(1).max(20).optional().describe(`Number of results to return (default: ${defaultTopK})`)
|
|
23
|
+
}),
|
|
24
|
+
execute: async ({ query, spaceIds, topK }) => {
|
|
25
|
+
let targetSpaceIds = spaceIds;
|
|
26
|
+
if (allowedSpaceIds && allowedSpaceIds.length > 0) {
|
|
27
|
+
if (targetSpaceIds) {
|
|
28
|
+
const requested = Array.isArray(targetSpaceIds) ? targetSpaceIds : [targetSpaceIds];
|
|
29
|
+
targetSpaceIds = requested.filter(
|
|
30
|
+
(id) => allowedSpaceIds.includes(id)
|
|
31
|
+
);
|
|
32
|
+
if (targetSpaceIds.length === 0) {
|
|
33
|
+
return {
|
|
34
|
+
error: "None of the requested spaces are accessible",
|
|
35
|
+
results: []
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
targetSpaceIds = allowedSpaceIds;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (!targetSpaceIds) {
|
|
43
|
+
const { relevantSpaces } = await client.smartQuery({
|
|
44
|
+
query,
|
|
45
|
+
maxSpaces: 3
|
|
46
|
+
});
|
|
47
|
+
if (relevantSpaces.length === 0) {
|
|
48
|
+
return {
|
|
49
|
+
message: "No relevant spaces found for this query",
|
|
50
|
+
results: []
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
targetSpaceIds = relevantSpaces.map((s) => s.space.id);
|
|
54
|
+
}
|
|
55
|
+
const { results, totalResults } = await client.query({
|
|
56
|
+
query,
|
|
57
|
+
spaceIds: targetSpaceIds,
|
|
58
|
+
topK: topK ?? defaultTopK
|
|
59
|
+
});
|
|
60
|
+
return {
|
|
61
|
+
totalResults,
|
|
62
|
+
results: results.map((r) => ({
|
|
63
|
+
content: r.chunk.content,
|
|
64
|
+
similarity: r.similarity,
|
|
65
|
+
document: {
|
|
66
|
+
id: r.document.id,
|
|
67
|
+
filename: r.document.filename
|
|
68
|
+
},
|
|
69
|
+
space: {
|
|
70
|
+
id: r.space.id,
|
|
71
|
+
name: r.space.name
|
|
72
|
+
}
|
|
73
|
+
}))
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
tools.findRelevantSpaces = ai.tool({
|
|
78
|
+
description: "Discover which knowledge spaces are most relevant for a query. Use this to understand what topics are covered or to find the right space before querying.",
|
|
79
|
+
inputSchema: zod.z.object({
|
|
80
|
+
query: zod.z.string().describe("The query to find relevant spaces for"),
|
|
81
|
+
maxSpaces: zod.z.number().int().min(1).max(10).optional().describe("Maximum number of spaces to return (default: 3)")
|
|
82
|
+
}),
|
|
83
|
+
execute: async ({ query, maxSpaces }) => {
|
|
84
|
+
const { relevantSpaces, totalSpaces } = await client.smartQuery({
|
|
85
|
+
query,
|
|
86
|
+
maxSpaces: maxSpaces ?? 3
|
|
87
|
+
});
|
|
88
|
+
let filtered = relevantSpaces;
|
|
89
|
+
if (allowedSpaceIds && allowedSpaceIds.length > 0) {
|
|
90
|
+
filtered = relevantSpaces.filter(
|
|
91
|
+
(s) => allowedSpaceIds.includes(s.space.id)
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
totalSpacesSearched: totalSpaces,
|
|
96
|
+
relevantSpaces: filtered.map((s) => ({
|
|
97
|
+
id: s.space.id,
|
|
98
|
+
name: s.space.name,
|
|
99
|
+
description: s.space.description,
|
|
100
|
+
relevanceScore: s.relevanceScore,
|
|
101
|
+
matchReason: s.matchReason
|
|
102
|
+
}))
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
tools.listSpaces = ai.tool({
|
|
107
|
+
description: "List all available knowledge spaces. Use this to see what topics or categories of knowledge are available.",
|
|
108
|
+
inputSchema: zod.z.object({
|
|
109
|
+
status: zod.z.enum(["active", "archived", "all"]).optional().describe("Filter by space status (default: active)")
|
|
110
|
+
}),
|
|
111
|
+
execute: async ({ status }) => {
|
|
112
|
+
const { spaces, total } = await client.spaces.list({
|
|
113
|
+
status: status ?? "active",
|
|
114
|
+
pageSize: 100
|
|
115
|
+
});
|
|
116
|
+
let filtered = spaces;
|
|
117
|
+
if (allowedSpaceIds && allowedSpaceIds.length > 0) {
|
|
118
|
+
filtered = spaces.filter((s) => allowedSpaceIds.includes(s.id));
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
total: filtered.length,
|
|
122
|
+
spaces: filtered.map((s) => ({
|
|
123
|
+
id: s.id,
|
|
124
|
+
name: s.name,
|
|
125
|
+
description: s.description,
|
|
126
|
+
icon: s.icon
|
|
127
|
+
}))
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
tools.getDocumentContent = ai.tool({
|
|
132
|
+
description: "Get the full processed content of a specific document. Use this when you need the complete text of a document after finding it via search.",
|
|
133
|
+
inputSchema: zod.z.object({
|
|
134
|
+
documentId: zod.z.string().describe("The ID of the document to retrieve"),
|
|
135
|
+
spaceId: zod.z.string().describe("The ID of the space containing the document")
|
|
136
|
+
}),
|
|
137
|
+
execute: async ({ documentId, spaceId }) => {
|
|
138
|
+
if (allowedSpaceIds && !allowedSpaceIds.includes(spaceId)) {
|
|
139
|
+
return { error: "Access denied to this space" };
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
const { content, filename } = await client.documents.getContent(
|
|
143
|
+
documentId,
|
|
144
|
+
spaceId
|
|
145
|
+
);
|
|
146
|
+
return { filename, content };
|
|
147
|
+
} catch (error) {
|
|
148
|
+
return {
|
|
149
|
+
error: error instanceof Error ? error.message : "Failed to get document"
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
if (enableUpload) {
|
|
155
|
+
tools.uploadDocument = ai.tool({
|
|
156
|
+
description: "Upload new content to the knowledge base. Use this to add new information that should be searchable.",
|
|
157
|
+
inputSchema: zod.z.object({
|
|
158
|
+
spaceId: zod.z.string().describe("The ID of the space to upload the document to"),
|
|
159
|
+
content: zod.z.string().describe("The markdown or text content to upload"),
|
|
160
|
+
filename: zod.z.string().optional().describe("Optional filename (defaults to document.md)")
|
|
161
|
+
}),
|
|
162
|
+
execute: async ({ spaceId, content, filename }) => {
|
|
163
|
+
if (allowedSpaceIds && !allowedSpaceIds.includes(spaceId)) {
|
|
164
|
+
return { error: "Access denied to this space" };
|
|
165
|
+
}
|
|
166
|
+
try {
|
|
167
|
+
const { document } = await client.documents.upload({
|
|
168
|
+
spaceId,
|
|
169
|
+
content,
|
|
170
|
+
filename
|
|
171
|
+
});
|
|
172
|
+
return {
|
|
173
|
+
success: true,
|
|
174
|
+
documentId: document.id,
|
|
175
|
+
filename: document.filename,
|
|
176
|
+
status: document.status
|
|
177
|
+
};
|
|
178
|
+
} catch (error) {
|
|
179
|
+
return {
|
|
180
|
+
error: error instanceof Error ? error.message : "Failed to upload document"
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
if (enableSpaceCreation) {
|
|
187
|
+
tools.createSpace = ai.tool({
|
|
188
|
+
description: "Create a new knowledge space. Use this to organize knowledge into a new category.",
|
|
189
|
+
inputSchema: zod.z.object({
|
|
190
|
+
name: zod.z.string().describe("The name of the space"),
|
|
191
|
+
description: zod.z.string().describe("A description of what the space contains"),
|
|
192
|
+
icon: zod.z.enum([
|
|
193
|
+
"folder",
|
|
194
|
+
"book",
|
|
195
|
+
"file-text",
|
|
196
|
+
"database",
|
|
197
|
+
"package",
|
|
198
|
+
"archive",
|
|
199
|
+
"briefcase",
|
|
200
|
+
"inbox",
|
|
201
|
+
"layers",
|
|
202
|
+
"box"
|
|
203
|
+
]).optional().describe("Icon for the space (default: folder)")
|
|
204
|
+
}),
|
|
205
|
+
execute: async ({ name, description, icon }) => {
|
|
206
|
+
try {
|
|
207
|
+
const { space } = await client.spaces.create({
|
|
208
|
+
name,
|
|
209
|
+
description,
|
|
210
|
+
icon: icon ?? "folder"
|
|
211
|
+
});
|
|
212
|
+
return {
|
|
213
|
+
success: true,
|
|
214
|
+
spaceId: space.id,
|
|
215
|
+
name: space.name,
|
|
216
|
+
slug: space.slug
|
|
217
|
+
};
|
|
218
|
+
} catch (error) {
|
|
219
|
+
return {
|
|
220
|
+
error: error instanceof Error ? error.message : "Failed to create space"
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
return tools;
|
|
227
|
+
}
|
|
228
|
+
function createQueryTool(client, spaceIds, options = {}) {
|
|
229
|
+
const { topK = 5 } = options;
|
|
230
|
+
return ai.tool({
|
|
231
|
+
description: "Search the knowledge base for relevant information. Returns the most similar content chunks from documents.",
|
|
232
|
+
inputSchema: zod.z.object({
|
|
233
|
+
query: zod.z.string().describe("The search query or question to find relevant content for")
|
|
234
|
+
}),
|
|
235
|
+
execute: async ({ query }) => {
|
|
236
|
+
let targetSpaceIds = spaceIds;
|
|
237
|
+
if (!targetSpaceIds) {
|
|
238
|
+
const { relevantSpaces } = await client.smartQuery({
|
|
239
|
+
query,
|
|
240
|
+
maxSpaces: 3
|
|
241
|
+
});
|
|
242
|
+
if (relevantSpaces.length === 0) {
|
|
243
|
+
return { results: [], message: "No relevant spaces found" };
|
|
244
|
+
}
|
|
245
|
+
targetSpaceIds = relevantSpaces.map((s) => s.space.id);
|
|
246
|
+
}
|
|
247
|
+
const { results } = await client.query({
|
|
248
|
+
query,
|
|
249
|
+
spaceIds: targetSpaceIds,
|
|
250
|
+
topK
|
|
251
|
+
});
|
|
252
|
+
return {
|
|
253
|
+
results: results.map((r) => ({
|
|
254
|
+
content: r.chunk.content,
|
|
255
|
+
similarity: r.similarity,
|
|
256
|
+
source: `${r.space.name} / ${r.document.filename}`
|
|
257
|
+
}))
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
exports.createOrchataTools = createOrchataTools;
|
|
264
|
+
exports.createQueryTool = createQueryTool;
|
|
265
|
+
//# sourceMappingURL=ai.cjs.map
|
|
266
|
+
//# sourceMappingURL=ai.cjs.map
|