@exulu/backend 1.67.0 → 1.69.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.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as _opentelemetry_sdk_node from '@opentelemetry/sdk-node';
2
2
  import * as knex from 'knex';
3
+ import { Knex } from 'knex';
3
4
  import { RedisClientType } from 'redis';
4
5
  import * as bullmq from 'bullmq';
5
6
  import { Queue } from 'bullmq';
@@ -10,6 +11,29 @@ import { z } from 'zod';
10
11
  import { Tiktoken } from 'tiktoken/lite';
11
12
  import models from 'tiktoken/model_to_encoding.json';
12
13
 
14
+ interface Project {
15
+ id: string;
16
+ name: string;
17
+ description: string;
18
+ custom_instructions: string;
19
+ rights_mode?: 'private' | 'users' | 'roles' | 'public';
20
+ created_by?: string;
21
+ project_items?: string[];
22
+ RBAC?: {
23
+ type?: string;
24
+ users?: Array<{
25
+ id: string;
26
+ rights: 'read' | 'write';
27
+ }>;
28
+ roles?: Array<{
29
+ id: string;
30
+ rights: 'read' | 'write';
31
+ }>;
32
+ };
33
+ createdAt?: string;
34
+ updatedAt?: string;
35
+ }
36
+
13
37
  type ApiKeyScopeMode = "admin" | "agents";
14
38
  type User = {
15
39
  id: number;
@@ -22,10 +46,20 @@ type User = {
22
46
  personal_system_prompt?: string;
23
47
  super_admin?: boolean;
24
48
  favourite_agents?: string[];
49
+ /** Per-user favourited data items — global ids ("<contextId>/<itemId>"). */
50
+ favourite_items?: string[];
51
+ /** Per-user recently viewed data items — global ids, most-recent first. */
52
+ recently_viewed_items?: string[];
25
53
  scope_mode?: ApiKeyScopeMode;
26
54
  agent_ids?: string[];
27
55
  role: UserRole;
28
56
  team?: ExuluTeam;
57
+ /**
58
+ * Optional attribution target (mainly for API keys, type "api"): hydrated
59
+ * from the `project` uuid column at auth time so buildTags can emit
60
+ * project_id_ for API-triggered requests.
61
+ */
62
+ project?: Project;
29
63
  /**
30
64
  * Live LiteLLM budget snapshot for the user, attached at context time when
31
65
  * the "show user budget in chat" setting is on. Not a Postgres column.
@@ -115,6 +149,7 @@ interface ExuluAgent {
115
149
  instructions?: string;
116
150
  feedback?: boolean;
117
151
  suggestions_enabled?: boolean;
152
+ sandbox_enabled?: boolean;
118
153
  slug?: string;
119
154
  tools?: {
120
155
  id: string;
@@ -350,6 +385,50 @@ type ExuluContextProcessor = {
350
385
  };
351
386
  };
352
387
 
388
+ /**
389
+ * Chunking is now an ExuluContext concern (it used to live on the removed
390
+ * ExuluEmbedder class). A context may supply its own `chunker` to control how
391
+ * an item is split into embeddable chunks; if it doesn't, `defaultChunker`
392
+ * runs. Embedding generation itself goes through LiteLLM via resolveEmbedder —
393
+ * the chunker only produces the text segments.
394
+ */
395
+ type ChunkerResponse = {
396
+ item: Item & {
397
+ id: string;
398
+ };
399
+ chunks: {
400
+ content: string;
401
+ index: number;
402
+ metadata?: Record<string, unknown>;
403
+ }[];
404
+ };
405
+ /**
406
+ * A chunker takes a (fully-hydrated) item and a target max chunk size and
407
+ * returns the ordered text chunks to embed. `utils.storage` is provided for
408
+ * chunkers that need to read file contents from object storage.
409
+ *
410
+ * Note: unlike the old ExuluEmbedder.chunker, there is no `settings` argument —
411
+ * the per-context `embedder_settings` config layer was removed. Chunkers that
412
+ * need configuration should close over it in code.
413
+ */
414
+ type ChunkerOperation = (item: Item & {
415
+ id: string;
416
+ }, maxChunkSize: number, utils: {
417
+ storage: ExuluStorage;
418
+ }) => Promise<ChunkerResponse>;
419
+ /**
420
+ * Built-in chunker used when a context configures an embedder model but does
421
+ * not provide its own `chunker`. It runs the standard SentenceChunker (also
422
+ * exposed as ExuluChunkers.sentence) over the item's primary text — preferring
423
+ * a `content` field, then `description`, combined with the `name` — so a
424
+ * context "just works" from a model name alone. `maxChunkSize` is used as the
425
+ * per-chunk token budget. Contexts with structured or file-backed content
426
+ * should supply a custom ChunkerOperation.
427
+ */
428
+ declare const defaultChunker: ChunkerOperation;
429
+
430
+ type ExuluRightsMode = "private" | "users" | "roles" | "teams" | "public";
431
+
353
432
  type STATISTICS_TYPE = "CONTEXT_RETRIEVE" | "SOURCE_UPDATE" | "EMBEDDER_UPSERT" | "EMBEDDER_GENERATE" | "EMBEDDER_DELETE" | "WORKFLOW_RUN" | "CONTEXT_UPSERT" | "TOOL_CALL" | "AGENT_RUN";
354
433
  declare const STATISTICS_TYPE_ENUM: {
355
434
  CONTEXT_RETRIEVE: string;
@@ -373,67 +452,6 @@ type ExuluStatistic = {
373
452
  };
374
453
  type STATISTICS_LABELS = "tool" | "agent" | "flow" | "api" | "claude-code" | "user" | "processor";
375
454
 
376
- type ExuluEmbedderConfig = {
377
- name: string;
378
- description: string;
379
- default?: string;
380
- };
381
- type VectorGenerationResponse = Promise<{
382
- id: string;
383
- chunks: {
384
- content: string;
385
- index: number;
386
- metadata: Record<string, string>;
387
- vector: number[];
388
- }[];
389
- }>;
390
- type VectorGenerateOperation = (inputs: ChunkerResponse, settings: Record<string, string>) => VectorGenerationResponse;
391
- type ChunkerOperation = (item: Item & {
392
- id: string;
393
- }, maxChunkSize: number, utils: {
394
- storage: ExuluStorage;
395
- }, config: Record<string, string>) => Promise<ChunkerResponse>;
396
- type ChunkerResponse = {
397
- item: Item & {
398
- id: string;
399
- };
400
- chunks: {
401
- content: string;
402
- index: number;
403
- }[];
404
- };
405
- declare class ExuluEmbedder {
406
- id: string;
407
- name: string;
408
- slug: string;
409
- queue?: Promise<ExuluQueueConfig>;
410
- private generateEmbeddings;
411
- description: string;
412
- vectorDimensions: number;
413
- config?: ExuluEmbedderConfig[];
414
- maxChunkSize: number;
415
- _chunker: ChunkerOperation;
416
- constructor({ id, name, description, generateEmbeddings, queue, vectorDimensions, maxChunkSize, chunker, config, }: {
417
- id: string;
418
- name: string;
419
- description: string;
420
- config?: ExuluEmbedderConfig[];
421
- generateEmbeddings: VectorGenerateOperation;
422
- chunker: ChunkerOperation;
423
- queue?: Promise<ExuluQueueConfig>;
424
- vectorDimensions: number;
425
- maxChunkSize: number;
426
- });
427
- chunker: (context: string, item: Item & {
428
- id: string;
429
- }, maxChunkSize: number, config: ExuluConfig) => Promise<ChunkerResponse>;
430
- private hydrateEmbedderConfig;
431
- generateFromQuery(context: string, query: string, statistics?: ExuluStatisticParams, user?: number, role?: string): VectorGenerationResponse;
432
- generateFromDocument(context: string, input: Item, config: ExuluConfig, statistics?: ExuluStatisticParams, user?: number, role?: string): VectorGenerationResponse;
433
- }
434
-
435
- type ExuluRightsMode = "private" | "users" | "roles" | "public";
436
-
437
455
  /**
438
456
  * Base operator type with comparison operations
439
457
  */
@@ -536,8 +554,6 @@ type ExuluEntitiesConfig = {
536
554
  types?: EntityTypeDefinition[];
537
555
  /** models.id used for extraction. Resolved via resolveModel(). Falls back to a platform default. */
538
556
  model?: string;
539
- /** Where to extract from. "chunks" (default) locates each mention to a chunk. */
540
- extractFrom?: "chunks" | "document";
541
557
  /** Weight of the shared-entity boost term in retrieval ranking. Default 0.3. */
542
558
  boostWeight?: number;
543
559
  /** Drop mentions below this extractor confidence (0..1). Default 0.5. */
@@ -609,6 +625,18 @@ type VectorSearchChunkResult = {
609
625
  };
610
626
  };
611
627
 
628
+ /**
629
+ * A context's embedder is now just a reference to a LiteLLM embedding model
630
+ * (plus an optional queue), not an ExuluEmbedder instance. Embedding generation
631
+ * goes through resolveEmbedder; chunking is configured separately via the
632
+ * context's `chunker` (or the built-in default chunker).
633
+ */
634
+ type ExuluContextEmbedder = {
635
+ /** LiteLLM model_name of the embedding model (declared in config.litellm.yaml). */
636
+ model: string;
637
+ /** When set, embedding generation runs as a background job on this queue. */
638
+ queue?: Promise<ExuluQueueConfig>;
639
+ };
612
640
  type ExuluContextFieldDefinition = {
613
641
  name: string;
614
642
  type: ExuluFieldTypes;
@@ -651,14 +679,20 @@ declare class ExuluContext {
651
679
  fields: ExuluContextFieldDefinition[];
652
680
  processor?: ExuluContextProcessor;
653
681
  description: string;
654
- embedder?: ExuluEmbedder;
682
+ embedder?: ExuluContextEmbedder;
683
+ /**
684
+ * Splits an item into embeddable chunks. Moved here from the removed
685
+ * ExuluEmbedder. When omitted, the built-in `defaultChunker` (SentenceChunker)
686
+ * is used so a context works from just an embedder model name.
687
+ */
688
+ chunker?: ChunkerOperation;
655
689
  queryRewriter?: (query: string) => Promise<string>;
656
690
  resultReranker?: (results: {
657
691
  chunk_content: string;
658
692
  chunk_index: number;
659
693
  chunk_id: string;
660
694
  chunk_source: string;
661
- chunk_metadata: Record<string, string>;
695
+ chunk_metadata: Record<string, unknown>;
662
696
  chunk_created_at: string;
663
697
  chunk_updated_at: string;
664
698
  item_id: string;
@@ -669,7 +703,7 @@ declare class ExuluContext {
669
703
  chunk_index: number;
670
704
  chunk_id: string;
671
705
  chunk_source: string;
672
- chunk_metadata: Record<string, string>;
706
+ chunk_metadata: Record<string, unknown>;
673
707
  chunk_created_at: string;
674
708
  chunk_updated_at: string;
675
709
  item_id: string;
@@ -698,12 +732,13 @@ declare class ExuluContext {
698
732
  */
699
733
  entities?: ExuluEntitiesConfig;
700
734
  sources: ExuluContextSource[];
701
- constructor({ id, name, description, embedder, processor, active, fields, queryRewriter, resultReranker, configuration, entities, sources, }: {
735
+ constructor({ id, name, description, embedder, chunker, processor, active, fields, queryRewriter, resultReranker, configuration, entities, sources, }: {
702
736
  id: string;
703
737
  name: string;
704
738
  fields: ExuluContextFieldDefinition[];
705
739
  description: string;
706
- embedder?: ExuluEmbedder;
740
+ embedder?: ExuluContextEmbedder;
741
+ chunker?: ChunkerOperation;
707
742
  sources: ExuluContextSource[];
708
743
  category?: string;
709
744
  active: boolean;
@@ -753,6 +788,9 @@ declare class ExuluContext {
753
788
  after?: number;
754
789
  };
755
790
  entityFilter?: EntityFilter;
791
+ /** Precomputed query embedding; forwarded to vectorSearch to skip re-embedding (caller must use
792
+ * this context's embedding model). Spread into vectorSearch via `...options` below. */
793
+ queryEmbedding?: number[];
756
794
  }) => Promise<{
757
795
  itemFilters: SearchFilters;
758
796
  chunkFilters: SearchFilters;
@@ -795,9 +833,11 @@ declare class ExuluContext {
795
833
  getItem: ({ item }: {
796
834
  item: Item;
797
835
  }) => Promise<Item>;
798
- getItems: ({ filters, fields, }: {
836
+ getItems: ({ filters, fields, user, role, }: {
799
837
  filters?: any[];
800
838
  fields?: string[];
839
+ user?: User;
840
+ role?: string;
801
841
  }) => Promise<Item[]>;
802
842
  embeddings: {
803
843
  generate: {
@@ -837,6 +877,18 @@ declare class ExuluContext {
837
877
  processed: number;
838
878
  skipped: number;
839
879
  }>;
880
+ /**
881
+ * Extract + ingest entities for a SINGLE item — powers the item detail
882
+ * page's "Extract entities" test action. Returns the number of mentions
883
+ * found so the UI can report the result.
884
+ */
885
+ extractItem: (itemId: string) => Promise<{
886
+ extracted: number;
887
+ }>;
888
+ /** Detach all entities from a single item (drops links, prunes orphans). */
889
+ detachItem: (itemId: string) => Promise<{
890
+ detached: number;
891
+ }>;
840
892
  /** Remove all entities (and their mentions via cascade) of a given type. */
841
893
  purgeType: (typeName: string) => Promise<{
842
894
  removed: number;
@@ -846,26 +898,6 @@ declare class ExuluContext {
846
898
  createChunksTable: () => Promise<void>;
847
899
  }
848
900
 
849
- declare class ExuluReranker {
850
- id: string;
851
- name: string;
852
- description: string;
853
- execute: (params: {
854
- query: string;
855
- chunks: VectorSearchChunkResult[];
856
- }) => Promise<VectorSearchChunkResult[]>;
857
- constructor({ id, name, description, execute, }: {
858
- id: string;
859
- name: string;
860
- description: string;
861
- execute: (params: {
862
- query: string;
863
- chunks: VectorSearchChunkResult[];
864
- }) => Promise<VectorSearchChunkResult[]>;
865
- });
866
- run(query: string, chunks: VectorSearchChunkResult[]): Promise<VectorSearchChunkResult[]>;
867
- }
868
-
869
901
  type ExuluAgentToolConfig = {
870
902
  id: string;
871
903
  type: string;
@@ -944,8 +976,8 @@ declare class ExuluProvider {
944
976
  constructor({ id, name, description, config, capabilities, type, maxContextLength, provider, queue, authenticationInformation, workflows, }: ExuluProviderParams);
945
977
  get providerName(): string;
946
978
  get modelName(): string;
947
- tool: (instance: string, providers: ExuluProvider[], contexts: ExuluContext[], rerankers: ExuluReranker[]) => Promise<ExuluTool | null>;
948
- generateSync: ({ prompt, req, user, session, inputMessages, approvedTools, currentTools, currentSkills, allExuluTools, statistics, toolConfigs, providerapikey, languageModel, contexts, rerankers, exuluConfig, agent, instructions, maxStepCount, onTokenUsage }: {
979
+ tool: (instance: string, providers: ExuluProvider[], contexts: ExuluContext[]) => Promise<ExuluTool | null>;
980
+ generateSync: ({ prompt, req, user, session, inputMessages, approvedTools, currentTools, currentSkills, allExuluTools, statistics, toolConfigs, providerapikey, languageModel, contexts, exuluConfig, agent, instructions, maxStepCount, onTokenUsage }: {
949
981
  prompt?: string;
950
982
  user?: User;
951
983
  maxStepCount?: number;
@@ -962,7 +994,6 @@ declare class ExuluProvider {
962
994
  providerapikey?: string | undefined;
963
995
  languageModel: LanguageModel;
964
996
  contexts?: ExuluContext[] | undefined;
965
- rerankers?: ExuluReranker[] | undefined;
966
997
  exuluConfig?: ExuluConfig;
967
998
  instructions?: string;
968
999
  onTokenUsage?: (usage: {
@@ -978,7 +1009,7 @@ declare class ExuluProvider {
978
1009
  * - Image files -> image parts (which ARE supported by Responses API)
979
1010
  */
980
1011
  private processFilePartsInMessages;
981
- generateStream: ({ user, session, agent, message, previousMessages, currentTools, currentSkills, approvedTools, allExuluTools, toolConfigs, providerapikey, languageModel, contexts, rerankers, exuluConfig, instructions, req, maxStepCount }: {
1012
+ generateStream: ({ user, session, agent, message, previousMessages, currentTools, currentSkills, approvedTools, allExuluTools, toolConfigs, providerapikey, languageModel, contexts, exuluConfig, instructions, req, maxStepCount }: {
982
1013
  user?: User;
983
1014
  session?: string;
984
1015
  agent?: ExuluAgent;
@@ -993,7 +1024,6 @@ declare class ExuluProvider {
993
1024
  providerapikey?: string | undefined;
994
1025
  languageModel: LanguageModel;
995
1026
  contexts?: ExuluContext[] | undefined;
996
- rerankers?: ExuluReranker[] | undefined;
997
1027
  exuluConfig?: ExuluConfig;
998
1028
  instructions?: string;
999
1029
  req?: Request;
@@ -1099,17 +1129,15 @@ declare class ExuluApp {
1099
1129
  private _config?;
1100
1130
  private _evals;
1101
1131
  private _queues;
1102
- private _rerankers;
1103
1132
  private _contexts?;
1104
1133
  private _tools;
1105
1134
  private _expressApp;
1106
1135
  constructor();
1107
- create: ({ contexts, providers, config, agents, tools, evals, rerankers, }: {
1136
+ create: ({ contexts, providers, config, agents, tools, evals, }: {
1108
1137
  contexts?: Record<string, ExuluContext>;
1109
1138
  config: ExuluConfig;
1110
1139
  agents?: ExuluAgent[];
1111
1140
  providers?: ExuluProvider[];
1112
- rerankers?: ExuluReranker[];
1113
1141
  evals?: ExuluEval[];
1114
1142
  tools?: ExuluTool[];
1115
1143
  }) => Promise<ExuluApp>;
@@ -1783,6 +1811,50 @@ declare class RecursiveChunker extends BaseChunker {
1783
1811
  toString(): string;
1784
1812
  }
1785
1813
 
1814
+ interface AuthorizedReadOpts {
1815
+ itemIds?: string[];
1816
+ externalIds?: string[];
1817
+ chunkIndexRange?: {
1818
+ from?: number;
1819
+ to?: number;
1820
+ };
1821
+ }
1822
+ /**
1823
+ * Supported, RBAC-safe read API for retrieval clients (e.g. the agentic harness).
1824
+ * Relevance + visibility still go through ExuluContext.search(); this namespace
1825
+ * adds the read shapes search() cannot express, always over authorized rows.
1826
+ */
1827
+ declare const ExuluReadApi: {
1828
+ getTableName: (id: string) => string;
1829
+ getChunksTableName: (id: string) => string;
1830
+ getEntitiesTableName: (id: string) => string;
1831
+ getChunkEntitiesTableName: (id: string) => string;
1832
+ entitiesAvailable: (context: {
1833
+ id: string;
1834
+ entities?: unknown;
1835
+ }) => Promise<boolean>;
1836
+ authorizedRead: (context: {
1837
+ id: string;
1838
+ fields?: unknown[];
1839
+ entities?: unknown;
1840
+ }, user: User, role: string, opts?: AuthorizedReadOpts) => Promise<VectorSearchChunkResult[]>;
1841
+ embedQuery: (context: {
1842
+ id: string;
1843
+ name?: string;
1844
+ embedder: {
1845
+ model: string;
1846
+ };
1847
+ }, text: string, opts?: {
1848
+ user?: User;
1849
+ role?: string;
1850
+ inputType?: "document" | "query";
1851
+ }) => Promise<number[]>;
1852
+ };
1853
+
1854
+ declare function postgresClient(): Promise<{
1855
+ db: Knex;
1856
+ }>;
1857
+
1786
1858
  /**
1787
1859
  * Represents the essential data for a sentence within a text.
1788
1860
  *
@@ -2208,14 +2280,79 @@ declare function validatePythonEnvironment(packageRoot?: string, checkPackages?:
2208
2280
  message: string;
2209
2281
  }>;
2210
2282
 
2283
+ /**
2284
+ * resolveOcr — the OCR-side counterpart of resolveEmbedder.
2285
+ *
2286
+ * Like resolveEmbedder, this is LiteLLM-ONLY: OCR always goes through the
2287
+ * spawned LiteLLM proxy's Mistral-compatible `/v1/ocr` endpoint. There is no
2288
+ * in-code provider/SDK fallback — a caller just names a LiteLLM `model` (e.g.
2289
+ * "mistral-ocr", "vertex-ocr") and it works, with cost attribution via tags
2290
+ * (user/role/project/agent/routine/context, when provided — see buildTags()).
2291
+ *
2292
+ * Routing OCR through the proxy means we can cost-control it through the same
2293
+ * tag-based budgets as chat and embeddings, and switch the underlying provider
2294
+ * (mistral / azure_ai / vertex_ai) by editing config.litellm.yaml without
2295
+ * touching this code.
2296
+ *
2297
+ * LiteLLM follows the Mistral OCR request/response shape:
2298
+ * https://docs.mistral.ai/capabilities/vision/#optical-character-recognition-ocr
2299
+ */
2300
+ type ResolveOcrInput = {
2301
+ /** LiteLLM model_name of the OCR model (e.g. "mistral-ocr"). */
2302
+ model: string;
2303
+ /** Context this OCR belongs to — emitted as context_id_/context_name_ tags. */
2304
+ contextId?: string;
2305
+ contextName?: string;
2306
+ user?: User;
2307
+ /** When only a numeric user id is available (background ingestion jobs). */
2308
+ userId?: number;
2309
+ roleId?: string;
2310
+ project?: Project;
2311
+ agent?: ExuluAgent;
2312
+ routine?: {
2313
+ id: string;
2314
+ name: string;
2315
+ };
2316
+ };
2317
+
2211
2318
  type DocumentProcessorConfig = {
2212
2319
  vlm?: {
2213
- model: LanguageModel;
2320
+ /**
2321
+ * LiteLLM model_name for the VLM page-validation pass (declared in
2322
+ * config.litellm.yaml, e.g. "vertex-gemini-2.5-flash"). Resolved via
2323
+ * resolveModel() so the VLM pass shares the same tag-based cost controls
2324
+ * and provider-switching as chat / embeddings / OCR, and the underlying
2325
+ * provider can be swapped without code changes.
2326
+ */
2327
+ model: string;
2214
2328
  concurrency: number;
2215
2329
  };
2216
2330
  processor: {
2217
2331
  name: "docling" | "liteparse" | "mistral" | "officeparser";
2332
+ /**
2333
+ * LiteLLM model_name for the "mistral" OCR processor (declared in
2334
+ * config.litellm.yaml). Defaults to "mistral-ocr". OCR is routed through
2335
+ * the LiteLLM proxy so it shares the same tag-based cost controls as chat
2336
+ * and embeddings, and the underlying provider (mistral / azure_ai /
2337
+ * vertex_ai) can be switched without code changes.
2338
+ */
2339
+ model?: string;
2340
+ /**
2341
+ * Maximum pages per OCR request for the "mistral" processor.
2342
+ * Vertex AI OCR rejects documents over 30 pages; the PDF is split into
2343
+ * chunks of this size and each chunk is OCR'd independently.
2344
+ * Defaults to 25 (safely under the Vertex AI 30-page limit).
2345
+ */
2346
+ maxPagesPerChunk?: number;
2218
2347
  };
2348
+ /**
2349
+ * Optional cost-attribution context, forwarded to LiteLLM as spend tags
2350
+ * (user / role / project / context) for both the OCR pass (resolveOcr) and
2351
+ * the VLM page-validation pass (resolveModel). Not yet populated by callers;
2352
+ * the wiring is in place so per-user/per-context budgets work the moment
2353
+ * attribution is threaded through.
2354
+ */
2355
+ attribution?: Omit<ResolveOcrInput, "model">;
2219
2356
  debugging?: {
2220
2357
  deleteTempFiles?: boolean;
2221
2358
  };
@@ -2235,6 +2372,81 @@ declare function documentProcessor({ file, name, config }: {
2235
2372
  config?: DocumentProcessorConfig;
2236
2373
  }): Promise<ProcessedDocument | undefined>;
2237
2374
 
2375
+ /**
2376
+ * resolveReranker — the rerank-side counterpart of resolveEmbedder / resolveOcr.
2377
+ *
2378
+ * Like those, this is LiteLLM-ONLY: reranking always goes through the spawned
2379
+ * LiteLLM proxy's cohere-compatible `/v1/rerank` endpoint. There is no in-code
2380
+ * provider/SDK fallback — a caller just names a LiteLLM `model` (a model_name
2381
+ * declared in config.litellm.yaml with `model_info.type: reranker`) and it
2382
+ * works, with cost attribution via tags (user/role/project/agent/routine/
2383
+ * context, when provided — see buildTags()).
2384
+ *
2385
+ * Routing rerank through the proxy means we cost-control it through the same
2386
+ * tag-based budgets as chat / embeddings / OCR, and switch the underlying
2387
+ * provider (cohere / vertex_ai / together_ai / ...) by editing
2388
+ * config.litellm.yaml without touching this code.
2389
+ *
2390
+ * `rerank` takes the chunks directly, builds each document as
2391
+ * `item_name + ": " + chunk_content` (the standard retrieval convention), calls
2392
+ * the proxy, and maps the relevance scores back onto the chunks (reordered,
2393
+ * `rerank_score` attached). The item type is constrained structurally
2394
+ * (item_name / chunk_content) so both ChunkResult and VectorSearchChunkResult
2395
+ * work without importing either — no src/exulu → retrieval/GraphQL dependency.
2396
+ *
2397
+ * LiteLLM follows the Cohere rerank request/response shape:
2398
+ * https://docs.cohere.com/reference/rerank
2399
+ */
2400
+ type ResolveRerankerInput = {
2401
+ /** LiteLLM model_name of the reranker (e.g. "rerank-v4.0-pro"). */
2402
+ model: string;
2403
+ /** Context this rerank belongs to — emitted as context_id_/context_name_ tags. */
2404
+ contextId?: string;
2405
+ contextName?: string;
2406
+ user?: User;
2407
+ /** When only a numeric user id is available (background ingestion jobs). */
2408
+ userId?: number;
2409
+ roleId?: string;
2410
+ project?: Project;
2411
+ agent?: ExuluAgent;
2412
+ routine?: {
2413
+ id: string;
2414
+ name: string;
2415
+ };
2416
+ };
2417
+ /** Minimal chunk shape rerank() needs to build a document. */
2418
+ type RerankableChunk = {
2419
+ item_name?: string;
2420
+ chunk_content?: string;
2421
+ };
2422
+
2423
+ /**
2424
+ * Public, package-facing reranker — the counterpart of
2425
+ * `ExuluDocumentProcessor.process`. A drop-in replacement for a hand-rolled
2426
+ * Cohere / Google reranker: pass `{ query, items, model }` and get the items
2427
+ * back reordered desc by relevance with a `rerank_score` attached.
2428
+ *
2429
+ * `model` is a LiteLLM model_name declared in config.litellm.yaml with
2430
+ * `model_info.type: reranker`, so the SAME call works against any supported
2431
+ * provider (cohere / vertex_ai / together_ai / ...) — switch providers in
2432
+ * config, not in code — and reranking is cost-attributed via the optional
2433
+ * identity/context fields (user / role / project / agent / routine / context).
2434
+ *
2435
+ * Each document is built as `item_name + ": " + chunk_content` (the standard
2436
+ * retrieval convention). Items are constrained structurally, so any chunk shape
2437
+ * carrying `item_name` / `chunk_content` works and the extra fields are
2438
+ * preserved on the returned objects.
2439
+ */
2440
+ type ExuluRerankInput<T extends RerankableChunk> = {
2441
+ query: string;
2442
+ items: T[];
2443
+ /** Only score/return the top N items (optional optimization hint). */
2444
+ topN?: number;
2445
+ } & ResolveRerankerInput;
2446
+ declare function rerank<T extends RerankableChunk>(input: ExuluRerankInput<T>): Promise<(T & {
2447
+ rerank_score: number;
2448
+ })[]>;
2449
+
2238
2450
  /**
2239
2451
  * Creates the v3 ExuluTool for agentic context retrieval.
2240
2452
  *
@@ -2244,9 +2456,8 @@ declare function documentProcessor({ file, name, config }: {
2244
2456
  * - Context example records sampled at init and cached
2245
2457
  * - Strategy-specific instructions and tool sets
2246
2458
  */
2247
- declare function createAgenticRetrievalToolV3({ contexts, instructions: adminInstructions, rerankers, user, role, model, preselected, memoryItems }: {
2459
+ declare function createAgenticRetrievalToolV3({ contexts, instructions: adminInstructions, user, role, model, preselected, memoryItems }: {
2248
2460
  contexts: ExuluContext[];
2249
- rerankers: ExuluReranker[];
2250
2461
  user?: User;
2251
2462
  role?: string;
2252
2463
  model?: LanguageModel;
@@ -2326,6 +2537,9 @@ declare const ExuluAuthentication: {
2326
2537
  declare const ExuluDocumentProcessor: {
2327
2538
  process: typeof documentProcessor;
2328
2539
  };
2540
+ declare const ExuluReranker: {
2541
+ rerank: typeof rerank;
2542
+ };
2329
2543
  declare const ExuluOtel: {
2330
2544
  create: ({ SIGNOZ_ACCESS_TOKEN, SIGNOZ_TRACES_URL, SIGNOZ_LOGS_URL, }: {
2331
2545
  SIGNOZ_ACCESS_TOKEN: string;
@@ -2366,4 +2580,4 @@ declare const ExuluPython: {
2366
2580
  instructions: typeof getPythonSetupInstructions;
2367
2581
  };
2368
2582
 
2369
- export { type JOB_STATUS as EXULU_JOB_STATUS, JOB_STATUS_ENUM as EXULU_JOB_STATUS_ENUM, type STATISTICS_TYPE as EXULU_STATISTICS_TYPE, STATISTICS_TYPE_ENUM as EXULU_STATISTICS_TYPE_ENUM, type ExuluAgent, ExuluApp, ExuluAuthentication, ExuluChunkers, ExuluContext, ExuluDatabase, ExuluDefaultProviders, ExuluDefaultTools, ExuluDocumentProcessor, ExuluEmbedder, ExuluEval, type Item as ExuluItem, ExuluJobs, type ExuluOauthConfig, type ExuluOauthToolContext, ExuluOtel, ExuluProvider, ExuluPython, queues as ExuluQueues, ExuluReranker, ExuluTool, trajectoryRegistry as ExuluTrajectoryRegistry, ExuluVariables };
2583
+ export { type ChunkerOperation, type ChunkerResponse, type JOB_STATUS as EXULU_JOB_STATUS, JOB_STATUS_ENUM as EXULU_JOB_STATUS_ENUM, type STATISTICS_TYPE as EXULU_STATISTICS_TYPE, STATISTICS_TYPE_ENUM as EXULU_STATISTICS_TYPE_ENUM, type ExuluAgent, ExuluApp, ExuluAuthentication, ExuluChunkers, ExuluContext, type ExuluContextEmbedder, ExuluDatabase, ExuluDefaultProviders, ExuluDefaultTools, ExuluDocumentProcessor, ExuluEval, type Item as ExuluItem, ExuluJobs, type ExuluOauthConfig, type ExuluOauthToolContext, ExuluOtel, ExuluProvider, ExuluPython, queues as ExuluQueues, ExuluReadApi, ExuluReranker, ExuluTool, trajectoryRegistry as ExuluTrajectoryRegistry, ExuluVariables, type VectorSearchChunkResult, defaultChunker, postgresClient };