@exulu/backend 1.48.2 → 1.49.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/dist/index.cjs +351 -42
- package/dist/index.d.cts +96 -1
- package/dist/index.d.ts +96 -1
- package/dist/index.js +340 -38
- package/ee/{markdown.ts → chunking/markdown.ts} +2 -2
- package/ee/python/README.md +295 -0
- package/ee/python/documents/processing/README.md +155 -0
- package/ee/{documents → python/documents}/processing/doc_processor.ts +25 -17
- package/ee/{documents/processing/pdf_to_markdown.py → python/documents/processing/document_to_markdown.py} +3 -10
- package/ee/python/setup.sh +180 -0
- package/package.json +14 -3
- package/scripts/postinstall.cjs +149 -0
- package/.agents/skills/mintlify/SKILL.md +0 -347
- package/.editorconfig +0 -15
- package/.eslintrc.json +0 -52
- package/.github/workflows/release-backend.yml +0 -38
- package/.husky/commit-msg +0 -1
- package/.jscpd.json +0 -18
- package/.mcp.json +0 -25
- package/.nvmrc +0 -1
- package/.prettierignore +0 -5
- package/.prettierrc.json +0 -12
- package/CHANGELOG.md +0 -8
- package/SECURITY.md +0 -5
- package/commitlint.config.js +0 -4
- package/devops/documentation/patch-older-releases.md +0 -42
- package/ee/documents/processing/build_pdf_processor.sh +0 -35
- package/ee/documents/processing/chunk_markdown.py +0 -263
- package/ee/documents/processing/pdf_processor.spec +0 -115
- package/eslint.config.js +0 -88
- package/jest.config.ts +0 -25
- package/mintlify-docs/.mintignore +0 -7
- package/mintlify-docs/AGENTS.md +0 -33
- package/mintlify-docs/CLAUDE.MD +0 -50
- package/mintlify-docs/CONTRIBUTING.md +0 -32
- package/mintlify-docs/LICENSE +0 -21
- package/mintlify-docs/README.md +0 -55
- package/mintlify-docs/ai-tools/claude-code.mdx +0 -43
- package/mintlify-docs/ai-tools/cursor.mdx +0 -39
- package/mintlify-docs/ai-tools/windsurf.mdx +0 -39
- package/mintlify-docs/api-reference/core-types/agent-types.mdx +0 -110
- package/mintlify-docs/api-reference/core-types/analytics-types.mdx +0 -95
- package/mintlify-docs/api-reference/core-types/configuration-types.mdx +0 -83
- package/mintlify-docs/api-reference/core-types/evaluation-types.mdx +0 -106
- package/mintlify-docs/api-reference/core-types/job-types.mdx +0 -135
- package/mintlify-docs/api-reference/core-types/overview.mdx +0 -73
- package/mintlify-docs/api-reference/core-types/prompt-types.mdx +0 -102
- package/mintlify-docs/api-reference/core-types/rbac-types.mdx +0 -163
- package/mintlify-docs/api-reference/core-types/session-types.mdx +0 -77
- package/mintlify-docs/api-reference/core-types/user-management.mdx +0 -112
- package/mintlify-docs/api-reference/core-types/workflow-types.mdx +0 -88
- package/mintlify-docs/api-reference/core-types.mdx +0 -585
- package/mintlify-docs/api-reference/dynamic-types.mdx +0 -851
- package/mintlify-docs/api-reference/endpoint/create.mdx +0 -4
- package/mintlify-docs/api-reference/endpoint/delete.mdx +0 -4
- package/mintlify-docs/api-reference/endpoint/get.mdx +0 -4
- package/mintlify-docs/api-reference/endpoint/webhook.mdx +0 -4
- package/mintlify-docs/api-reference/introduction.mdx +0 -661
- package/mintlify-docs/api-reference/mutations.mdx +0 -1012
- package/mintlify-docs/api-reference/openapi.json +0 -217
- package/mintlify-docs/api-reference/queries.mdx +0 -1154
- package/mintlify-docs/backend/introduction.mdx +0 -218
- package/mintlify-docs/changelog.mdx +0 -387
- package/mintlify-docs/community-edition.mdx +0 -304
- package/mintlify-docs/core/exulu-agent/api-reference.mdx +0 -894
- package/mintlify-docs/core/exulu-agent/configuration.mdx +0 -690
- package/mintlify-docs/core/exulu-agent/introduction.mdx +0 -552
- package/mintlify-docs/core/exulu-app/api-reference.mdx +0 -481
- package/mintlify-docs/core/exulu-app/configuration.mdx +0 -319
- package/mintlify-docs/core/exulu-app/introduction.mdx +0 -117
- package/mintlify-docs/core/exulu-authentication.mdx +0 -810
- package/mintlify-docs/core/exulu-chunkers/api-reference.mdx +0 -1011
- package/mintlify-docs/core/exulu-chunkers/configuration.mdx +0 -596
- package/mintlify-docs/core/exulu-chunkers/introduction.mdx +0 -403
- package/mintlify-docs/core/exulu-context/api-reference.mdx +0 -911
- package/mintlify-docs/core/exulu-context/configuration.mdx +0 -648
- package/mintlify-docs/core/exulu-context/introduction.mdx +0 -394
- package/mintlify-docs/core/exulu-database.mdx +0 -811
- package/mintlify-docs/core/exulu-default-agents.mdx +0 -545
- package/mintlify-docs/core/exulu-eval/api-reference.mdx +0 -772
- package/mintlify-docs/core/exulu-eval/configuration.mdx +0 -680
- package/mintlify-docs/core/exulu-eval/introduction.mdx +0 -459
- package/mintlify-docs/core/exulu-logging.mdx +0 -464
- package/mintlify-docs/core/exulu-otel.mdx +0 -670
- package/mintlify-docs/core/exulu-queues/api-reference.mdx +0 -648
- package/mintlify-docs/core/exulu-queues/configuration.mdx +0 -650
- package/mintlify-docs/core/exulu-queues/introduction.mdx +0 -474
- package/mintlify-docs/core/exulu-reranker/api-reference.mdx +0 -630
- package/mintlify-docs/core/exulu-reranker/configuration.mdx +0 -663
- package/mintlify-docs/core/exulu-reranker/introduction.mdx +0 -516
- package/mintlify-docs/core/exulu-tool/api-reference.mdx +0 -723
- package/mintlify-docs/core/exulu-tool/configuration.mdx +0 -805
- package/mintlify-docs/core/exulu-tool/introduction.mdx +0 -539
- package/mintlify-docs/core/exulu-variables/api-reference.mdx +0 -699
- package/mintlify-docs/core/exulu-variables/configuration.mdx +0 -736
- package/mintlify-docs/core/exulu-variables/introduction.mdx +0 -511
- package/mintlify-docs/development.mdx +0 -94
- package/mintlify-docs/docs.json +0 -248
- package/mintlify-docs/enterprise-edition.mdx +0 -538
- package/mintlify-docs/essentials/code.mdx +0 -35
- package/mintlify-docs/essentials/images.mdx +0 -59
- package/mintlify-docs/essentials/markdown.mdx +0 -88
- package/mintlify-docs/essentials/navigation.mdx +0 -87
- package/mintlify-docs/essentials/reusable-snippets.mdx +0 -110
- package/mintlify-docs/essentials/settings.mdx +0 -318
- package/mintlify-docs/favicon.svg +0 -3
- package/mintlify-docs/frontend/introduction.mdx +0 -39
- package/mintlify-docs/getting-started.mdx +0 -267
- package/mintlify-docs/guides/custom-agent.mdx +0 -608
- package/mintlify-docs/guides/first-agent.mdx +0 -315
- package/mintlify-docs/images/admin_ui.png +0 -0
- package/mintlify-docs/images/contexts.png +0 -0
- package/mintlify-docs/images/create_agents.png +0 -0
- package/mintlify-docs/images/evals.png +0 -0
- package/mintlify-docs/images/graphql.png +0 -0
- package/mintlify-docs/images/graphql_api.png +0 -0
- package/mintlify-docs/images/hero-dark.png +0 -0
- package/mintlify-docs/images/hero-light.png +0 -0
- package/mintlify-docs/images/hero.png +0 -0
- package/mintlify-docs/images/knowledge_sources.png +0 -0
- package/mintlify-docs/images/mcp.png +0 -0
- package/mintlify-docs/images/scaling.png +0 -0
- package/mintlify-docs/index.mdx +0 -411
- package/mintlify-docs/logo/dark.svg +0 -9
- package/mintlify-docs/logo/light.svg +0 -9
- package/mintlify-docs/partners.mdx +0 -558
- package/mintlify-docs/products.mdx +0 -77
- package/mintlify-docs/snippets/snippet-intro.mdx +0 -4
- package/mintlify-docs/styles.css +0 -207
- package/ngrok.bash +0 -1
- package/ngrok.md +0 -6
- package/ngrok.yml +0 -10
- package/release.config.cjs +0 -15
- package/skills-lock.json +0 -10
- package/types/context-processor.ts +0 -45
- package/types/enums/eval-types.ts +0 -5
- package/types/enums/field-types.ts +0 -1
- package/types/enums/jobs.ts +0 -11
- package/types/enums/statistics.ts +0 -13
- package/types/exulu-table-definition.ts +0 -79
- package/types/file-types.ts +0 -18
- package/types/models/agent-session.ts +0 -27
- package/types/models/agent.ts +0 -68
- package/types/models/context.ts +0 -53
- package/types/models/embedding.ts +0 -17
- package/types/models/eval-run.ts +0 -40
- package/types/models/exulu-agent-tool-config.ts +0 -11
- package/types/models/item.ts +0 -21
- package/types/models/job.ts +0 -8
- package/types/models/project.ts +0 -16
- package/types/models/rate-limiter-rules.ts +0 -7
- package/types/models/test-case.ts +0 -25
- package/types/models/tool.ts +0 -9
- package/types/models/user-role.ts +0 -12
- package/types/models/user.ts +0 -20
- package/types/models/variable.ts +0 -8
- package/types/models/vector-methods.ts +0 -7
- package/types/provider-config.ts +0 -21
- package/types/queue-config.ts +0 -16
- package/types/rbac-rights-modes.ts +0 -1
- package/types/statistics.ts +0 -20
- package/types/workflow.ts +0 -31
- /package/ee/{documents → python/documents}/THIRD_PARTY_LICENSES/docling.txt +0 -0
- /package/ee/{documents/processing → python}/requirements.txt +0 -0
|
@@ -1,630 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "API reference"
|
|
3
|
-
description: "Complete method and property reference for ExuluReranker"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
## Constructor
|
|
7
|
-
|
|
8
|
-
```typescript
|
|
9
|
-
const reranker = new ExuluReranker(options: ExuluRerankerOptions);
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
Creates a new ExuluReranker instance. See the [configuration guide](/core/exulu-reranker/configuration) for all available options.
|
|
13
|
-
|
|
14
|
-
## Methods
|
|
15
|
-
|
|
16
|
-
### run()
|
|
17
|
-
|
|
18
|
-
Executes the reranker to reorder search result chunks based on relevance to the query.
|
|
19
|
-
|
|
20
|
-
```typescript
|
|
21
|
-
async run(
|
|
22
|
-
query: string,
|
|
23
|
-
chunks: VectorSearchChunkResult[]
|
|
24
|
-
): Promise<VectorSearchChunkResult[]>
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
<ParamField path="query" type="string" required>
|
|
28
|
-
The user's search query that the chunks should be ranked against
|
|
29
|
-
</ParamField>
|
|
30
|
-
|
|
31
|
-
<ParamField path="chunks" type="VectorSearchChunkResult[]" required>
|
|
32
|
-
Array of search result chunks to rerank
|
|
33
|
-
</ParamField>
|
|
34
|
-
|
|
35
|
-
<ResponseField name="return" type="Promise<VectorSearchChunkResult[]>">
|
|
36
|
-
Reordered array of chunks, typically sorted by relevance (most relevant first)
|
|
37
|
-
</ResponseField>
|
|
38
|
-
|
|
39
|
-
```typescript
|
|
40
|
-
const reranker = new ExuluReranker({
|
|
41
|
-
id: "cohere_rerank",
|
|
42
|
-
name: "Cohere Reranker",
|
|
43
|
-
description: "Uses Cohere's rerank API",
|
|
44
|
-
execute: async ({ query, chunks }) => {
|
|
45
|
-
// Reranking logic
|
|
46
|
-
return reorderedChunks;
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
// Get initial search results
|
|
51
|
-
const searchResults = await context.search({
|
|
52
|
-
query: "How do I authenticate users?",
|
|
53
|
-
method: "hybridSearch",
|
|
54
|
-
limit: 20,
|
|
55
|
-
// ...
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
// Rerank the results
|
|
59
|
-
const rerankedChunks = await reranker.run(
|
|
60
|
-
"How do I authenticate users?",
|
|
61
|
-
searchResults.chunks
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
console.log(rerankedChunks[0].chunk_content); // Most relevant chunk
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
<Note>
|
|
68
|
-
The `run()` method is a convenience wrapper that calls the `execute()` function with the proper parameter structure.
|
|
69
|
-
</Note>
|
|
70
|
-
|
|
71
|
-
## Properties
|
|
72
|
-
|
|
73
|
-
### id
|
|
74
|
-
|
|
75
|
-
<ResponseField name="id" type="string">
|
|
76
|
-
Unique identifier for the reranker
|
|
77
|
-
</ResponseField>
|
|
78
|
-
|
|
79
|
-
```typescript
|
|
80
|
-
console.log(reranker.id); // "cohere_rerank_v3"
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### name
|
|
84
|
-
|
|
85
|
-
<ResponseField name="name" type="string">
|
|
86
|
-
Human-readable name for the reranker
|
|
87
|
-
</ResponseField>
|
|
88
|
-
|
|
89
|
-
```typescript
|
|
90
|
-
console.log(reranker.name); // "Cohere Rerank English v3"
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
### description
|
|
94
|
-
|
|
95
|
-
<ResponseField name="description" type="string">
|
|
96
|
-
Description of what the reranker does
|
|
97
|
-
</ResponseField>
|
|
98
|
-
|
|
99
|
-
```typescript
|
|
100
|
-
console.log(reranker.description);
|
|
101
|
-
// "Reranks search results using Cohere's rerank-english-v3.0 model"
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
### execute
|
|
105
|
-
|
|
106
|
-
<ResponseField name="execute" type="ExecuteFunction">
|
|
107
|
-
The function that implements the reranking logic
|
|
108
|
-
</ResponseField>
|
|
109
|
-
|
|
110
|
-
```typescript
|
|
111
|
-
// The execute function has this signature
|
|
112
|
-
type ExecuteFunction = (params: {
|
|
113
|
-
query: string;
|
|
114
|
-
chunks: VectorSearchChunkResult[];
|
|
115
|
-
}) => Promise<VectorSearchChunkResult[]>;
|
|
116
|
-
|
|
117
|
-
// Access it directly
|
|
118
|
-
const result = await reranker.execute({
|
|
119
|
-
query: "test query",
|
|
120
|
-
chunks: chunks
|
|
121
|
-
});
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
<Info>
|
|
125
|
-
While you can call `execute()` directly, it's recommended to use the `run()` method for better readability.
|
|
126
|
-
</Info>
|
|
127
|
-
|
|
128
|
-
## Type definitions
|
|
129
|
-
|
|
130
|
-
```typescript
|
|
131
|
-
// Reranker constructor options
|
|
132
|
-
type ExuluRerankerOptions = {
|
|
133
|
-
id: string;
|
|
134
|
-
name: string;
|
|
135
|
-
description: string;
|
|
136
|
-
execute: ExecuteFunction;
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
// Execute function type
|
|
140
|
-
type ExecuteFunction = (params: {
|
|
141
|
-
query: string;
|
|
142
|
-
chunks: VectorSearchChunkResult[];
|
|
143
|
-
}) => Promise<VectorSearchChunkResult[]>;
|
|
144
|
-
|
|
145
|
-
// Chunk result type
|
|
146
|
-
type VectorSearchChunkResult = {
|
|
147
|
-
chunk_content: string;
|
|
148
|
-
chunk_index: number;
|
|
149
|
-
chunk_id: string;
|
|
150
|
-
chunk_source: string;
|
|
151
|
-
chunk_metadata: Record<string, string>;
|
|
152
|
-
chunk_created_at: string;
|
|
153
|
-
chunk_updated_at: string;
|
|
154
|
-
item_id: string;
|
|
155
|
-
item_external_id: string;
|
|
156
|
-
item_name: string;
|
|
157
|
-
item_updated_at: string;
|
|
158
|
-
item_created_at: string;
|
|
159
|
-
chunk_cosine_distance?: number;
|
|
160
|
-
chunk_fts_rank?: number;
|
|
161
|
-
chunk_hybrid_score?: number;
|
|
162
|
-
context?: {
|
|
163
|
-
name: string;
|
|
164
|
-
id: string;
|
|
165
|
-
};
|
|
166
|
-
};
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
## Usage examples
|
|
170
|
-
|
|
171
|
-
### Basic usage
|
|
172
|
-
|
|
173
|
-
```typescript
|
|
174
|
-
import { ExuluReranker } from "@exulu/backend";
|
|
175
|
-
|
|
176
|
-
const reranker = new ExuluReranker({
|
|
177
|
-
id: "simple_reranker",
|
|
178
|
-
name: "Simple Reranker",
|
|
179
|
-
description: "Reranks by chunk length",
|
|
180
|
-
execute: async ({ query, chunks }) => {
|
|
181
|
-
// Sort by content length (example)
|
|
182
|
-
return chunks.sort((a, b) =>
|
|
183
|
-
b.chunk_content.length - a.chunk_content.length
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
const reranked = await reranker.run(query, chunks);
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
### With Cohere API
|
|
192
|
-
|
|
193
|
-
```typescript
|
|
194
|
-
const cohereReranker = new ExuluReranker({
|
|
195
|
-
id: "cohere_rerank",
|
|
196
|
-
name: "Cohere Reranker",
|
|
197
|
-
description: "Uses Cohere rerank-english-v3.0",
|
|
198
|
-
execute: async ({ query, chunks }) => {
|
|
199
|
-
const response = await fetch("https://api.cohere.com/v1/rerank", {
|
|
200
|
-
method: "POST",
|
|
201
|
-
headers: {
|
|
202
|
-
"Authorization": `Bearer ${process.env.COHERE_API_KEY}`,
|
|
203
|
-
"Content-Type": "application/json"
|
|
204
|
-
},
|
|
205
|
-
body: JSON.stringify({
|
|
206
|
-
model: "rerank-english-v3.0",
|
|
207
|
-
query: query,
|
|
208
|
-
documents: chunks.map(c => c.chunk_content),
|
|
209
|
-
top_n: 20
|
|
210
|
-
})
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
const data = await response.json();
|
|
214
|
-
|
|
215
|
-
return data.results
|
|
216
|
-
.sort((a, b) => b.relevance_score - a.relevance_score)
|
|
217
|
-
.map(result => chunks[result.index]);
|
|
218
|
-
}
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
// Use it
|
|
222
|
-
const results = await context.search({
|
|
223
|
-
query: "authentication",
|
|
224
|
-
method: "hybridSearch",
|
|
225
|
-
limit: 50
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
const reranked = await cohereReranker.run(
|
|
229
|
-
"authentication",
|
|
230
|
-
results.chunks
|
|
231
|
-
);
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
### With ExuluContext integration
|
|
235
|
-
|
|
236
|
-
```typescript
|
|
237
|
-
import { ExuluContext, ExuluReranker } from "@exulu/backend";
|
|
238
|
-
|
|
239
|
-
// Create reranker
|
|
240
|
-
const reranker = new ExuluReranker({
|
|
241
|
-
id: "my_reranker",
|
|
242
|
-
name: "My Reranker",
|
|
243
|
-
description: "Custom reranking logic",
|
|
244
|
-
execute: async ({ query, chunks }) => {
|
|
245
|
-
// Your reranking implementation
|
|
246
|
-
return reorderedChunks;
|
|
247
|
-
}
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
// Use with context
|
|
251
|
-
const context = new ExuluContext({
|
|
252
|
-
id: "docs",
|
|
253
|
-
name: "Documentation",
|
|
254
|
-
description: "Product documentation",
|
|
255
|
-
active: true,
|
|
256
|
-
fields: [
|
|
257
|
-
{ name: "title", type: "text", required: true },
|
|
258
|
-
{ name: "content", type: "longtext", required: true }
|
|
259
|
-
],
|
|
260
|
-
sources: [],
|
|
261
|
-
embedder: myEmbedder,
|
|
262
|
-
resultReranker: async (chunks) => {
|
|
263
|
-
// Extract query from first chunk's context
|
|
264
|
-
const query = chunks[0]?.context?.query || "";
|
|
265
|
-
|
|
266
|
-
// Run reranker
|
|
267
|
-
return reranker.run(query, chunks);
|
|
268
|
-
}
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
// Now all searches through this context will be reranked
|
|
272
|
-
const results = await context.search({
|
|
273
|
-
query: "How do I configure logging?",
|
|
274
|
-
method: "hybridSearch",
|
|
275
|
-
limit: 10
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
// results.chunks are already reranked
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
### Custom scoring reranker
|
|
282
|
-
|
|
283
|
-
```typescript
|
|
284
|
-
const customReranker = new ExuluReranker({
|
|
285
|
-
id: "custom_scorer",
|
|
286
|
-
name: "Custom Scorer",
|
|
287
|
-
description: "Reranks with custom business logic",
|
|
288
|
-
execute: async ({ query, chunks }) => {
|
|
289
|
-
// Compute custom score for each chunk
|
|
290
|
-
const scored = chunks.map(chunk => {
|
|
291
|
-
let score = chunk.chunk_hybrid_score || 0;
|
|
292
|
-
|
|
293
|
-
// Boost recent content
|
|
294
|
-
const daysSinceUpdate = (Date.now() - new Date(chunk.chunk_updated_at).getTime()) / (1000 * 60 * 60 * 24);
|
|
295
|
-
score += Math.max(0, 1 - daysSinceUpdate / 365);
|
|
296
|
-
|
|
297
|
-
// Boost certain categories
|
|
298
|
-
if (chunk.chunk_metadata.category === "tutorial") {
|
|
299
|
-
score *= 1.5;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// Boost exact keyword matches
|
|
303
|
-
const queryLower = query.toLowerCase();
|
|
304
|
-
const contentLower = chunk.chunk_content.toLowerCase();
|
|
305
|
-
if (contentLower.includes(queryLower)) {
|
|
306
|
-
score *= 1.2;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
return { chunk, score };
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
// Sort by score descending
|
|
313
|
-
scored.sort((a, b) => b.score - a.score);
|
|
314
|
-
|
|
315
|
-
return scored.map(s => s.chunk);
|
|
316
|
-
}
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
// Use it
|
|
320
|
-
const reranked = await customReranker.run(
|
|
321
|
-
"authentication setup",
|
|
322
|
-
searchResults.chunks
|
|
323
|
-
);
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
### Error-resilient reranker
|
|
327
|
-
|
|
328
|
-
```typescript
|
|
329
|
-
const resilientReranker = new ExuluReranker({
|
|
330
|
-
id: "resilient",
|
|
331
|
-
name: "Resilient Reranker",
|
|
332
|
-
description: "Falls back to original order on errors",
|
|
333
|
-
execute: async ({ query, chunks }) => {
|
|
334
|
-
try {
|
|
335
|
-
// Attempt reranking
|
|
336
|
-
const response = await fetch(RERANK_API_URL, {
|
|
337
|
-
method: "POST",
|
|
338
|
-
headers: { /* ... */ },
|
|
339
|
-
body: JSON.stringify({
|
|
340
|
-
query,
|
|
341
|
-
documents: chunks.map(c => c.chunk_content)
|
|
342
|
-
})
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
if (!response.ok) {
|
|
346
|
-
throw new Error(`API returned ${response.status}`);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
const data = await response.json();
|
|
350
|
-
return data.results.map(r => chunks[r.index]);
|
|
351
|
-
|
|
352
|
-
} catch (error) {
|
|
353
|
-
console.error("Reranking failed, using original order:", error);
|
|
354
|
-
|
|
355
|
-
// Return original order as fallback
|
|
356
|
-
return chunks;
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
});
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
### Caching reranker
|
|
363
|
-
|
|
364
|
-
```typescript
|
|
365
|
-
import crypto from "crypto";
|
|
366
|
-
|
|
367
|
-
const cache = new Map<string, VectorSearchChunkResult[]>();
|
|
368
|
-
|
|
369
|
-
const cachedReranker = new ExuluReranker({
|
|
370
|
-
id: "cached",
|
|
371
|
-
name: "Cached Reranker",
|
|
372
|
-
description: "Caches reranking results",
|
|
373
|
-
execute: async ({ query, chunks }) => {
|
|
374
|
-
// Create cache key
|
|
375
|
-
const chunkIds = chunks.map(c => c.chunk_id).sort().join(",");
|
|
376
|
-
const cacheKey = crypto
|
|
377
|
-
.createHash("md5")
|
|
378
|
-
.update(`${query}:${chunkIds}`)
|
|
379
|
-
.digest("hex");
|
|
380
|
-
|
|
381
|
-
// Check cache
|
|
382
|
-
if (cache.has(cacheKey)) {
|
|
383
|
-
console.log("Cache hit");
|
|
384
|
-
return cache.get(cacheKey)!;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
// Perform reranking
|
|
388
|
-
const reranked = await performReranking(query, chunks);
|
|
389
|
-
|
|
390
|
-
// Store in cache
|
|
391
|
-
cache.set(cacheKey, reranked);
|
|
392
|
-
|
|
393
|
-
return reranked;
|
|
394
|
-
}
|
|
395
|
-
});
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
### Hybrid reranker (API + custom)
|
|
399
|
-
|
|
400
|
-
```typescript
|
|
401
|
-
const hybridReranker = new ExuluReranker({
|
|
402
|
-
id: "hybrid",
|
|
403
|
-
name: "Hybrid Reranker",
|
|
404
|
-
description: "Combines API reranking with custom scoring",
|
|
405
|
-
execute: async ({ query, chunks }) => {
|
|
406
|
-
// Get API scores
|
|
407
|
-
const apiResponse = await fetch(RERANK_API_URL, {
|
|
408
|
-
method: "POST",
|
|
409
|
-
headers: { /* ... */ },
|
|
410
|
-
body: JSON.stringify({
|
|
411
|
-
query,
|
|
412
|
-
documents: chunks.map(c => c.chunk_content)
|
|
413
|
-
})
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
const apiData = await apiResponse.json();
|
|
417
|
-
|
|
418
|
-
// Combine with custom scoring
|
|
419
|
-
const scored = chunks.map((chunk, idx) => {
|
|
420
|
-
// API relevance score (0-1)
|
|
421
|
-
const apiScore = apiData.results.find(r => r.index === idx)?.relevance_score || 0;
|
|
422
|
-
|
|
423
|
-
// Custom score (0-1)
|
|
424
|
-
const recency = Math.max(0, 1 - (Date.now() - new Date(chunk.chunk_updated_at).getTime()) / (365 * 24 * 60 * 60 * 1000));
|
|
425
|
-
const categoryBoost = chunk.chunk_metadata.priority === "high" ? 0.2 : 0;
|
|
426
|
-
const customScore = Math.min(1, recency + categoryBoost);
|
|
427
|
-
|
|
428
|
-
// Weighted combination: 70% API, 30% custom
|
|
429
|
-
const finalScore = (apiScore * 0.7) + (customScore * 0.3);
|
|
430
|
-
|
|
431
|
-
return { chunk, score: finalScore };
|
|
432
|
-
});
|
|
433
|
-
|
|
434
|
-
scored.sort((a, b) => b.score - a.score);
|
|
435
|
-
return scored.map(s => s.chunk);
|
|
436
|
-
}
|
|
437
|
-
});
|
|
438
|
-
```
|
|
439
|
-
|
|
440
|
-
### LLM-based reranker
|
|
441
|
-
|
|
442
|
-
```typescript
|
|
443
|
-
import OpenAI from "openai";
|
|
444
|
-
|
|
445
|
-
const openai = new OpenAI();
|
|
446
|
-
|
|
447
|
-
const llmReranker = new ExuluReranker({
|
|
448
|
-
id: "llm_rerank",
|
|
449
|
-
name: "LLM Reranker",
|
|
450
|
-
description: "Uses GPT-4 to judge relevance",
|
|
451
|
-
execute: async ({ query, chunks }) => {
|
|
452
|
-
// Limit to top 10 for cost control
|
|
453
|
-
const topChunks = chunks.slice(0, 10);
|
|
454
|
-
|
|
455
|
-
// Score in parallel
|
|
456
|
-
const scored = await Promise.all(
|
|
457
|
-
topChunks.map(async (chunk) => {
|
|
458
|
-
const response = await openai.chat.completions.create({
|
|
459
|
-
model: "gpt-4o-mini",
|
|
460
|
-
messages: [{
|
|
461
|
-
role: "user",
|
|
462
|
-
content: `On a scale of 0-10, how relevant is this passage to the query?
|
|
463
|
-
|
|
464
|
-
Query: "${query}"
|
|
465
|
-
|
|
466
|
-
Passage: "${chunk.chunk_content}"
|
|
467
|
-
|
|
468
|
-
Respond with only a number.`
|
|
469
|
-
}],
|
|
470
|
-
temperature: 0,
|
|
471
|
-
max_tokens: 5
|
|
472
|
-
});
|
|
473
|
-
|
|
474
|
-
const score = parseFloat(response.choices[0].message.content || "0");
|
|
475
|
-
|
|
476
|
-
return { chunk, score };
|
|
477
|
-
})
|
|
478
|
-
);
|
|
479
|
-
|
|
480
|
-
scored.sort((a, b) => b.score - a.score);
|
|
481
|
-
|
|
482
|
-
return [
|
|
483
|
-
...scored.map(s => s.chunk),
|
|
484
|
-
...chunks.slice(10) // Append remaining chunks
|
|
485
|
-
];
|
|
486
|
-
}
|
|
487
|
-
});
|
|
488
|
-
```
|
|
489
|
-
|
|
490
|
-
### Accessing reranker properties
|
|
491
|
-
|
|
492
|
-
```typescript
|
|
493
|
-
const reranker = new ExuluReranker({
|
|
494
|
-
id: "example",
|
|
495
|
-
name: "Example Reranker",
|
|
496
|
-
description: "For demonstration",
|
|
497
|
-
execute: async ({ query, chunks }) => chunks
|
|
498
|
-
});
|
|
499
|
-
|
|
500
|
-
// Access properties
|
|
501
|
-
console.log(reranker.id); // "example"
|
|
502
|
-
console.log(reranker.name); // "Example Reranker"
|
|
503
|
-
console.log(reranker.description); // "For demonstration"
|
|
504
|
-
|
|
505
|
-
// Call execute directly
|
|
506
|
-
const result = await reranker.execute({
|
|
507
|
-
query: "test",
|
|
508
|
-
chunks: myChunks
|
|
509
|
-
});
|
|
510
|
-
|
|
511
|
-
// Or use run() for cleaner API
|
|
512
|
-
const result2 = await reranker.run("test", myChunks);
|
|
513
|
-
```
|
|
514
|
-
|
|
515
|
-
## Comparison: run() vs execute()
|
|
516
|
-
|
|
517
|
-
Both methods do the same thing, but `run()` provides a cleaner API:
|
|
518
|
-
|
|
519
|
-
```typescript
|
|
520
|
-
// Using execute() - verbose
|
|
521
|
-
const result = await reranker.execute({
|
|
522
|
-
query: "test query",
|
|
523
|
-
chunks: myChunks
|
|
524
|
-
});
|
|
525
|
-
|
|
526
|
-
// Using run() - cleaner
|
|
527
|
-
const result = await reranker.run("test query", myChunks);
|
|
528
|
-
```
|
|
529
|
-
|
|
530
|
-
<Tip>
|
|
531
|
-
Use `run()` for external calls and `execute()` when you need to pass the function as a callback.
|
|
532
|
-
</Tip>
|
|
533
|
-
|
|
534
|
-
## Integration patterns
|
|
535
|
-
|
|
536
|
-
### Direct usage
|
|
537
|
-
|
|
538
|
-
```typescript
|
|
539
|
-
// Get search results
|
|
540
|
-
const results = await context.search({
|
|
541
|
-
query: "authentication",
|
|
542
|
-
method: "hybridSearch",
|
|
543
|
-
limit: 50
|
|
544
|
-
});
|
|
545
|
-
|
|
546
|
-
// Apply reranking
|
|
547
|
-
const reranked = await reranker.run(
|
|
548
|
-
"authentication",
|
|
549
|
-
results.chunks
|
|
550
|
-
);
|
|
551
|
-
|
|
552
|
-
// Use top results
|
|
553
|
-
const topResults = reranked.slice(0, 10);
|
|
554
|
-
```
|
|
555
|
-
|
|
556
|
-
### As context configuration
|
|
557
|
-
|
|
558
|
-
```typescript
|
|
559
|
-
const context = new ExuluContext({
|
|
560
|
-
// ... other config
|
|
561
|
-
resultReranker: async (chunks) => {
|
|
562
|
-
const query = chunks[0]?.context?.query || "";
|
|
563
|
-
return reranker.run(query, chunks);
|
|
564
|
-
}
|
|
565
|
-
});
|
|
566
|
-
|
|
567
|
-
// Reranking happens automatically
|
|
568
|
-
const results = await context.search({
|
|
569
|
-
query: "authentication",
|
|
570
|
-
method: "hybridSearch"
|
|
571
|
-
});
|
|
572
|
-
// results.chunks are already reranked
|
|
573
|
-
```
|
|
574
|
-
|
|
575
|
-
### Conditional reranking
|
|
576
|
-
|
|
577
|
-
```typescript
|
|
578
|
-
const context = new ExuluContext({
|
|
579
|
-
// ... other config
|
|
580
|
-
resultReranker: async (chunks) => {
|
|
581
|
-
// Only rerank if we have enough results
|
|
582
|
-
if (chunks.length < 5) {
|
|
583
|
-
return chunks;
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
// Only rerank if scores are close (ambiguous ranking)
|
|
587
|
-
const scores = chunks.map(c => c.chunk_hybrid_score || 0);
|
|
588
|
-
const maxScore = Math.max(...scores);
|
|
589
|
-
const minScore = Math.min(...scores);
|
|
590
|
-
|
|
591
|
-
if (maxScore - minScore > 0.3) {
|
|
592
|
-
// Clear winner, skip reranking
|
|
593
|
-
return chunks;
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
// Ambiguous results, apply reranking
|
|
597
|
-
const query = chunks[0]?.context?.query || "";
|
|
598
|
-
return reranker.run(query, chunks);
|
|
599
|
-
}
|
|
600
|
-
});
|
|
601
|
-
```
|
|
602
|
-
|
|
603
|
-
## Best practices
|
|
604
|
-
|
|
605
|
-
<Tip>
|
|
606
|
-
**Always preserve chunk objects**: Return the exact same chunk objects in a new order. Don't create new objects or modify existing ones.
|
|
607
|
-
</Tip>
|
|
608
|
-
|
|
609
|
-
<Note>
|
|
610
|
-
**Handle errors gracefully**: Always return the original chunk order if reranking fails. Don't throw errors.
|
|
611
|
-
</Note>
|
|
612
|
-
|
|
613
|
-
<Warning>
|
|
614
|
-
**Watch latency**: Reranking adds latency. For high-traffic applications, consider caching or limiting the number of chunks to rerank.
|
|
615
|
-
</Warning>
|
|
616
|
-
|
|
617
|
-
<Info>
|
|
618
|
-
**Monitor costs**: API-based reranking has costs. Track usage and consider caching for repeated queries.
|
|
619
|
-
</Info>
|
|
620
|
-
|
|
621
|
-
## Next steps
|
|
622
|
-
|
|
623
|
-
<CardGroup cols={2}>
|
|
624
|
-
<Card title="Configuration guide" icon="gear" href="/core/exulu-reranker/configuration">
|
|
625
|
-
Learn about configuration options
|
|
626
|
-
</Card>
|
|
627
|
-
<Card title="ExuluContext" icon="database" href="/core/exulu-context/introduction">
|
|
628
|
-
Learn about search contexts
|
|
629
|
-
</Card>
|
|
630
|
-
</CardGroup>
|