@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 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
+ [![Website](https://img.shields.io/badge/Website-orchata.ai-blue?style=for-the-badge&logo=internet-explorer)](https://orchata.ai)
13
+ [![GitHub](https://img.shields.io/badge/GitHub-Repository-black?style=for-the-badge&logo=github)](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