@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 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,3 @@
1
+ import { CohereRerankAdapter, cohereRerank, createCohereRerank } from "./adapters/rerank.js";
2
+ import { COHERE_RERANK_MODELS } from "./model-meta.js";
3
+ export { COHERE_RERANK_MODELS, CohereRerankAdapter, cohereRerank, createCohereRerank };
@@ -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
+ }