@tanstack/ai-cohere 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +55 -0
- package/dist/esm/adapters/rerank.d.ts +48 -0
- package/dist/esm/adapters/rerank.js +126 -0
- package/dist/esm/adapters/rerank.js.map +1 -0
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/model-meta.d.ts +38 -0
- package/dist/esm/model-meta.js +20 -0
- package/dist/esm/model-meta.js.map +1 -0
- package/dist/esm/utils/client.d.ts +21 -0
- package/dist/esm/utils/client.js +21 -0
- package/dist/esm/utils/client.js.map +1 -0
- package/package.json +66 -0
- package/src/adapters/rerank.ts +181 -0
- package/src/index.ts +24 -0
- package/src/model-meta.ts +50 -0
- package/src/utils/client.ts +45 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Tanner Linsley
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/TanStack/ai/main/media/header_ai.png" alt="TanStack AI" />
|
|
3
|
+
</div>
|
|
4
|
+
|
|
5
|
+
<br />
|
|
6
|
+
|
|
7
|
+
<div align="center">
|
|
8
|
+
<a href="https://npmjs.com/package/@tanstack/ai-cohere" target="_parent">
|
|
9
|
+
<img alt="NPM downloads" src="https://img.shields.io/npm/dm/@tanstack/ai-cohere.svg" />
|
|
10
|
+
</a>
|
|
11
|
+
<a href="https://github.com/TanStack/ai" target="_parent">
|
|
12
|
+
<img alt="GitHub stars" src="https://img.shields.io/github/stars/TanStack/ai.svg?style=social&label=Star" />
|
|
13
|
+
</a>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
# @tanstack/ai-cohere
|
|
17
|
+
|
|
18
|
+
Cohere adapter for [TanStack AI](https://tanstack.com/ai). Reorder candidate
|
|
19
|
+
documents by relevance to a query with Cohere's rerank models — the precision
|
|
20
|
+
step for RAG and search pipelines.
|
|
21
|
+
|
|
22
|
+
This adapter is **rerank-only**. For chat, summarization, embeddings, or media,
|
|
23
|
+
use OpenAI, Anthropic, or Gemini.
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pnpm add @tanstack/ai @tanstack/ai-cohere
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { rerank } from '@tanstack/ai'
|
|
35
|
+
import { cohereRerank } from '@tanstack/ai-cohere'
|
|
36
|
+
|
|
37
|
+
const { ranking, rerankedDocuments } = await rerank({
|
|
38
|
+
adapter: cohereRerank('rerank-v3.5'),
|
|
39
|
+
query: 'talk about rain',
|
|
40
|
+
documents: ['sunny day at the beach', 'rainy afternoon in the city'],
|
|
41
|
+
topN: 2,
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
console.log(rerankedDocuments[0]) // 'rainy afternoon in the city'
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The adapter reads `COHERE_API_KEY` from the environment. To pass a key
|
|
48
|
+
explicitly, use `createCohereRerank('rerank-v3.5', 'co-...')`.
|
|
49
|
+
|
|
50
|
+
## <a href="https://tanstack.com/ai/latest/docs/rerank/rerank">Read the docs -></a>
|
|
51
|
+
|
|
52
|
+
- [Reranking Guide](https://tanstack.com/ai/latest/docs/rerank/rerank) — object
|
|
53
|
+
documents, RAG pipelines, options, and the result shape.
|
|
54
|
+
- [Cohere Adapter](https://tanstack.com/ai/latest/docs/adapters/cohere) —
|
|
55
|
+
models, configuration, and explicit API keys.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { BaseRerankAdapter } from '@tanstack/ai/adapters';
|
|
2
|
+
import { CohereClientConfig } from '../utils/client.js';
|
|
3
|
+
import { CohereRerankModel, InferCohereRerankProviderOptions } from '../model-meta.js';
|
|
4
|
+
import { RerankAdapterResult, RerankOptions } from '@tanstack/ai';
|
|
5
|
+
/**
|
|
6
|
+
* Cohere rerank adapter.
|
|
7
|
+
*
|
|
8
|
+
* Talks to Cohere's `/v2/rerank` endpoint over raw `fetch` — no SDK. Returns
|
|
9
|
+
* scored indices into the submitted documents; the `rerank()` activity maps
|
|
10
|
+
* those back to the caller's original documents.
|
|
11
|
+
*/
|
|
12
|
+
export declare class CohereRerankAdapter<TModel extends CohereRerankModel> extends BaseRerankAdapter<TModel, InferCohereRerankProviderOptions<TModel>> {
|
|
13
|
+
readonly name: "cohere";
|
|
14
|
+
private readonly apiKey;
|
|
15
|
+
private readonly baseUrl;
|
|
16
|
+
private readonly headers;
|
|
17
|
+
constructor(config: CohereClientConfig, model: TModel);
|
|
18
|
+
rerank(options: RerankOptions<InferCohereRerankProviderOptions<TModel>>): Promise<RerankAdapterResult>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Creates a Cohere rerank adapter with an explicit API key. Type resolution
|
|
22
|
+
* (per-model provider options) happens here at the call site.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* const adapter = createCohereRerank('rerank-v3.5', 'co-...')
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function createCohereRerank<TModel extends CohereRerankModel>(model: TModel, apiKey: string, config?: Omit<CohereClientConfig, 'apiKey'>): CohereRerankAdapter<TModel>;
|
|
30
|
+
/**
|
|
31
|
+
* Creates a Cohere rerank adapter, reading `COHERE_API_KEY` from the
|
|
32
|
+
* environment.
|
|
33
|
+
*
|
|
34
|
+
* @throws Error if `COHERE_API_KEY` is not found.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* import { rerank } from '@tanstack/ai'
|
|
39
|
+
* import { cohereRerank } from '@tanstack/ai-cohere'
|
|
40
|
+
*
|
|
41
|
+
* const { rerankedDocuments } = await rerank({
|
|
42
|
+
* adapter: cohereRerank('rerank-v3.5'),
|
|
43
|
+
* query: 'talk about rain',
|
|
44
|
+
* documents: ['sunny day', 'rainy afternoon'],
|
|
45
|
+
* })
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare function cohereRerank<TModel extends CohereRerankModel>(model: TModel, config?: Omit<CohereClientConfig, 'apiKey'>): CohereRerankAdapter<TModel>;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { getCohereApiKeyFromEnv } from "../utils/client.js";
|
|
2
|
+
import { BaseRerankAdapter } from "@tanstack/ai/adapters";
|
|
3
|
+
//#region src/adapters/rerank.ts
|
|
4
|
+
function isCohereRerankResponse(value) {
|
|
5
|
+
if (typeof value !== "object" || value === null) return false;
|
|
6
|
+
const results = value.results;
|
|
7
|
+
return Array.isArray(results) && results.every((r) => typeof r === "object" && r !== null && typeof r.index === "number" && typeof r.relevance_score === "number");
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Cohere rerank adapter.
|
|
11
|
+
*
|
|
12
|
+
* Talks to Cohere's `/v2/rerank` endpoint over raw `fetch` — no SDK. Returns
|
|
13
|
+
* scored indices into the submitted documents; the `rerank()` activity maps
|
|
14
|
+
* those back to the caller's original documents.
|
|
15
|
+
*/
|
|
16
|
+
var CohereRerankAdapter = class extends BaseRerankAdapter {
|
|
17
|
+
name = "cohere";
|
|
18
|
+
apiKey;
|
|
19
|
+
baseUrl;
|
|
20
|
+
headers;
|
|
21
|
+
constructor(config, model) {
|
|
22
|
+
super({}, model);
|
|
23
|
+
this.apiKey = config.apiKey;
|
|
24
|
+
this.baseUrl = (config.baseUrl ?? "https://api.cohere.com").replace(/\/+$/, "");
|
|
25
|
+
this.headers = config.headers ?? {};
|
|
26
|
+
}
|
|
27
|
+
async rerank(options) {
|
|
28
|
+
const { model, query, documents, topN, modelOptions, abortSignal, logger } = options;
|
|
29
|
+
const body = {
|
|
30
|
+
model,
|
|
31
|
+
query,
|
|
32
|
+
documents
|
|
33
|
+
};
|
|
34
|
+
if (topN !== void 0) body["top_n"] = topN;
|
|
35
|
+
if (modelOptions?.maxTokensPerDoc !== void 0) body["max_tokens_per_doc"] = modelOptions.maxTokensPerDoc;
|
|
36
|
+
logger.request(`activity=rerank provider=${this.name} model=${model} documents=${documents.length}`, {
|
|
37
|
+
provider: this.name,
|
|
38
|
+
model
|
|
39
|
+
});
|
|
40
|
+
let response;
|
|
41
|
+
try {
|
|
42
|
+
response = await fetch(`${this.baseUrl}/v2/rerank`, {
|
|
43
|
+
method: "POST",
|
|
44
|
+
headers: {
|
|
45
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
46
|
+
"Content-Type": "application/json",
|
|
47
|
+
...this.headers
|
|
48
|
+
},
|
|
49
|
+
body: JSON.stringify(body),
|
|
50
|
+
...abortSignal ? { signal: abortSignal } : {}
|
|
51
|
+
});
|
|
52
|
+
} catch (error) {
|
|
53
|
+
logger.errors(`${this.name}.rerank fatal`, {
|
|
54
|
+
error,
|
|
55
|
+
source: `${this.name}.rerank`
|
|
56
|
+
});
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
if (!response.ok) {
|
|
60
|
+
const detail = await response.text().catch(() => "");
|
|
61
|
+
const error = /* @__PURE__ */ new Error(`Cohere rerank request failed: ${response.status} ${response.statusText}${detail ? ` — ${detail}` : ""}`);
|
|
62
|
+
logger.errors(`${this.name}.rerank fatal`, {
|
|
63
|
+
error,
|
|
64
|
+
source: `${this.name}.rerank`
|
|
65
|
+
});
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
const json = await response.json();
|
|
69
|
+
if (!isCohereRerankResponse(json)) throw new Error("Cohere rerank response had an unexpected shape");
|
|
70
|
+
const searchUnits = json.meta?.billed_units?.search_units;
|
|
71
|
+
const usage = {
|
|
72
|
+
promptTokens: 0,
|
|
73
|
+
completionTokens: 0,
|
|
74
|
+
totalTokens: 0,
|
|
75
|
+
...searchUnits !== void 0 ? { unitsBilled: searchUnits } : {}
|
|
76
|
+
};
|
|
77
|
+
return {
|
|
78
|
+
id: json.id ?? this.generateId(),
|
|
79
|
+
ranking: json.results.map((r) => ({
|
|
80
|
+
index: r.index,
|
|
81
|
+
score: r.relevance_score
|
|
82
|
+
})),
|
|
83
|
+
usage
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Creates a Cohere rerank adapter with an explicit API key. Type resolution
|
|
89
|
+
* (per-model provider options) happens here at the call site.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* const adapter = createCohereRerank('rerank-v3.5', 'co-...')
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
function createCohereRerank(model, apiKey, config) {
|
|
97
|
+
return new CohereRerankAdapter({
|
|
98
|
+
apiKey,
|
|
99
|
+
...config
|
|
100
|
+
}, model);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Creates a Cohere rerank adapter, reading `COHERE_API_KEY` from the
|
|
104
|
+
* environment.
|
|
105
|
+
*
|
|
106
|
+
* @throws Error if `COHERE_API_KEY` is not found.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```typescript
|
|
110
|
+
* import { rerank } from '@tanstack/ai'
|
|
111
|
+
* import { cohereRerank } from '@tanstack/ai-cohere'
|
|
112
|
+
*
|
|
113
|
+
* const { rerankedDocuments } = await rerank({
|
|
114
|
+
* adapter: cohereRerank('rerank-v3.5'),
|
|
115
|
+
* query: 'talk about rain',
|
|
116
|
+
* documents: ['sunny day', 'rainy afternoon'],
|
|
117
|
+
* })
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
function cohereRerank(model, config) {
|
|
121
|
+
return createCohereRerank(model, getCohereApiKeyFromEnv(), config);
|
|
122
|
+
}
|
|
123
|
+
//#endregion
|
|
124
|
+
export { CohereRerankAdapter, cohereRerank, createCohereRerank };
|
|
125
|
+
|
|
126
|
+
//# sourceMappingURL=rerank.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rerank.js","names":[],"sources":["../../../src/adapters/rerank.ts"],"sourcesContent":["import { BaseRerankAdapter } from '@tanstack/ai/adapters'\nimport {\n COHERE_DEFAULT_BASE_URL,\n getCohereApiKeyFromEnv,\n} from '../utils/client'\nimport type { CohereClientConfig } from '../utils/client'\nimport type {\n CohereRerankModel,\n InferCohereRerankProviderOptions,\n} from '../model-meta'\nimport type {\n RerankAdapterResult,\n RerankOptions,\n TokenUsage,\n} from '@tanstack/ai'\n\n/** Shape of the Cohere `/v2/rerank` response we depend on. */\ninterface CohereRerankResponse {\n id?: string\n results: Array<{ index: number; relevance_score: number }>\n meta?: { billed_units?: { search_units?: number } }\n}\n\nfunction isCohereRerankResponse(value: unknown): value is CohereRerankResponse {\n if (typeof value !== 'object' || value === null) return false\n const results = (value as { results?: unknown }).results\n return (\n Array.isArray(results) &&\n results.every(\n (r) =>\n typeof r === 'object' &&\n r !== null &&\n typeof (r as { index?: unknown }).index === 'number' &&\n typeof (r as { relevance_score?: unknown }).relevance_score ===\n 'number',\n )\n )\n}\n\n/**\n * Cohere rerank adapter.\n *\n * Talks to Cohere's `/v2/rerank` endpoint over raw `fetch` — no SDK. Returns\n * scored indices into the submitted documents; the `rerank()` activity maps\n * those back to the caller's original documents.\n */\nexport class CohereRerankAdapter<\n TModel extends CohereRerankModel,\n> extends BaseRerankAdapter<TModel, InferCohereRerankProviderOptions<TModel>> {\n readonly name = 'cohere' as const\n\n private readonly apiKey: string\n private readonly baseUrl: string\n private readonly headers: Record<string, string>\n\n constructor(config: CohereClientConfig, model: TModel) {\n super({}, model)\n this.apiKey = config.apiKey\n this.baseUrl = (config.baseUrl ?? COHERE_DEFAULT_BASE_URL).replace(\n /\\/+$/,\n '',\n )\n this.headers = config.headers ?? {}\n }\n\n async rerank(\n options: RerankOptions<InferCohereRerankProviderOptions<TModel>>,\n ): Promise<RerankAdapterResult> {\n const { model, query, documents, topN, modelOptions, abortSignal, logger } =\n options\n\n const body: Record<string, unknown> = { model, query, documents }\n if (topN !== undefined) body['top_n'] = topN\n if (modelOptions?.maxTokensPerDoc !== undefined) {\n body['max_tokens_per_doc'] = modelOptions.maxTokensPerDoc\n }\n\n logger.request(\n `activity=rerank provider=${this.name} model=${model} documents=${documents.length}`,\n { provider: this.name, model },\n )\n\n let response: Response\n try {\n response = await fetch(`${this.baseUrl}/v2/rerank`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n ...this.headers,\n },\n body: JSON.stringify(body),\n ...(abortSignal ? { signal: abortSignal } : {}),\n })\n } catch (error) {\n logger.errors(`${this.name}.rerank fatal`, {\n error,\n source: `${this.name}.rerank`,\n })\n throw error\n }\n\n if (!response.ok) {\n const detail = await response.text().catch(() => '')\n const error = new Error(\n `Cohere rerank request failed: ${response.status} ${response.statusText}${\n detail ? ` — ${detail}` : ''\n }`,\n )\n logger.errors(`${this.name}.rerank fatal`, {\n error,\n source: `${this.name}.rerank`,\n })\n throw error\n }\n\n const json: unknown = await response.json()\n if (!isCohereRerankResponse(json)) {\n throw new Error('Cohere rerank response had an unexpected shape')\n }\n\n const searchUnits = json.meta?.billed_units?.search_units\n const usage: TokenUsage = {\n promptTokens: 0,\n completionTokens: 0,\n totalTokens: 0,\n ...(searchUnits !== undefined ? { unitsBilled: searchUnits } : {}),\n }\n\n return {\n id: json.id ?? this.generateId(),\n ranking: json.results.map((r) => ({\n index: r.index,\n score: r.relevance_score,\n })),\n usage,\n }\n }\n}\n\n/**\n * Creates a Cohere rerank adapter with an explicit API key. Type resolution\n * (per-model provider options) happens here at the call site.\n *\n * @example\n * ```typescript\n * const adapter = createCohereRerank('rerank-v3.5', 'co-...')\n * ```\n */\nexport function createCohereRerank<TModel extends CohereRerankModel>(\n model: TModel,\n apiKey: string,\n config?: Omit<CohereClientConfig, 'apiKey'>,\n): CohereRerankAdapter<TModel> {\n return new CohereRerankAdapter({ apiKey, ...config }, model)\n}\n\n/**\n * Creates a Cohere rerank adapter, reading `COHERE_API_KEY` from the\n * environment.\n *\n * @throws Error if `COHERE_API_KEY` is not found.\n *\n * @example\n * ```typescript\n * import { rerank } from '@tanstack/ai'\n * import { cohereRerank } from '@tanstack/ai-cohere'\n *\n * const { rerankedDocuments } = await rerank({\n * adapter: cohereRerank('rerank-v3.5'),\n * query: 'talk about rain',\n * documents: ['sunny day', 'rainy afternoon'],\n * })\n * ```\n */\nexport function cohereRerank<TModel extends CohereRerankModel>(\n model: TModel,\n config?: Omit<CohereClientConfig, 'apiKey'>,\n): CohereRerankAdapter<TModel> {\n return createCohereRerank(model, getCohereApiKeyFromEnv(), config)\n}\n"],"mappings":";;;AAuBA,SAAS,uBAAuB,OAA+C;CAC7E,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CACxD,MAAM,UAAW,MAAgC;CACjD,OACE,MAAM,QAAQ,OAAO,KACrB,QAAQ,OACL,MACC,OAAO,MAAM,YACb,MAAM,QACN,OAAQ,EAA0B,UAAU,YAC5C,OAAQ,EAAoC,oBAC1C,QACN;AAEJ;;;;;;;;AASA,IAAa,sBAAb,cAEU,kBAAoE;CAC5E,OAAgB;CAEhB;CACA;CACA;CAEA,YAAY,QAA4B,OAAe;EACrD,MAAM,CAAC,GAAG,KAAK;EACf,KAAK,SAAS,OAAO;EACrB,KAAK,WAAW,OAAO,WAAA,yBAAA,CAAoC,QACzD,QACA,EACF;EACA,KAAK,UAAU,OAAO,WAAW,CAAC;CACpC;CAEA,MAAM,OACJ,SAC8B;EAC9B,MAAM,EAAE,OAAO,OAAO,WAAW,MAAM,cAAc,aAAa,WAChE;EAEF,MAAM,OAAgC;GAAE;GAAO;GAAO;EAAU;EAChE,IAAI,SAAS,KAAA,GAAW,KAAK,WAAW;EACxC,IAAI,cAAc,oBAAoB,KAAA,GACpC,KAAK,wBAAwB,aAAa;EAG5C,OAAO,QACL,4BAA4B,KAAK,KAAK,SAAS,MAAM,aAAa,UAAU,UAC5E;GAAE,UAAU,KAAK;GAAM;EAAM,CAC/B;EAEA,IAAI;EACJ,IAAI;GACF,WAAW,MAAM,MAAM,GAAG,KAAK,QAAQ,aAAa;IAClD,QAAQ;IACR,SAAS;KACP,eAAe,UAAU,KAAK;KAC9B,gBAAgB;KAChB,GAAG,KAAK;IACV;IACA,MAAM,KAAK,UAAU,IAAI;IACzB,GAAI,cAAc,EAAE,QAAQ,YAAY,IAAI,CAAC;GAC/C,CAAC;EACH,SAAS,OAAO;GACd,OAAO,OAAO,GAAG,KAAK,KAAK,gBAAgB;IACzC;IACA,QAAQ,GAAG,KAAK,KAAK;GACvB,CAAC;GACD,MAAM;EACR;EAEA,IAAI,CAAC,SAAS,IAAI;GAChB,MAAM,SAAS,MAAM,SAAS,KAAK,CAAC,CAAC,YAAY,EAAE;GACnD,MAAM,wBAAQ,IAAI,MAChB,iCAAiC,SAAS,OAAO,GAAG,SAAS,aAC3D,SAAS,MAAM,WAAW,IAE9B;GACA,OAAO,OAAO,GAAG,KAAK,KAAK,gBAAgB;IACzC;IACA,QAAQ,GAAG,KAAK,KAAK;GACvB,CAAC;GACD,MAAM;EACR;EAEA,MAAM,OAAgB,MAAM,SAAS,KAAK;EAC1C,IAAI,CAAC,uBAAuB,IAAI,GAC9B,MAAM,IAAI,MAAM,gDAAgD;EAGlE,MAAM,cAAc,KAAK,MAAM,cAAc;EAC7C,MAAM,QAAoB;GACxB,cAAc;GACd,kBAAkB;GAClB,aAAa;GACb,GAAI,gBAAgB,KAAA,IAAY,EAAE,aAAa,YAAY,IAAI,CAAC;EAClE;EAEA,OAAO;GACL,IAAI,KAAK,MAAM,KAAK,WAAW;GAC/B,SAAS,KAAK,QAAQ,KAAK,OAAO;IAChC,OAAO,EAAE;IACT,OAAO,EAAE;GACX,EAAE;GACF;EACF;CACF;AACF;;;;;;;;;;AAWA,SAAgB,mBACd,OACA,QACA,QAC6B;CAC7B,OAAO,IAAI,oBAAoB;EAAE;EAAQ,GAAG;CAAO,GAAG,KAAK;AAC7D;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,aACd,OACA,QAC6B;CAC7B,OAAO,mBAAmB,OAAO,uBAAuB,GAAG,MAAM;AACnE"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { CohereRerankAdapter, createCohereRerank, cohereRerank, } from './adapters/rerank.js';
|
|
2
|
+
export { COHERE_RERANK_MODELS, type CohereRerankModel, type CohereRerankProviderOptions, type CohereRerankModelProviderOptionsByName, type InferCohereRerankProviderOptions, } from './model-meta.js';
|
|
3
|
+
export type { CohereClientConfig } from './utils/client.js';
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cohere rerank model metadata.
|
|
3
|
+
*
|
|
4
|
+
* Provider options are resolved per model at the `cohereRerank('model')` call
|
|
5
|
+
* site via {@link CohereRerankModelProviderOptionsByName}. Cohere's rerank
|
|
6
|
+
* models currently share the same options, but the per-model map keeps the
|
|
7
|
+
* surface symmetric with the other adapters and lets divergent options be
|
|
8
|
+
* expressed later without changing the adapter contract.
|
|
9
|
+
*/
|
|
10
|
+
/** Available Cohere rerank models. */
|
|
11
|
+
export declare const COHERE_RERANK_MODELS: readonly ["rerank-v3.5", "rerank-english-v3.0", "rerank-multilingual-v3.0"];
|
|
12
|
+
/** Union of supported Cohere rerank model names. */
|
|
13
|
+
export type CohereRerankModel = (typeof COHERE_RERANK_MODELS)[number];
|
|
14
|
+
/**
|
|
15
|
+
* Provider-specific options for a Cohere rerank request. Forwarded on the
|
|
16
|
+
* `modelOptions` field of `rerank()`.
|
|
17
|
+
*/
|
|
18
|
+
export interface CohereRerankProviderOptions {
|
|
19
|
+
/**
|
|
20
|
+
* Long documents are chunked to fit the model's context. This caps the
|
|
21
|
+
* number of tokens kept per document. Cohere defaults to 4096.
|
|
22
|
+
*/
|
|
23
|
+
maxTokensPerDoc?: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Per-model provider-options map. Each model resolves to its own options type
|
|
27
|
+
* at the factory call site (see {@link InferCohereRerankProviderOptions}).
|
|
28
|
+
*/
|
|
29
|
+
export interface CohereRerankModelProviderOptionsByName {
|
|
30
|
+
'rerank-v3.5': CohereRerankProviderOptions;
|
|
31
|
+
'rerank-english-v3.0': CohereRerankProviderOptions;
|
|
32
|
+
'rerank-multilingual-v3.0': CohereRerankProviderOptions;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Resolve the provider options for a given rerank model. Falls back to the
|
|
36
|
+
* base options for any model not in the map.
|
|
37
|
+
*/
|
|
38
|
+
export type InferCohereRerankProviderOptions<TModel extends string> = TModel extends keyof CohereRerankModelProviderOptionsByName ? CohereRerankModelProviderOptionsByName[TModel] : CohereRerankProviderOptions;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/model-meta.ts
|
|
2
|
+
/**
|
|
3
|
+
* Cohere rerank model metadata.
|
|
4
|
+
*
|
|
5
|
+
* Provider options are resolved per model at the `cohereRerank('model')` call
|
|
6
|
+
* site via {@link CohereRerankModelProviderOptionsByName}. Cohere's rerank
|
|
7
|
+
* models currently share the same options, but the per-model map keeps the
|
|
8
|
+
* surface symmetric with the other adapters and lets divergent options be
|
|
9
|
+
* expressed later without changing the adapter contract.
|
|
10
|
+
*/
|
|
11
|
+
/** Available Cohere rerank models. */
|
|
12
|
+
var COHERE_RERANK_MODELS = [
|
|
13
|
+
"rerank-v3.5",
|
|
14
|
+
"rerank-english-v3.0",
|
|
15
|
+
"rerank-multilingual-v3.0"
|
|
16
|
+
];
|
|
17
|
+
//#endregion
|
|
18
|
+
export { COHERE_RERANK_MODELS };
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=model-meta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-meta.js","names":[],"sources":["../../src/model-meta.ts"],"sourcesContent":["/**\n * Cohere rerank model metadata.\n *\n * Provider options are resolved per model at the `cohereRerank('model')` call\n * site via {@link CohereRerankModelProviderOptionsByName}. Cohere's rerank\n * models currently share the same options, but the per-model map keeps the\n * surface symmetric with the other adapters and lets divergent options be\n * expressed later without changing the adapter contract.\n */\n\n/** Available Cohere rerank models. */\nexport const COHERE_RERANK_MODELS = [\n 'rerank-v3.5',\n 'rerank-english-v3.0',\n 'rerank-multilingual-v3.0',\n] as const\n\n/** Union of supported Cohere rerank model names. */\nexport type CohereRerankModel = (typeof COHERE_RERANK_MODELS)[number]\n\n/**\n * Provider-specific options for a Cohere rerank request. Forwarded on the\n * `modelOptions` field of `rerank()`.\n */\nexport interface CohereRerankProviderOptions {\n /**\n * Long documents are chunked to fit the model's context. This caps the\n * number of tokens kept per document. Cohere defaults to 4096.\n */\n maxTokensPerDoc?: number\n}\n\n/**\n * Per-model provider-options map. Each model resolves to its own options type\n * at the factory call site (see {@link InferCohereRerankProviderOptions}).\n */\nexport interface CohereRerankModelProviderOptionsByName {\n 'rerank-v3.5': CohereRerankProviderOptions\n 'rerank-english-v3.0': CohereRerankProviderOptions\n 'rerank-multilingual-v3.0': CohereRerankProviderOptions\n}\n\n/**\n * Resolve the provider options for a given rerank model. Falls back to the\n * base options for any model not in the map.\n */\nexport type InferCohereRerankProviderOptions<TModel extends string> =\n TModel extends keyof CohereRerankModelProviderOptionsByName\n ? CohereRerankModelProviderOptionsByName[TModel]\n : CohereRerankProviderOptions\n"],"mappings":";;;;;;;;;;;AAWA,IAAa,uBAAuB;CAClC;CACA;CACA;AACF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cohere client configuration shared by the rerank adapter.
|
|
3
|
+
*/
|
|
4
|
+
export interface CohereClientConfig {
|
|
5
|
+
/** Cohere API key. Required by the adapter factories. */
|
|
6
|
+
apiKey: string;
|
|
7
|
+
/** Override the API base URL. Defaults to `https://api.cohere.com`. */
|
|
8
|
+
baseUrl?: string;
|
|
9
|
+
/** Extra headers merged into every request. */
|
|
10
|
+
headers?: Record<string, string>;
|
|
11
|
+
}
|
|
12
|
+
export declare const COHERE_DEFAULT_BASE_URL = "https://api.cohere.com";
|
|
13
|
+
/**
|
|
14
|
+
* Reads the Cohere API key from the environment.
|
|
15
|
+
*
|
|
16
|
+
* Looks for `COHERE_API_KEY` in `process.env` (Node) or `window.env`
|
|
17
|
+
* (browser with injected env).
|
|
18
|
+
*
|
|
19
|
+
* @throws Error if `COHERE_API_KEY` is not found.
|
|
20
|
+
*/
|
|
21
|
+
export declare function getCohereApiKeyFromEnv(): string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/utils/client.ts
|
|
2
|
+
var COHERE_DEFAULT_BASE_URL = "https://api.cohere.com";
|
|
3
|
+
/**
|
|
4
|
+
* Reads the Cohere API key from the environment.
|
|
5
|
+
*
|
|
6
|
+
* Looks for `COHERE_API_KEY` in `process.env` (Node) or `window.env`
|
|
7
|
+
* (browser with injected env).
|
|
8
|
+
*
|
|
9
|
+
* @throws Error if `COHERE_API_KEY` is not found.
|
|
10
|
+
*/
|
|
11
|
+
function getCohereApiKeyFromEnv() {
|
|
12
|
+
const windowEnv = typeof globalThis !== "undefined" && globalThis.window ? globalThis.window.env : void 0;
|
|
13
|
+
const processEnv = typeof process !== "undefined" ? process.env : void 0;
|
|
14
|
+
const key = windowEnv?.["COHERE_API_KEY"] ?? processEnv?.["COHERE_API_KEY"];
|
|
15
|
+
if (!key) throw new Error("COHERE_API_KEY not found in environment. Pass an API key explicitly via createCohereRerank(model, apiKey).");
|
|
16
|
+
return key;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { COHERE_DEFAULT_BASE_URL, getCohereApiKeyFromEnv };
|
|
20
|
+
|
|
21
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","names":[],"sources":["../../../src/utils/client.ts"],"sourcesContent":["/**\n * Cohere client configuration shared by the rerank adapter.\n */\nexport interface CohereClientConfig {\n /** Cohere API key. Required by the adapter factories. */\n apiKey: string\n /** Override the API base URL. Defaults to `https://api.cohere.com`. */\n baseUrl?: string\n /** Extra headers merged into every request. */\n headers?: Record<string, string>\n}\n\nexport const COHERE_DEFAULT_BASE_URL = 'https://api.cohere.com'\n\n/**\n * Reads the Cohere API key from the environment.\n *\n * Looks for `COHERE_API_KEY` in `process.env` (Node) or `window.env`\n * (browser with injected env).\n *\n * @throws Error if `COHERE_API_KEY` is not found.\n */\nexport function getCohereApiKeyFromEnv(): string {\n const windowEnv =\n typeof globalThis !== 'undefined' &&\n (globalThis as Record<string, unknown>).window\n ? ((\n (globalThis as Record<string, unknown>).window as Record<\n string,\n unknown\n >\n ).env as Record<string, string> | undefined)\n : undefined\n const processEnv = typeof process !== 'undefined' ? process.env : undefined\n // Prefer an injected `window.env` (browser builds) but fall back to\n // `process.env` — bundlers and Electron can populate it even when `window`\n // exists.\n const key = windowEnv?.['COHERE_API_KEY'] ?? processEnv?.['COHERE_API_KEY']\n if (!key) {\n throw new Error(\n 'COHERE_API_KEY not found in environment. Pass an API key explicitly via createCohereRerank(model, apiKey).',\n )\n }\n return key\n}\n"],"mappings":";AAYA,IAAa,0BAA0B;;;;;;;;;AAUvC,SAAgB,yBAAiC;CAC/C,MAAM,YACJ,OAAO,eAAe,eACrB,WAAuC,SAEjC,WAAuC,OAIxC,MACF,KAAA;CACN,MAAM,aAAa,OAAO,YAAY,cAAc,QAAQ,MAAM,KAAA;CAIlE,MAAM,MAAM,YAAY,qBAAqB,aAAa;CAC1D,IAAI,CAAC,KACH,MAAM,IAAI,MACR,4GACF;CAEF,OAAO;AACT"}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tanstack/ai-cohere",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
7
|
+
"description": "Cohere adapter for TanStack AI — document reranking.",
|
|
8
|
+
"author": "Tanner Linsley",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"homepage": "https://tanstack.com/ai",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/TanStack/ai.git",
|
|
14
|
+
"directory": "packages/ai-cohere"
|
|
15
|
+
},
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/TanStack/ai/issues"
|
|
18
|
+
},
|
|
19
|
+
"funding": {
|
|
20
|
+
"type": "github",
|
|
21
|
+
"url": "https://github.com/sponsors/tannerlinsley"
|
|
22
|
+
},
|
|
23
|
+
"type": "module",
|
|
24
|
+
"module": "./dist/esm/index.js",
|
|
25
|
+
"types": "./dist/esm/index.d.ts",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./dist/esm/index.d.ts",
|
|
29
|
+
"import": "./dist/esm/index.js"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist",
|
|
34
|
+
"src"
|
|
35
|
+
],
|
|
36
|
+
"keywords": [
|
|
37
|
+
"ai",
|
|
38
|
+
"ai-sdk",
|
|
39
|
+
"typescript",
|
|
40
|
+
"tanstack",
|
|
41
|
+
"cohere",
|
|
42
|
+
"rerank",
|
|
43
|
+
"reranking",
|
|
44
|
+
"search",
|
|
45
|
+
"retrieval",
|
|
46
|
+
"adapter"
|
|
47
|
+
],
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"@tanstack/ai": "^0.43.1"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@vitest/coverage-v8": "4.0.14",
|
|
53
|
+
"vite": "^8.1.4",
|
|
54
|
+
"@tanstack/ai": "0.43.1"
|
|
55
|
+
},
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "vite build",
|
|
58
|
+
"clean": "premove ./build ./dist",
|
|
59
|
+
"lint:fix": "oxlint src --type-aware --fix",
|
|
60
|
+
"test:build": "publint --strict",
|
|
61
|
+
"test:oxlint": "oxlint src --type-aware",
|
|
62
|
+
"test:lib": "vitest run",
|
|
63
|
+
"test:lib:dev": "pnpm test:lib --watch",
|
|
64
|
+
"test:types": "tsc"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { BaseRerankAdapter } from '@tanstack/ai/adapters'
|
|
2
|
+
import {
|
|
3
|
+
COHERE_DEFAULT_BASE_URL,
|
|
4
|
+
getCohereApiKeyFromEnv,
|
|
5
|
+
} from '../utils/client'
|
|
6
|
+
import type { CohereClientConfig } from '../utils/client'
|
|
7
|
+
import type {
|
|
8
|
+
CohereRerankModel,
|
|
9
|
+
InferCohereRerankProviderOptions,
|
|
10
|
+
} from '../model-meta'
|
|
11
|
+
import type {
|
|
12
|
+
RerankAdapterResult,
|
|
13
|
+
RerankOptions,
|
|
14
|
+
TokenUsage,
|
|
15
|
+
} from '@tanstack/ai'
|
|
16
|
+
|
|
17
|
+
/** Shape of the Cohere `/v2/rerank` response we depend on. */
|
|
18
|
+
interface CohereRerankResponse {
|
|
19
|
+
id?: string
|
|
20
|
+
results: Array<{ index: number; relevance_score: number }>
|
|
21
|
+
meta?: { billed_units?: { search_units?: number } }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function isCohereRerankResponse(value: unknown): value is CohereRerankResponse {
|
|
25
|
+
if (typeof value !== 'object' || value === null) return false
|
|
26
|
+
const results = (value as { results?: unknown }).results
|
|
27
|
+
return (
|
|
28
|
+
Array.isArray(results) &&
|
|
29
|
+
results.every(
|
|
30
|
+
(r) =>
|
|
31
|
+
typeof r === 'object' &&
|
|
32
|
+
r !== null &&
|
|
33
|
+
typeof (r as { index?: unknown }).index === 'number' &&
|
|
34
|
+
typeof (r as { relevance_score?: unknown }).relevance_score ===
|
|
35
|
+
'number',
|
|
36
|
+
)
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Cohere rerank adapter.
|
|
42
|
+
*
|
|
43
|
+
* Talks to Cohere's `/v2/rerank` endpoint over raw `fetch` — no SDK. Returns
|
|
44
|
+
* scored indices into the submitted documents; the `rerank()` activity maps
|
|
45
|
+
* those back to the caller's original documents.
|
|
46
|
+
*/
|
|
47
|
+
export class CohereRerankAdapter<
|
|
48
|
+
TModel extends CohereRerankModel,
|
|
49
|
+
> extends BaseRerankAdapter<TModel, InferCohereRerankProviderOptions<TModel>> {
|
|
50
|
+
readonly name = 'cohere' as const
|
|
51
|
+
|
|
52
|
+
private readonly apiKey: string
|
|
53
|
+
private readonly baseUrl: string
|
|
54
|
+
private readonly headers: Record<string, string>
|
|
55
|
+
|
|
56
|
+
constructor(config: CohereClientConfig, model: TModel) {
|
|
57
|
+
super({}, model)
|
|
58
|
+
this.apiKey = config.apiKey
|
|
59
|
+
this.baseUrl = (config.baseUrl ?? COHERE_DEFAULT_BASE_URL).replace(
|
|
60
|
+
/\/+$/,
|
|
61
|
+
'',
|
|
62
|
+
)
|
|
63
|
+
this.headers = config.headers ?? {}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async rerank(
|
|
67
|
+
options: RerankOptions<InferCohereRerankProviderOptions<TModel>>,
|
|
68
|
+
): Promise<RerankAdapterResult> {
|
|
69
|
+
const { model, query, documents, topN, modelOptions, abortSignal, logger } =
|
|
70
|
+
options
|
|
71
|
+
|
|
72
|
+
const body: Record<string, unknown> = { model, query, documents }
|
|
73
|
+
if (topN !== undefined) body['top_n'] = topN
|
|
74
|
+
if (modelOptions?.maxTokensPerDoc !== undefined) {
|
|
75
|
+
body['max_tokens_per_doc'] = modelOptions.maxTokensPerDoc
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
logger.request(
|
|
79
|
+
`activity=rerank provider=${this.name} model=${model} documents=${documents.length}`,
|
|
80
|
+
{ provider: this.name, model },
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
let response: Response
|
|
84
|
+
try {
|
|
85
|
+
response = await fetch(`${this.baseUrl}/v2/rerank`, {
|
|
86
|
+
method: 'POST',
|
|
87
|
+
headers: {
|
|
88
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
89
|
+
'Content-Type': 'application/json',
|
|
90
|
+
...this.headers,
|
|
91
|
+
},
|
|
92
|
+
body: JSON.stringify(body),
|
|
93
|
+
...(abortSignal ? { signal: abortSignal } : {}),
|
|
94
|
+
})
|
|
95
|
+
} catch (error) {
|
|
96
|
+
logger.errors(`${this.name}.rerank fatal`, {
|
|
97
|
+
error,
|
|
98
|
+
source: `${this.name}.rerank`,
|
|
99
|
+
})
|
|
100
|
+
throw error
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (!response.ok) {
|
|
104
|
+
const detail = await response.text().catch(() => '')
|
|
105
|
+
const error = new Error(
|
|
106
|
+
`Cohere rerank request failed: ${response.status} ${response.statusText}${
|
|
107
|
+
detail ? ` — ${detail}` : ''
|
|
108
|
+
}`,
|
|
109
|
+
)
|
|
110
|
+
logger.errors(`${this.name}.rerank fatal`, {
|
|
111
|
+
error,
|
|
112
|
+
source: `${this.name}.rerank`,
|
|
113
|
+
})
|
|
114
|
+
throw error
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const json: unknown = await response.json()
|
|
118
|
+
if (!isCohereRerankResponse(json)) {
|
|
119
|
+
throw new Error('Cohere rerank response had an unexpected shape')
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const searchUnits = json.meta?.billed_units?.search_units
|
|
123
|
+
const usage: TokenUsage = {
|
|
124
|
+
promptTokens: 0,
|
|
125
|
+
completionTokens: 0,
|
|
126
|
+
totalTokens: 0,
|
|
127
|
+
...(searchUnits !== undefined ? { unitsBilled: searchUnits } : {}),
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
id: json.id ?? this.generateId(),
|
|
132
|
+
ranking: json.results.map((r) => ({
|
|
133
|
+
index: r.index,
|
|
134
|
+
score: r.relevance_score,
|
|
135
|
+
})),
|
|
136
|
+
usage,
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Creates a Cohere rerank adapter with an explicit API key. Type resolution
|
|
143
|
+
* (per-model provider options) happens here at the call site.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```typescript
|
|
147
|
+
* const adapter = createCohereRerank('rerank-v3.5', 'co-...')
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
export function createCohereRerank<TModel extends CohereRerankModel>(
|
|
151
|
+
model: TModel,
|
|
152
|
+
apiKey: string,
|
|
153
|
+
config?: Omit<CohereClientConfig, 'apiKey'>,
|
|
154
|
+
): CohereRerankAdapter<TModel> {
|
|
155
|
+
return new CohereRerankAdapter({ apiKey, ...config }, model)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Creates a Cohere rerank adapter, reading `COHERE_API_KEY` from the
|
|
160
|
+
* environment.
|
|
161
|
+
*
|
|
162
|
+
* @throws Error if `COHERE_API_KEY` is not found.
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```typescript
|
|
166
|
+
* import { rerank } from '@tanstack/ai'
|
|
167
|
+
* import { cohereRerank } from '@tanstack/ai-cohere'
|
|
168
|
+
*
|
|
169
|
+
* const { rerankedDocuments } = await rerank({
|
|
170
|
+
* adapter: cohereRerank('rerank-v3.5'),
|
|
171
|
+
* query: 'talk about rain',
|
|
172
|
+
* documents: ['sunny day', 'rainy afternoon'],
|
|
173
|
+
* })
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
export function cohereRerank<TModel extends CohereRerankModel>(
|
|
177
|
+
model: TModel,
|
|
178
|
+
config?: Omit<CohereClientConfig, 'apiKey'>,
|
|
179
|
+
): CohereRerankAdapter<TModel> {
|
|
180
|
+
return createCohereRerank(model, getCohereApiKeyFromEnv(), config)
|
|
181
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Cohere Adapters (tree-shakeable)
|
|
3
|
+
// ============================================================================
|
|
4
|
+
|
|
5
|
+
// Rerank adapter - document reranking via Cohere's /v2/rerank endpoint
|
|
6
|
+
export {
|
|
7
|
+
CohereRerankAdapter,
|
|
8
|
+
createCohereRerank,
|
|
9
|
+
cohereRerank,
|
|
10
|
+
} from './adapters/rerank'
|
|
11
|
+
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Type Exports
|
|
14
|
+
// ============================================================================
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
COHERE_RERANK_MODELS,
|
|
18
|
+
type CohereRerankModel,
|
|
19
|
+
type CohereRerankProviderOptions,
|
|
20
|
+
type CohereRerankModelProviderOptionsByName,
|
|
21
|
+
type InferCohereRerankProviderOptions,
|
|
22
|
+
} from './model-meta'
|
|
23
|
+
|
|
24
|
+
export type { CohereClientConfig } from './utils/client'
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cohere rerank model metadata.
|
|
3
|
+
*
|
|
4
|
+
* Provider options are resolved per model at the `cohereRerank('model')` call
|
|
5
|
+
* site via {@link CohereRerankModelProviderOptionsByName}. Cohere's rerank
|
|
6
|
+
* models currently share the same options, but the per-model map keeps the
|
|
7
|
+
* surface symmetric with the other adapters and lets divergent options be
|
|
8
|
+
* expressed later without changing the adapter contract.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** Available Cohere rerank models. */
|
|
12
|
+
export const COHERE_RERANK_MODELS = [
|
|
13
|
+
'rerank-v3.5',
|
|
14
|
+
'rerank-english-v3.0',
|
|
15
|
+
'rerank-multilingual-v3.0',
|
|
16
|
+
] as const
|
|
17
|
+
|
|
18
|
+
/** Union of supported Cohere rerank model names. */
|
|
19
|
+
export type CohereRerankModel = (typeof COHERE_RERANK_MODELS)[number]
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Provider-specific options for a Cohere rerank request. Forwarded on the
|
|
23
|
+
* `modelOptions` field of `rerank()`.
|
|
24
|
+
*/
|
|
25
|
+
export interface CohereRerankProviderOptions {
|
|
26
|
+
/**
|
|
27
|
+
* Long documents are chunked to fit the model's context. This caps the
|
|
28
|
+
* number of tokens kept per document. Cohere defaults to 4096.
|
|
29
|
+
*/
|
|
30
|
+
maxTokensPerDoc?: number
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Per-model provider-options map. Each model resolves to its own options type
|
|
35
|
+
* at the factory call site (see {@link InferCohereRerankProviderOptions}).
|
|
36
|
+
*/
|
|
37
|
+
export interface CohereRerankModelProviderOptionsByName {
|
|
38
|
+
'rerank-v3.5': CohereRerankProviderOptions
|
|
39
|
+
'rerank-english-v3.0': CohereRerankProviderOptions
|
|
40
|
+
'rerank-multilingual-v3.0': CohereRerankProviderOptions
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Resolve the provider options for a given rerank model. Falls back to the
|
|
45
|
+
* base options for any model not in the map.
|
|
46
|
+
*/
|
|
47
|
+
export type InferCohereRerankProviderOptions<TModel extends string> =
|
|
48
|
+
TModel extends keyof CohereRerankModelProviderOptionsByName
|
|
49
|
+
? CohereRerankModelProviderOptionsByName[TModel]
|
|
50
|
+
: CohereRerankProviderOptions
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cohere client configuration shared by the rerank adapter.
|
|
3
|
+
*/
|
|
4
|
+
export interface CohereClientConfig {
|
|
5
|
+
/** Cohere API key. Required by the adapter factories. */
|
|
6
|
+
apiKey: string
|
|
7
|
+
/** Override the API base URL. Defaults to `https://api.cohere.com`. */
|
|
8
|
+
baseUrl?: string
|
|
9
|
+
/** Extra headers merged into every request. */
|
|
10
|
+
headers?: Record<string, string>
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const COHERE_DEFAULT_BASE_URL = 'https://api.cohere.com'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Reads the Cohere API key from the environment.
|
|
17
|
+
*
|
|
18
|
+
* Looks for `COHERE_API_KEY` in `process.env` (Node) or `window.env`
|
|
19
|
+
* (browser with injected env).
|
|
20
|
+
*
|
|
21
|
+
* @throws Error if `COHERE_API_KEY` is not found.
|
|
22
|
+
*/
|
|
23
|
+
export function getCohereApiKeyFromEnv(): string {
|
|
24
|
+
const windowEnv =
|
|
25
|
+
typeof globalThis !== 'undefined' &&
|
|
26
|
+
(globalThis as Record<string, unknown>).window
|
|
27
|
+
? ((
|
|
28
|
+
(globalThis as Record<string, unknown>).window as Record<
|
|
29
|
+
string,
|
|
30
|
+
unknown
|
|
31
|
+
>
|
|
32
|
+
).env as Record<string, string> | undefined)
|
|
33
|
+
: undefined
|
|
34
|
+
const processEnv = typeof process !== 'undefined' ? process.env : undefined
|
|
35
|
+
// Prefer an injected `window.env` (browser builds) but fall back to
|
|
36
|
+
// `process.env` — bundlers and Electron can populate it even when `window`
|
|
37
|
+
// exists.
|
|
38
|
+
const key = windowEnv?.['COHERE_API_KEY'] ?? processEnv?.['COHERE_API_KEY']
|
|
39
|
+
if (!key) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
'COHERE_API_KEY not found in environment. Pass an API key explicitly via createCohereRerank(model, apiKey).',
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
return key
|
|
45
|
+
}
|