@volter/twin-cohere 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +224 -0
- package/defaults/handlers.json +26 -0
- package/dist/defaults/handlers.json +26 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +31 -0
- package/dist/src/cohere-budget.d.ts +55 -0
- package/dist/src/cohere-budget.js +171 -0
- package/dist/src/cohere-capabilities.d.ts +14 -0
- package/dist/src/cohere-capabilities.js +1852 -0
- package/dist/src/cohere-conformance.d.ts +17 -0
- package/dist/src/cohere-conformance.js +464 -0
- package/dist/src/cohere-connector.d.ts +150 -0
- package/dist/src/cohere-connector.js +625 -0
- package/dist/src/cohere-models.d.ts +21 -0
- package/dist/src/cohere-models.js +73 -0
- package/dist/src/cohere-scenario.d.ts +57 -0
- package/dist/src/cohere-scenario.js +176 -0
- package/dist/src/cohere-server.d.ts +16 -0
- package/dist/src/cohere-server.js +184 -0
- package/dist/src/cohere-stub.d.ts +119 -0
- package/dist/src/cohere-stub.js +321 -0
- package/dist/src/cohere-twin.d.ts +82 -0
- package/dist/src/cohere-twin.js +1243 -0
- package/dist/src/cohere-types.d.ts +226 -0
- package/dist/src/cohere-types.js +40 -0
- package/dist/src/index.d.ts +15 -0
- package/dist/src/index.js +84 -0
- package/package.json +71 -0
- package/src/cli.ts +30 -0
- package/src/cohere-budget.ts +197 -0
- package/src/cohere-capabilities.ts +1855 -0
- package/src/cohere-conformance.ts +489 -0
- package/src/cohere-connector.ts +709 -0
- package/src/cohere-models.ts +79 -0
- package/src/cohere-scenario.ts +194 -0
- package/src/cohere-server.ts +195 -0
- package/src/cohere-stub.ts +337 -0
- package/src/cohere-twin.ts +1290 -0
- package/src/cohere-types.ts +231 -0
- package/src/index.ts +159 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
// Shared wire-shape types for the Cohere API surface. These mirror the real vendor JSON shapes
|
|
2
|
+
// (not an SDK's internal types — the twin never imports a vendor SDK at runtime; the SDKs are
|
|
3
|
+
// exercised only in *.test.ts). Kept minimal but faithful.
|
|
4
|
+
//
|
|
5
|
+
// COHERE SPEAKS ITS OWN DIALECT. It is NOT OpenAI-compatible and copying an OpenAI-shaped pack's
|
|
6
|
+
// permissiveness would be exactly the bug: Cohere's chat response has no `choices` array, its
|
|
7
|
+
// finish reasons are UPPER-CASE (`COMPLETE`/`TOOL_CALL`/`MAX_TOKENS`), its usage lives under
|
|
8
|
+
// `usage.billed_units`/`usage.tokens` (v2) or `meta.billed_units` (v1), and its error envelope is
|
|
9
|
+
// a BARE `{ "message": "…" }` with no `error` wrapper, no `type`, no `code`.
|
|
10
|
+
//
|
|
11
|
+
// PROVENANCE for every shape below: the two SDKs this pack is built against, read from their
|
|
12
|
+
// published npm tarballs during this build (2026-08-31):
|
|
13
|
+
// • cohere-ai@8.1.0 — the Fern-generated client. The WIRE keys come from its
|
|
14
|
+
// `serialization/**/*.d.ts` `interface Raw` blocks (Fern's serializers map snake_case wire
|
|
15
|
+
// keys onto camelCase TS properties, so the TS types alone would be MISLEADING here):
|
|
16
|
+
// `V2ChatResponse`, `AssistantMessageResponse`, `Usage`, `UsageTokens`, `UsageBilledUnits`,
|
|
17
|
+
// `ChatFinishReason`, `V2ChatStreamResponse` (+ its twelve event members),
|
|
18
|
+
// `EmbedByTypeResponse`, `EmbedByTypeResponseEmbeddings`, `EmbedFloatsResponse`,
|
|
19
|
+
// `V2RerankResponse`, `V2RerankResponseResultsItem`, `ClassifyResponse`, `TokenizeResponse`,
|
|
20
|
+
// `DetokenizeResponse`, `CheckApiKeyResponse`, `ListModelsResponse`, `GetModelResponse`,
|
|
21
|
+
// `ApiMeta`, `ApiMetaBilledUnits`, `ApiMetaApiVersion`, `NonStreamedChatResponse`, `Dataset`,
|
|
22
|
+
// `Connector`, `EmbedJob`, `ToolCallV2`.
|
|
23
|
+
// • @ai-sdk/cohere@4.0.35 — the SECOND independent transcription of the same wire, and the
|
|
24
|
+
// STRICTER one for chat/embed/rerank: `cohereChatResponseSchema`, `cohereChatChunkSchema`
|
|
25
|
+
// (a `z.discriminatedUnion("type", …)` over the stream events), `cohereUsageSchema`,
|
|
26
|
+
// `cohereTextEmbeddingResponseSchema`, `cohereRerankingResponseSchema` and
|
|
27
|
+
// `cohereErrorDataSchema`. Where the two disagree in strictness the twin satisfies BOTH.
|
|
28
|
+
|
|
29
|
+
// ── Errors ──────────────────────────────────────────────────────────────────────────────
|
|
30
|
+
/**
|
|
31
|
+
* Cohere's API error envelope. It is a BARE object with ONE key — exactly as
|
|
32
|
+
* @ai-sdk/cohere@4.0.35's `cohereErrorDataSchema` transcribes it:
|
|
33
|
+
* `cohereErrorDataSchema = z.object({ message: z.string() })`
|
|
34
|
+
* There is no `error` wrapper, no `type`, and no `code`. A twin that emitted OpenAI's
|
|
35
|
+
* `{ error: { message, type } }` here would be caught by that schema on every failure path.
|
|
36
|
+
*/
|
|
37
|
+
export type CohereApiError = { message: string };
|
|
38
|
+
|
|
39
|
+
// ── Chat v2 (`POST /v2/chat`) ───────────────────────────────────────────────────────────
|
|
40
|
+
/** A v2 chat message as the caller sends it. `content` is a string OR a content-part array. */
|
|
41
|
+
export type CohereMessageV2 = {
|
|
42
|
+
role: 'user' | 'assistant' | 'system' | 'tool';
|
|
43
|
+
content?: string | Array<Record<string, unknown>> | null;
|
|
44
|
+
tool_calls?: CohereToolCallV2[] | null;
|
|
45
|
+
tool_plan?: string | null;
|
|
46
|
+
tool_call_id?: string | null;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* `ToolCallV2`. The vendor's own serializer declares `function?: ToolCallV2Function.Raw | null`,
|
|
51
|
+
* with `name` and `arguments` optional INSIDE it — but this type deliberately declares all three
|
|
52
|
+
* REQUIRED, because that is what the twin EMITS and what a caller may rely on.
|
|
53
|
+
*
|
|
54
|
+
* The narrowing is the right way round: @ai-sdk/cohere's `cohereChatResponseSchema` requires
|
|
55
|
+
* `function.name` and `function.arguments` on every tool call, and its `tool-call-start` chunk
|
|
56
|
+
* schema requires them too — so a twin that emitted the vendor's loosest legal shape would fail
|
|
57
|
+
* the stricter of its two clients. Narrower on OUTPUT, never on input. (§9 round 1, finding 9
|
|
58
|
+
* caught the comment here saying the opposite of the code.)
|
|
59
|
+
*/
|
|
60
|
+
export type CohereToolCallV2 = {
|
|
61
|
+
id: string;
|
|
62
|
+
type: 'function';
|
|
63
|
+
function: { name: string; arguments: string };
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The reason a chat request finished. Cohere's values are UPPER-CASE and are its own set — this
|
|
68
|
+
* is the single most conspicuous place an OpenAI-shaped copy goes wrong (`stop` / `tool_calls`
|
|
69
|
+
* are NOT Cohere values). Source: `api/types/ChatFinishReason.d.ts`.
|
|
70
|
+
*/
|
|
71
|
+
export type CohereFinishReason = 'COMPLETE' | 'STOP_SEQUENCE' | 'MAX_TOKENS' | 'TOOL_CALL' | 'ERROR' | 'TIMEOUT';
|
|
72
|
+
|
|
73
|
+
export const COHERE_FINISH_REASONS: readonly CohereFinishReason[] = ['COMPLETE', 'STOP_SEQUENCE', 'MAX_TOKENS', 'TOOL_CALL', 'ERROR', 'TIMEOUT'];
|
|
74
|
+
|
|
75
|
+
/** `Usage` — TWO nested counters, `billed_units` and `tokens`, not a flat `prompt_tokens` trio. */
|
|
76
|
+
export type CohereUsage = {
|
|
77
|
+
billed_units: { input_tokens: number; output_tokens: number };
|
|
78
|
+
tokens: { input_tokens: number; output_tokens: number };
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/** A content item on an assistant response message. */
|
|
82
|
+
export type CohereAssistantContentItem =
|
|
83
|
+
| { type: 'text'; text: string }
|
|
84
|
+
| { type: 'thinking'; thinking: string };
|
|
85
|
+
|
|
86
|
+
/** `AssistantMessageResponse`. */
|
|
87
|
+
export type CohereAssistantMessage = {
|
|
88
|
+
role: 'assistant';
|
|
89
|
+
content?: CohereAssistantContentItem[];
|
|
90
|
+
tool_plan?: string;
|
|
91
|
+
tool_calls?: CohereToolCallV2[];
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/** The unary `POST /v2/chat` envelope — NO `choices`, NO `object`, NO `created`. */
|
|
95
|
+
export type CohereChatV2Response = {
|
|
96
|
+
id: string;
|
|
97
|
+
finish_reason: CohereFinishReason;
|
|
98
|
+
message: CohereAssistantMessage;
|
|
99
|
+
usage: CohereUsage;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* The v2 streaming event `type` values, in the order `cohereChatChunkSchema`'s discriminated
|
|
104
|
+
* union declares them. The twin emits a subset; the SET is the vendor's.
|
|
105
|
+
*/
|
|
106
|
+
export type CohereStreamEventType =
|
|
107
|
+
| 'message-start' | 'content-start' | 'content-delta' | 'content-end'
|
|
108
|
+
| 'tool-plan-delta' | 'tool-call-start' | 'tool-call-delta' | 'tool-call-end'
|
|
109
|
+
| 'citation-start' | 'citation-end' | 'message-end' | 'debug';
|
|
110
|
+
|
|
111
|
+
// ── Chat v1 (`POST /v1/chat`) — a DIFFERENT envelope, not a versioned alias ──────────────
|
|
112
|
+
/**
|
|
113
|
+
* v1's OWN finish-reason set. It is NOT the v2 `ChatFinishReason` set, which is the sort of
|
|
114
|
+
* conflation that looks harmless until a value crosses over: `NonStreamedChatResponse.finish_reason`
|
|
115
|
+
* is `FinishReason` — all EIGHT of `COMPLETE | STOP_SEQUENCE | ERROR | ERROR_TOXIC | ERROR_LIMIT |
|
|
116
|
+
* USER_CANCEL | MAX_TOKENS | TIMEOUT` (`api/types/FinishReason.d.ts`), with **no `TOOL_CALL`** and
|
|
117
|
+
* with three members v2 does not have. Typing the v1 body with the v2 union invited `TOOL_CALL`
|
|
118
|
+
* onto a response the vendor's union rejects (§9 round 1, finding 9) — and the first correction
|
|
119
|
+
* then transcribed only six of the eight, which §9 round two caught: this const is public API, so a
|
|
120
|
+
* consumer validating a v1 body against a short set rejects two legal vendor values.
|
|
121
|
+
* The twin only ever emits `COMPLETE` on v1, which is valid in this set, in the v2 set, and in the
|
|
122
|
+
* narrower `ChatStreamEndEventFinishReason` the v1 stream terminator uses.
|
|
123
|
+
*/
|
|
124
|
+
export type CohereV1FinishReason = 'COMPLETE' | 'STOP_SEQUENCE' | 'ERROR' | 'ERROR_TOXIC' | 'ERROR_LIMIT' | 'USER_CANCEL' | 'MAX_TOKENS' | 'TIMEOUT';
|
|
125
|
+
|
|
126
|
+
export const COHERE_V1_FINISH_REASONS: readonly CohereV1FinishReason[] = ['COMPLETE', 'STOP_SEQUENCE', 'ERROR', 'ERROR_TOXIC', 'ERROR_LIMIT', 'USER_CANCEL', 'MAX_TOKENS', 'TIMEOUT'];
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* `NonStreamedChatResponse`. v1 answers a FLAT `text` string with `meta` (not `usage`), and takes
|
|
130
|
+
* a single `message` string plus `chat_history` — it is a different protocol from v2, sharing
|
|
131
|
+
* only the host. Modeling it as "v2 with a prefix" is the trap.
|
|
132
|
+
*/
|
|
133
|
+
export type CohereChatV1Response = {
|
|
134
|
+
text: string;
|
|
135
|
+
generation_id: string;
|
|
136
|
+
response_id: string;
|
|
137
|
+
finish_reason: CohereV1FinishReason;
|
|
138
|
+
chat_history: Array<{ role: string; message: string }>;
|
|
139
|
+
meta: CohereApiMeta;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
// ── `ApiMeta` — the v1 metering envelope ────────────────────────────────────────────────
|
|
143
|
+
export type CohereApiMeta = {
|
|
144
|
+
api_version: { version: string };
|
|
145
|
+
billed_units: Partial<{ input_tokens: number; output_tokens: number; search_units: number; classifications: number; images: number; image_tokens: number; pages: number }>;
|
|
146
|
+
tokens?: { input_tokens?: number; output_tokens?: number };
|
|
147
|
+
warnings?: string[];
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// ── Embed ───────────────────────────────────────────────────────────────────────────────
|
|
151
|
+
/** The six `EmbeddingType` values Cohere accepts. `float` is the default and the only one
|
|
152
|
+
* @ai-sdk/cohere requests. */
|
|
153
|
+
export const COHERE_EMBEDDING_TYPES = ['float', 'int8', 'uint8', 'binary', 'ubinary', 'base64'] as const;
|
|
154
|
+
export type CohereEmbeddingType = (typeof COHERE_EMBEDDING_TYPES)[number];
|
|
155
|
+
|
|
156
|
+
/** The five `EmbedInputType` values. v2 embed REQUIRES one; v1 does not. */
|
|
157
|
+
export const COHERE_INPUT_TYPES = ['search_document', 'search_query', 'classification', 'clustering', 'image'] as const;
|
|
158
|
+
export type CohereInputType = (typeof COHERE_INPUT_TYPES)[number];
|
|
159
|
+
|
|
160
|
+
/** `V2EmbedRequestTruncate` / `EmbedRequestTruncate` — UPPER-CASE, unlike most vendors' enums. */
|
|
161
|
+
export const COHERE_TRUNCATE = ['NONE', 'START', 'END'] as const;
|
|
162
|
+
|
|
163
|
+
/** `EmbedByTypeResponse` — v2 keys the vectors BY TYPE under `embeddings`. */
|
|
164
|
+
export type CohereEmbedV2Response = {
|
|
165
|
+
id: string;
|
|
166
|
+
embeddings: Partial<Record<CohereEmbeddingType, number[][] | string[]>>;
|
|
167
|
+
texts: string[];
|
|
168
|
+
response_type: 'embeddings_by_type';
|
|
169
|
+
meta: CohereApiMeta;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
/** `EmbedFloatsResponse` — v1's DEFAULT answer puts a flat `number[][]` at `embeddings`. The two
|
|
173
|
+
* shapes are not interchangeable, and the v1 caller only gets the by-type shape when it asks for
|
|
174
|
+
* `embedding_types`. */
|
|
175
|
+
export type CohereEmbedV1FloatsResponse = {
|
|
176
|
+
id: string;
|
|
177
|
+
embeddings: number[][];
|
|
178
|
+
texts: string[];
|
|
179
|
+
response_type: 'embeddings_floats';
|
|
180
|
+
meta: CohereApiMeta;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
// ── Rerank ──────────────────────────────────────────────────────────────────────────────
|
|
184
|
+
export type CohereRerankResult = { index: number; relevance_score: number; document?: { text: string } };
|
|
185
|
+
export type CohereRerankResponse = { id: string; results: CohereRerankResult[]; meta: CohereApiMeta };
|
|
186
|
+
|
|
187
|
+
// ── Classify ────────────────────────────────────────────────────────────────────────────
|
|
188
|
+
export type CohereClassification = {
|
|
189
|
+
id: string;
|
|
190
|
+
input: string;
|
|
191
|
+
prediction: string;
|
|
192
|
+
predictions: string[];
|
|
193
|
+
confidence: number;
|
|
194
|
+
confidences: number[];
|
|
195
|
+
labels: Record<string, { confidence: number }>;
|
|
196
|
+
classification_type: 'single-label' | 'multi-label';
|
|
197
|
+
};
|
|
198
|
+
export type CohereClassifyResponse = { id: string; classifications: CohereClassification[]; meta: CohereApiMeta };
|
|
199
|
+
|
|
200
|
+
// ── Tokenize / detokenize / check-api-key ───────────────────────────────────────────────
|
|
201
|
+
export type CohereTokenizeResponse = { tokens: number[]; token_strings: string[]; meta: CohereApiMeta };
|
|
202
|
+
export type CohereDetokenizeResponse = { text: string; meta: CohereApiMeta };
|
|
203
|
+
export type CohereCheckApiKeyResponse = { valid: boolean; organization_id: string; owner_id: string };
|
|
204
|
+
|
|
205
|
+
// ── Models ──────────────────────────────────────────────────────────────────────────────
|
|
206
|
+
/** `CompatibleEndpoint` — the closed set of endpoint names a model card may list. */
|
|
207
|
+
export const COHERE_ENDPOINTS = ['chat', 'embed', 'classify', 'summarize', 'rerank', 'rate', 'generate'] as const;
|
|
208
|
+
export type CohereEndpoint = (typeof COHERE_ENDPOINTS)[number];
|
|
209
|
+
|
|
210
|
+
export type CohereModelCard = {
|
|
211
|
+
name: string;
|
|
212
|
+
endpoints: CohereEndpoint[];
|
|
213
|
+
finetuned: boolean;
|
|
214
|
+
context_length: number;
|
|
215
|
+
tokenizer_url: string | null;
|
|
216
|
+
default_endpoints: CohereEndpoint[];
|
|
217
|
+
is_deprecated?: boolean;
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// ── Streaming ───────────────────────────────────────────────────────────────────────────
|
|
221
|
+
/**
|
|
222
|
+
* A single Server-Sent Event the streaming path emits (collected in tests, socketed by the
|
|
223
|
+
* server). `data` is the JSON payload; the terminator is signalled with `done: true` — cohere-ai's
|
|
224
|
+
* `core.Stream` is constructed with `eventShape: { type: 'sse', streamTerminator: '[DONE]' }`, so
|
|
225
|
+
* `data: [DONE]` is what ends a v2 chat stream.
|
|
226
|
+
*/
|
|
227
|
+
export type SseEvent = { data?: Record<string, unknown>; done?: boolean };
|
|
228
|
+
|
|
229
|
+
/** A sink the streaming path writes events into (an injected collector in tests / a real HTTP SSE
|
|
230
|
+
* writer in the server). NO real sockets or setTimeout in the handler. */
|
|
231
|
+
export type SseSink = (event: SseEvent) => void;
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// @volter/twin-cohere — the Cohere twin (one vendor, one package), built on the shared
|
|
2
|
+
// @volter/world-core kernel. Cohere's API is TWO protocols on one host: the v1 surface
|
|
3
|
+
// (`/v1/chat` with a single `message` string, `/v1/embed` answering flat float vectors,
|
|
4
|
+
// `/v1/rerank`, `/v1/classify`, `/v1/tokenize`, `/v1/models`, datasets, connectors, embed jobs)
|
|
5
|
+
// and the v2 surface (`/v2/chat` with structured `messages[]`, `/v2/embed` keyed by embedding
|
|
6
|
+
// type, `/v2/rerank`). Both are modeled — vendor-faithfully, and as the DIFFERENT protocols they
|
|
7
|
+
// are rather than as a versioned alias. (Cohere is an API-first vendor: its dashboard is
|
|
8
|
+
// incidental tooling for keys, billing and usage, not where the work happens —
|
|
9
|
+
// docs/contributing/architecture.md C1b — so this pack ships no mirror.)
|
|
10
|
+
//
|
|
11
|
+
// THE HONEST CARVE-OUT: the twin cannot run the model, so every generative endpoint returns a
|
|
12
|
+
// DETERMINISTIC STUB (clearly labeled `[twin-stub:<model>]`), never pretending to be real
|
|
13
|
+
// inference. Everything around it — the wire protocol — is faithful. (Conformance + capability
|
|
14
|
+
// tooling live in @volter/world-tooling, a dev dependency — NOT re-exported here, per E2.)
|
|
15
|
+
export { handleCohereTwinRequest, buildChatV2, streamChatV2, COHERE_ROUTER_SURFACE, COHERE_CLOSED_SETS } from './cohere-twin.ts';
|
|
16
|
+
export type { CohereRequest, CohereResponseEnvelope, ChatV2Args } from './cohere-twin.ts';
|
|
17
|
+
export { createCohereTwinFetch, createCohereTwinServer, type CohereTwinFetchOptions } from './cohere-server.ts';
|
|
18
|
+
export { cohereScenarioAdapter, createCohereScenarioEngine, loadCohereScenarioDocument, realizeCohereRespond } from './cohere-scenario.ts';
|
|
19
|
+
export type { CohereScenarioEngine, CohereScenarioRequest, CohereScenarioRespond, ScenarioToolCall, ScriptedResult } from './cohere-scenario.ts';
|
|
20
|
+
export { COHERE_MODELS, COHERE_ENDPOINTS, findModel, modelServes } from './cohere-models.ts';
|
|
21
|
+
export {
|
|
22
|
+
base64Embedding,
|
|
23
|
+
classifyText,
|
|
24
|
+
COHERE_OUTPUT_DIMENSIONS,
|
|
25
|
+
cohereId,
|
|
26
|
+
contentToText,
|
|
27
|
+
countInputTokens,
|
|
28
|
+
embedDimensions,
|
|
29
|
+
estimateTokens,
|
|
30
|
+
fnv1a,
|
|
31
|
+
lastUserText,
|
|
32
|
+
preferredTokenId,
|
|
33
|
+
pseudoEmbedding,
|
|
34
|
+
quantizeEmbedding,
|
|
35
|
+
rerankScore,
|
|
36
|
+
segmentText,
|
|
37
|
+
stubAssistantText,
|
|
38
|
+
stubToolArguments,
|
|
39
|
+
stubToolCall,
|
|
40
|
+
stubToolPlan,
|
|
41
|
+
stubV1Text,
|
|
42
|
+
toolCallId,
|
|
43
|
+
toolNames,
|
|
44
|
+
} from './cohere-stub.ts';
|
|
45
|
+
export {
|
|
46
|
+
COHERE_EMBEDDING_TYPES,
|
|
47
|
+
COHERE_ENDPOINTS as COHERE_COMPATIBLE_ENDPOINTS,
|
|
48
|
+
COHERE_FINISH_REASONS,
|
|
49
|
+
COHERE_INPUT_TYPES,
|
|
50
|
+
COHERE_TRUNCATE,
|
|
51
|
+
COHERE_V1_FINISH_REASONS,
|
|
52
|
+
} from './cohere-types.ts';
|
|
53
|
+
export type {
|
|
54
|
+
CohereApiError, CohereApiMeta, CohereAssistantContentItem, CohereAssistantMessage,
|
|
55
|
+
CohereChatV1Response, CohereChatV2Response, CohereClassifyResponse, CohereEmbedV1FloatsResponse,
|
|
56
|
+
CohereEmbedV2Response, CohereEmbeddingType, CohereFinishReason, CohereInputType,
|
|
57
|
+
CohereMessageV2, CohereModelCard, CohereRerankResponse, CohereToolCallV2, CohereUsage,
|
|
58
|
+
CohereV1FinishReason,
|
|
59
|
+
SseEvent, SseSink,
|
|
60
|
+
} from './cohere-types.ts';
|
|
61
|
+
export {
|
|
62
|
+
COHERE_API_BASE,
|
|
63
|
+
cohereRequestForAction,
|
|
64
|
+
fullSyncCohere,
|
|
65
|
+
liveCohereExecute,
|
|
66
|
+
mapConnector,
|
|
67
|
+
mapDataset,
|
|
68
|
+
mapEmbedJob,
|
|
69
|
+
pollTimestamp,
|
|
70
|
+
pullCohereState,
|
|
71
|
+
pushCohereAction,
|
|
72
|
+
pushPendingCohereActions,
|
|
73
|
+
syncCohereFromReal,
|
|
74
|
+
unpushableReason,
|
|
75
|
+
} from './cohere-connector.ts';
|
|
76
|
+
export type { CohereExecute, LiveCohereOptions } from './cohere-connector.ts';
|
|
77
|
+
// The client-side rate budget — the fail-closed backstop `liveCohereExecute` routes every live
|
|
78
|
+
// request through. The MECHANISM is the kernel's shared, vendor-agnostic `RateBudget`; what lives
|
|
79
|
+
// here is Cohere's DECLARATION (window/ceiling/per-endpoint weights) plus the vendor-bound
|
|
80
|
+
// bindings. Exported so an operator can inspect spend (`snapshot`) and so a caller can catch
|
|
81
|
+
// `CohereBudgetError` by type; there is deliberately no export that disables the guard.
|
|
82
|
+
export {
|
|
83
|
+
COHERE_BUDGET_CEILING,
|
|
84
|
+
COHERE_BUDGET_MAX_RETRY_AFTER_S,
|
|
85
|
+
COHERE_BUDGET_WINDOW_MS,
|
|
86
|
+
COHERE_CALL_WEIGHTS,
|
|
87
|
+
COHERE_RATE_BUDGET,
|
|
88
|
+
CohereBudget,
|
|
89
|
+
CohereBudgetError,
|
|
90
|
+
cohereBudgetPath,
|
|
91
|
+
cohereCallWeight,
|
|
92
|
+
} from './cohere-budget.ts';
|
|
93
|
+
export type { CohereBudgetErrorKind, CohereBudgetOptions, CohereBudgetReservation, CohereBudgetSnapshot } from './cohere-budget.ts';
|
|
94
|
+
|
|
95
|
+
// Registry descriptor: the pack self-describes so tooling can discover it, and it is the SINGLE
|
|
96
|
+
// HOME for this vendor's world-facing facts. `bun scripts/pack-facts.ts` compiles `adoption` /
|
|
97
|
+
// `hosts` / `endpointEnv` into packages/world-core/generated/pack-facts.json; re-run it
|
|
98
|
+
// after ANY edit below or the drift gate (scripts/pack-facts.test.ts) goes RED.
|
|
99
|
+
import type { TwinPack } from '@volter/world-core';
|
|
100
|
+
import { COHERE_RATE_BUDGET as RATE_BUDGET } from './cohere-budget.ts';
|
|
101
|
+
export const pack: TwinPack = {
|
|
102
|
+
vendor: 'cohere',
|
|
103
|
+
// The SAME object cohere-budget.ts declares at module load — one source of truth, so
|
|
104
|
+
// registering the pack and importing the connector can never arm two different ceilings.
|
|
105
|
+
rateBudget: RATE_BUDGET,
|
|
106
|
+
transport: 'rest',
|
|
107
|
+
archetype: 'generative',
|
|
108
|
+
bin: 'world-cohere',
|
|
109
|
+
// The subject types this twin projects. `token` is the LEARNED TOKENIZER VOCABULARY that
|
|
110
|
+
// `/v1/tokenize` observes and `/v1/detokenize` folds — twin-local state with no vendor
|
|
111
|
+
// endpoint, which is why the connector refuses to push it type-wide.
|
|
112
|
+
resources: ['dataset', 'connector', 'embed_job', 'token'],
|
|
113
|
+
specSource: 'Cohere API v1 + v2, grounded in the two installed SDKs (cohere-ai@8.1.0 — the Fern-generated client, whose serialization/**/*.d.ts `interface Raw` blocks carry the snake_case WIRE keys — and @ai-sdk/cohere@4.0.35, whose zod schemas are the stricter second transcription of chat/embed/rerank); envelope-faithful, model output is a labeled stub',
|
|
114
|
+
description: 'Cohere twin — faithful v1 AND v2 protocol envelopes (chat with SSE and NDJSON streaming, tool calls, UPPER-CASE finish reasons, two-level usage), deterministic embeddings across all six embedding_types, rerank/classify, a learned tokenizer vocabulary, the real model catalog, and stateful datasets / connectors / embed jobs; generative output is a labeled stub.',
|
|
115
|
+
// cohere-ai addresses the same origin with `v1/…` and `v2/…` paths (`core.url.join(environment,
|
|
116
|
+
// "v2/chat")`); @ai-sdk/cohere's default baseURL is 'https://api.cohere.com/v2'. The common
|
|
117
|
+
// prefix both share is the origin root, so the browser-routing prefix is '/'.
|
|
118
|
+
browserRouting: { apiPathPrefix: '/', loaderHost: 'https://api.cohere.com' },
|
|
119
|
+
|
|
120
|
+
// ADOPTION — how an app repo betrays that it talks to this vendor (§7 point 11), declared HERE
|
|
121
|
+
// rather than in the central SDK_TWINS / ENV_STEM_VENDORS maps (declaring a fact in both homes
|
|
122
|
+
// throws at module init).
|
|
123
|
+
// • sdks — the TWO official npm clients of the surface this pack models: Cohere's own
|
|
124
|
+
// Fern-generated client and the Vercel AI SDK provider. `cohere-ai` was on covers.ts's
|
|
125
|
+
// UNKNOWN_DEP_KNOWN_SERVICES list (the curated "well-known client with NO twin pack" set)
|
|
126
|
+
// until this pack was born; that entry is deleted in the same commit, because
|
|
127
|
+
// scripts/packless-claims.test.ts is RED on any name both packless-listed and pack-claimed.
|
|
128
|
+
// • envStems — the two SDKs read DIFFERENT variables and both are claimed: cohere-ai's
|
|
129
|
+
// `BearerAuthProvider` falls back to `CO_API_KEY` (`const ENV_TOKEN = "CO_API_KEY"`), while
|
|
130
|
+
// @ai-sdk/cohere calls `loadApiKey({ environmentVariableName: 'COHERE_API_KEY' })`. Claiming
|
|
131
|
+
// only one would let an app configured for the other read as uncovered. The stems are
|
|
132
|
+
// written bare because the overlay lowercases and the detector strips non-alphanumerics.
|
|
133
|
+
// • NO `scopes` entry: Cohere owns no npm scope. `@ai-sdk/` belongs to Vercel and is shared by
|
|
134
|
+
// every provider, so claiming it would attribute openai/anthropic/mistral traffic here.
|
|
135
|
+
adoption: {
|
|
136
|
+
// Cohere's official Python SDK (`cohere-ai` on npm, `cohere` on PyPI).
|
|
137
|
+
pypi: ['cohere'],
|
|
138
|
+
sdks: ['cohere-ai', '@ai-sdk/cohere'],
|
|
139
|
+
envStems: ['COHERE', 'CO'],
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
// INTERCEPTION (§7 point 8). ONE host: `CohereEnvironment` in cohere-ai@8.1.0's
|
|
143
|
+
// environments.d.ts declares exactly `Production: "https://api.cohere.com"` and nothing else —
|
|
144
|
+
// no regional or staging siblings — and @ai-sdk/cohere's default baseURL is that host plus
|
|
145
|
+
// `/v2`. The Bedrock/SageMaker clients the SDK also ships (`AwsClient`, `BedrockClient`,
|
|
146
|
+
// `SagemakerClient`) address AWS hosts, which are a different vendor's plane and deliberately
|
|
147
|
+
// NOT claimed here.
|
|
148
|
+
hosts: [{ host: 'api.cohere.com' }],
|
|
149
|
+
|
|
150
|
+
// WORLD WIRING (§7 point 12) — the ruling is NONE, and it is grounded, not skipped.
|
|
151
|
+
// NEITHER SDK reads a base-URL environment variable. cohere-ai takes the override as a
|
|
152
|
+
// CONSTRUCTOR option (`baseUrl` / `environment`, resolved through `core.Supplier.get`) and the
|
|
153
|
+
// only env var anywhere in its source is `CO_API_KEY` (plus the AWS credential names its Bedrock
|
|
154
|
+
// client uses); @ai-sdk/cohere takes `options.baseURL` and reads only `COHERE_API_KEY`.
|
|
155
|
+
// Inventing a `COHERE_BASE_URL` would make `covers` report the world covered — any app-read env
|
|
156
|
+
// counts — while the app, reading no such var, still talked to the real vendor. Interception is
|
|
157
|
+
// therefore host-based, via the `hosts` entry above, which is the truth.
|
|
158
|
+
endpointEnvNone: 'neither official SDK reads a base-URL env var: cohere-ai@8.1.0 takes the override as the `baseUrl`/`environment` CONSTRUCTOR option and reads only CO_API_KEY from the environment (auth/BearerAuthProvider.js), and @ai-sdk/cohere@4.0.35 takes `options.baseURL` and reads only COHERE_API_KEY. Interception is host-based on api.cohere.com; inventing a COHERE_BASE_URL nothing reads would make `covers` claim a world it does not cover.',
|
|
159
|
+
};
|