@qevrion/sdk 0.0.0-stage → 0.2.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 CHANGED
@@ -1,3 +1,138 @@
1
- # Temporary Holding Version
1
+ # @qevrion/sdk
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Small, dependency-free TypeScript client for QevrionAI text chat, streaming, embeddings, and model discovery. ESM, Node.js 20.3+. Keep API keys in your server environment.
4
+
5
+ ## Install
6
+
7
+ After publication:
8
+
9
+ ```sh
10
+ npm install @qevrion/sdk
11
+ ```
12
+
13
+ ```ts
14
+ import { Qevrion } from '@qevrion/sdk';
15
+
16
+ const client = new Qevrion({ apiKey: process.env.QEVRION_API_KEY! });
17
+ const { data: models } = await client.models.list({ type: 'chat' });
18
+ const model = models[0]?.id;
19
+ if (!model) throw new Error('No models are enabled.');
20
+
21
+ const result = await client.chat.completions.create({
22
+ model,
23
+ messages: [{ role: 'user', content: 'Hello!' }],
24
+ max_tokens: 256,
25
+ });
26
+ console.log(result.choices[0]?.message.content);
27
+
28
+ for await (const chunk of client.chat.completions.stream({
29
+ model,
30
+ messages: [{ role: 'user', content: 'Tell me a short story.' }],
31
+ })) {
32
+ process.stdout.write(chunk.choices[0]?.delta.content ?? '');
33
+ }
34
+ ```
35
+
36
+ `create()` returns a JSON completion; `stream()` returns an async iterable of raw chat chunks, including usage-only chunks. Breaking the loop cancels the reader and aborts the HTTP request. A stream ending without `[DONE]` raises `QevrionProtocolError` so interrupted responses are detectable. Cancellation cannot guarantee that the upstream provider stops generating or charging.
37
+
38
+ Supported input: text `system`, `user`, and `assistant` messages; `max_tokens` (1–4096, default 1024), `temperature` (0–2), and `top_p` (0–1). Model IDs must be enabled in the catalog. Tool calls, images, and native JSON schema output are not supported by the current API. Upstream `usage.cost`, when included, is not the final Qevrion account charge.
39
+
40
+ ## Embeddings
41
+
42
+ Available from SDK version `0.2.0`. An admin must publish an embedding model in the model catalog before use. Chat and embedding model IDs are separate; `models.list()` returns both types, while `models.list({ type: 'chat' })` and `models.list({ type: 'embedding' })` filter them.
43
+
44
+ ```ts
45
+ const { data: embeddingModels } = await client.models.list({ type: 'embedding' });
46
+ const embeddingModel = embeddingModels[0]?.id;
47
+ if (!embeddingModel) throw new Error('No embedding models are enabled.');
48
+
49
+ const result = await client.embeddings.create({
50
+ model: embeddingModel,
51
+ input: ['A document about Lagos.', 'A document about Abuja.'],
52
+ });
53
+ for (const item of result.data) {
54
+ console.log(item.index, item.embedding); // number[] with the default float format
55
+ }
56
+ ```
57
+
58
+ `input` accepts one non-empty string or 1–100 non-empty strings. The API caps the entire JSON request at 100,000 bytes; model context limits still apply. Token arrays, multimodal input, and streaming are not supported for embeddings. Optional parameters: `dimensions` (1–65536, subject to the model), `encoding_format` (`float` by default, or `base64`), and a provider-specific `input_type` such as `search_query` or `search_document`. With `encoding_format: 'base64'`, response embeddings are typed as strings. Each result includes its original input index; use it to match vectors to inputs.
59
+
60
+ Embeddings require the same account credits as chat. The API reserves a conservative estimate (minimum $0.01) and settles at 2× the reported upstream cost. If cost is missing, it estimates from reported prompt tokens and the catalog input price; if token usage is also missing, it conservatively uses input bytes as the token estimate. Estimated charges are marked in usage history. Provider HTTP errors and connection failures release the reservation. A malformed successful response is charged using the original reservation estimate and returned as an upstream error, since the provider may already have performed work.
61
+
62
+ ## Configuration and errors
63
+
64
+ The default API root is `https://useqevrion.com/v1`. For local development pass `baseURL: 'http://localhost:3000/v1'`. A custom `fetch` can be supplied for testing or transport integration. Redirects are rejected.
65
+
66
+ All operations accept a second options argument (the first argument for `models.list`) with `signal` and `timeoutMs`. The default deadline is 120 seconds and includes reading the response body or stream. Network failures and aborts propagate from fetch. Automatic retries are disabled because model requests can incur charges.
67
+
68
+ ```ts
69
+ import { QevrionAPIError } from '@qevrion/sdk';
70
+
71
+ try {
72
+ await client.chat.completions.create({ model, messages: [] });
73
+ } catch (error) {
74
+ if (error instanceof QevrionAPIError) {
75
+ console.error(error.status, error.type, error.code, error.requestId);
76
+ } else {
77
+ throw error;
78
+ }
79
+ }
80
+ ```
81
+
82
+ API errors include HTTP `status`, provider `type`/`code` when supplied, and the Qevrion request ID when supplied. An error delivered inside an established SSE stream has HTTP status 200; use its type/code to diagnose it. JSON responses have TypeScript declarations; they are not runtime schema validated.
83
+
84
+ ## Genkit
85
+
86
+ Install the optional peer only if you use the separate Genkit entry point:
87
+
88
+ ```sh
89
+ npm install genkit
90
+ ```
91
+
92
+ ```ts
93
+ import { genkit } from 'genkit';
94
+ import { qevrion, qevrionModel } from '@qevrion/sdk/genkit';
95
+
96
+ const ai = genkit({
97
+ plugins: [qevrion({ apiKey: process.env.QEVRION_API_KEY! })],
98
+ });
99
+
100
+ const response = await ai.generate({
101
+ // Replace with an enabled catalog ID.
102
+ model: qevrionModel('openai/gpt-4o-mini'),
103
+ prompt: 'Hello!',
104
+ config: { maxOutputTokens: 256, temperature: 0 },
105
+ });
106
+ console.log(response.text);
107
+ ```
108
+
109
+ The adapter uses the SDK transport, including its cancellation, deadlines, errors, and disabled retries. It accepts `baseURL`, `timeoutMs`, a custom `fetch`, and a plugin `name` (default `qevrion`). If you change the name, pass the same name as the second argument to `qevrionModel` or `qevrionEmbedder`. For chat it supports `generate` and `generateStream`, advertises text chat capabilities, and maps `maxOutputTokens`, `temperature`, and `topP` to the API parameters. Unsupported configuration is rejected rather than silently ignored.
110
+
111
+ For text embeddings, use the same plugin and an enabled embedding model:
112
+
113
+ ```ts
114
+ import { qevrionEmbedder } from '@qevrion/sdk/genkit';
115
+
116
+ const embeddings = await ai.embed({
117
+ embedder: qevrionEmbedder('openai/text-embedding-3-small'),
118
+ content: 'A document about Lagos.',
119
+ // Optional; supported dimensions and task hints depend on the selected model.
120
+ options: { inputType: 'search_document' },
121
+ });
122
+ console.log(embeddings[0]?.embedding);
123
+ ```
124
+
125
+ `ai.embedMany()` accepts batches of up to 100 text documents. Embedder options are `dimensions` and `inputType` (mapped to `input_type`). The Genkit adapter returns float vectors in input order.
126
+
127
+ ## Build and release
128
+
129
+ From `packages/sdk`:
130
+
131
+ ```sh
132
+ npm ci
133
+ npm test
134
+ npm pack --dry-run
135
+ npm pack
136
+ ```
137
+
138
+ Install the generated tarball in another project to try it before publication. The package name is proposed; scope ownership and name availability must be checked by the publisher. Set the intended license before release (currently `UNLICENSED`), then publish with `npm publish --access public` using an account authorized for the `@qevrion` scope. This repository does not publish automatically. Only compiled files and this README are included in the package.
@@ -0,0 +1,37 @@
1
+ import { z } from 'genkit';
2
+ import { type QevrionOptions } from './index.js';
3
+ export interface QevrionGenkitOptions extends QevrionOptions {
4
+ name?: string;
5
+ }
6
+ export declare function qevrion(options: QevrionGenkitOptions): import("genkit/plugin").GenkitPluginV2Instance;
7
+ /** Reference an enabled embedding model for ai.embed() or ai.embedMany(). */
8
+ export declare function qevrionEmbedder(modelId: string, pluginName?: string): import("genkit").EmbedderReference<z.ZodObject<{
9
+ version: z.ZodOptional<z.ZodUndefined>;
10
+ dimensions: z.ZodOptional<z.ZodNumber>;
11
+ inputType: z.ZodOptional<z.ZodString>;
12
+ }, "strict", z.ZodTypeAny, {
13
+ version?: undefined;
14
+ dimensions?: number | undefined;
15
+ inputType?: string | undefined;
16
+ }, {
17
+ version?: undefined;
18
+ dimensions?: number | undefined;
19
+ inputType?: string | undefined;
20
+ }>>;
21
+ /** Pass a catalog model ID, including its provider, e.g. openai/gpt-4o-mini. */
22
+ export declare function qevrionModel(modelId: string, pluginName?: string): import("genkit").ModelReference<z.ZodObject<{
23
+ version: z.ZodOptional<z.ZodUndefined>;
24
+ maxOutputTokens: z.ZodOptional<z.ZodNumber>;
25
+ temperature: z.ZodOptional<z.ZodNumber>;
26
+ topP: z.ZodOptional<z.ZodNumber>;
27
+ }, "strict", z.ZodTypeAny, {
28
+ version?: undefined;
29
+ maxOutputTokens?: number | undefined;
30
+ temperature?: number | undefined;
31
+ topP?: number | undefined;
32
+ }, {
33
+ version?: undefined;
34
+ maxOutputTokens?: number | undefined;
35
+ temperature?: number | undefined;
36
+ topP?: number | undefined;
37
+ }>>;
package/dist/genkit.js ADDED
@@ -0,0 +1,146 @@
1
+ import { modelRef, z } from 'genkit';
2
+ import { embedderRef } from 'genkit/embedder';
3
+ import { embedder, genkitPluginV2, model } from 'genkit/plugin';
4
+ import { Qevrion } from './index.js';
5
+ const configSchema = z
6
+ .object({
7
+ // Genkit injects this field even when no model version was requested.
8
+ version: z.undefined().optional(),
9
+ maxOutputTokens: z.number().int().min(1).max(4096).optional(),
10
+ temperature: z.number().min(0).max(2).optional(),
11
+ topP: z.number().min(0).max(1).optional(),
12
+ })
13
+ .strict();
14
+ const supports = {
15
+ multiturn: true,
16
+ tools: false,
17
+ media: false,
18
+ systemRole: true,
19
+ output: ['text'],
20
+ };
21
+ const embeddingConfigSchema = z
22
+ .object({
23
+ version: z.undefined().optional(),
24
+ dimensions: z.number().int().min(1).max(65536).optional(),
25
+ inputType: z.string().min(1).max(100).optional(),
26
+ })
27
+ .strict();
28
+ function usage(value) {
29
+ return value
30
+ ? {
31
+ inputTokens: value.prompt_tokens,
32
+ outputTokens: value.completion_tokens,
33
+ totalTokens: value.total_tokens,
34
+ }
35
+ : undefined;
36
+ }
37
+ function finishReason(value) {
38
+ if (value === 'stop' || value === 'length')
39
+ return value;
40
+ return value === 'content_filter' ? 'blocked' : 'other';
41
+ }
42
+ export function qevrion(options) {
43
+ const client = new Qevrion(options);
44
+ const name = options.name ?? 'qevrion';
45
+ return genkitPluginV2({
46
+ name,
47
+ async resolve(actionType, actionName) {
48
+ const id = actionName.startsWith(`${name}/`) ? actionName.slice(name.length + 1) : actionName;
49
+ if (actionType === 'embedder') {
50
+ return embedder({
51
+ name: `${name}/${id}`,
52
+ configSchema: embeddingConfigSchema,
53
+ info: { supports: { input: ['text'] } },
54
+ }, async (request, context) => {
55
+ const config = embeddingConfigSchema.parse(request.options ?? {});
56
+ const input = request.input.map((document) => {
57
+ if (document.content.some((part) => typeof part.text !== 'string'))
58
+ throw new TypeError('Qevrion embeddings support text documents only.');
59
+ return document.text;
60
+ });
61
+ const result = await client.embeddings.create({ model: id, input, dimensions: config.dimensions, input_type: config.inputType }, { signal: context.abortSignal });
62
+ return {
63
+ embeddings: [...result.data]
64
+ .sort((a, b) => a.index - b.index)
65
+ .map((item) => ({ embedding: item.embedding })),
66
+ };
67
+ });
68
+ }
69
+ if (actionType !== 'model')
70
+ return undefined;
71
+ return model({ name: `${name}/${id}`, supports, configSchema }, async (request, context) => {
72
+ const config = configSchema.parse(request.config ?? {});
73
+ if (request.tools?.length || (request.output?.format && request.output.format !== 'text')) {
74
+ throw new TypeError('Qevrion supports text chat only.');
75
+ }
76
+ const params = {
77
+ model: id,
78
+ messages: request.messages.map((message) => {
79
+ if (!['user', 'model', 'system'].includes(message.role) ||
80
+ message.content.some((part) => typeof part.text !== 'string')) {
81
+ throw new TypeError('Qevrion supports text system, user, and assistant messages only.');
82
+ }
83
+ return {
84
+ role: message.role === 'model' ? 'assistant' : message.role,
85
+ content: message.content.map((part) => part.text).join(''),
86
+ };
87
+ }),
88
+ max_tokens: config.maxOutputTokens,
89
+ temperature: config.temperature,
90
+ top_p: config.topP,
91
+ };
92
+ const requestOptions = { signal: context.abortSignal };
93
+ if (!context.streamingRequested) {
94
+ const result = await client.chat.completions.create(params, requestOptions);
95
+ const choice = result.choices[0];
96
+ if (!choice)
97
+ throw new Error('Qevrion returned no completion choices.');
98
+ return {
99
+ message: { role: 'model', content: [{ text: choice.message.content ?? '' }] },
100
+ finishReason: finishReason(choice.finish_reason),
101
+ usage: usage(result.usage),
102
+ raw: result,
103
+ };
104
+ }
105
+ let text = '';
106
+ let reason = null;
107
+ let finalUsage;
108
+ for await (const chunk of client.chat.completions.stream(params, requestOptions)) {
109
+ if (chunk.usage)
110
+ finalUsage = chunk.usage;
111
+ const choice = chunk.choices.find((item) => item.index === 0);
112
+ if (!choice)
113
+ continue;
114
+ if (choice.finish_reason)
115
+ reason = choice.finish_reason;
116
+ if (choice.delta.content) {
117
+ text += choice.delta.content;
118
+ await context.sendChunk({ index: 0, content: [{ text: choice.delta.content }] });
119
+ }
120
+ }
121
+ return {
122
+ message: { role: 'model', content: [{ text }] },
123
+ finishReason: finishReason(reason),
124
+ usage: usage(finalUsage),
125
+ };
126
+ });
127
+ },
128
+ });
129
+ }
130
+ /** Reference an enabled embedding model for ai.embed() or ai.embedMany(). */
131
+ export function qevrionEmbedder(modelId, pluginName = 'qevrion') {
132
+ return embedderRef({
133
+ name: `${pluginName}/${modelId}`,
134
+ configSchema: embeddingConfigSchema,
135
+ info: { supports: { input: ['text'] } },
136
+ });
137
+ }
138
+ /** Pass a catalog model ID, including its provider, e.g. openai/gpt-4o-mini. */
139
+ export function qevrionModel(modelId, pluginName = 'qevrion') {
140
+ return modelRef({
141
+ name: `${pluginName}/${modelId}`,
142
+ configSchema,
143
+ info: { label: modelId, supports },
144
+ });
145
+ }
146
+ //# sourceMappingURL=genkit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"genkit.js","sourceRoot":"","sources":["../src/genkit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,OAAO,EAAoD,MAAM,YAAY,CAAC;AAMvF,MAAM,YAAY,GAAG,CAAC;KACnB,MAAM,CAAC;IACN,sEAAsE;IACtE,OAAO,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE;IACjC,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE;IAC7D,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAChD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;CAC1C,CAAC;KACD,MAAM,EAAE,CAAC;AAEZ,MAAM,QAAQ,GAAG;IACf,SAAS,EAAE,IAAI;IACf,KAAK,EAAE,KAAK;IACZ,KAAK,EAAE,KAAK;IACZ,UAAU,EAAE,IAAI;IAChB,MAAM,EAAE,CAAC,MAAe,CAAC;CAC1B,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC;KAC5B,MAAM,CAAC;IACN,OAAO,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE;IACjC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE;IACzD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;CACjD,CAAC;KACD,MAAM,EAAE,CAAC;AAEZ,SAAS,KAAK,CAAC,KAAoB;IACjC,OAAO,KAAK;QACV,CAAC,CAAC;YACE,WAAW,EAAE,KAAK,CAAC,aAAa;YAChC,YAAY,EAAE,KAAK,CAAC,iBAAiB;YACrC,WAAW,EAAE,KAAK,CAAC,YAAY;SAChC;QACH,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED,SAAS,YAAY,CAAC,KAAoB;IACxC,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACzD,OAAO,KAAK,KAAK,gBAAgB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,OAA6B;IACnD,MAAM,MAAM,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,SAAS,CAAC;IACvC,OAAO,cAAc,CAAC;QACpB,IAAI;QACJ,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,UAAU;YAClC,MAAM,EAAE,GAAG,UAAU,CAAC,UAAU,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;YAC9F,IAAI,UAAU,KAAK,UAAU,EAAE,CAAC;gBAC9B,OAAO,QAAQ,CACb;oBACE,IAAI,EAAE,GAAG,IAAI,IAAI,EAAE,EAAE;oBACrB,YAAY,EAAE,qBAAqB;oBACnC,IAAI,EAAE,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE;iBACxC,EACD,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;oBACzB,MAAM,MAAM,GAAG,qBAAqB,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;oBAClE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE;wBAC3C,IAAI,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC;4BAChE,MAAM,IAAI,SAAS,CAAC,iDAAiD,CAAC,CAAC;wBACzE,OAAO,QAAQ,CAAC,IAAI,CAAC;oBACvB,CAAC,CAAC,CAAC;oBACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,MAAM,CAC3C,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,UAAU,EAAE,MAAM,CAAC,SAAS,EAAE,EACjF,EAAE,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,CAChC,CAAC;oBACF,OAAO;wBACL,UAAU,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC;6BACzB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;6BACjC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;qBAClD,CAAC;gBACJ,CAAC,CACF,CAAC;YACJ,CAAC;YACD,IAAI,UAAU,KAAK,OAAO;gBAAE,OAAO,SAAS,CAAC;YAC7C,OAAO,KAAK,CAAC,EAAE,IAAI,EAAE,GAAG,IAAI,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;gBACzF,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;gBACxD,IAAI,OAAO,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,EAAE,CAAC;oBAC1F,MAAM,IAAI,SAAS,CAAC,kCAAkC,CAAC,CAAC;gBAC1D,CAAC;gBACD,MAAM,MAAM,GAAe;oBACzB,KAAK,EAAE,EAAE;oBACT,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;wBACzC,IACE,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC;4BACnD,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,EAC7D,CAAC;4BACD,MAAM,IAAI,SAAS,CACjB,kEAAkE,CACnE,CAAC;wBACJ,CAAC;wBACD,OAAO;4BACL,IAAI,EAAE,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAE,OAAO,CAAC,IAA0B;4BAClF,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;yBAC3D,CAAC;oBACJ,CAAC,CAAC;oBACF,UAAU,EAAE,MAAM,CAAC,eAAe;oBAClC,WAAW,EAAE,MAAM,CAAC,WAAW;oBAC/B,KAAK,EAAE,MAAM,CAAC,IAAI;iBACnB,CAAC;gBACF,MAAM,cAAc,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;gBACvD,IAAI,CAAC,OAAO,CAAC,kBAAkB,EAAE,CAAC;oBAChC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;oBAC5E,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;oBACjC,IAAI,CAAC,MAAM;wBAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;oBACxE,OAAO;wBACL,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC,EAAE;wBAC7E,YAAY,EAAE,YAAY,CAAC,MAAM,CAAC,aAAa,CAAC;wBAChD,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;wBAC1B,GAAG,EAAE,MAAM;qBACZ,CAAC;gBACJ,CAAC;gBACD,IAAI,IAAI,GAAG,EAAE,CAAC;gBACd,IAAI,MAAM,GAAkB,IAAI,CAAC;gBACjC,IAAI,UAAoC,CAAC;gBACzC,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,CAAC;oBACjF,IAAI,KAAK,CAAC,KAAK;wBAAE,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC;oBAC1C,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC;oBAC9D,IAAI,CAAC,MAAM;wBAAE,SAAS;oBACtB,IAAI,MAAM,CAAC,aAAa;wBAAE,MAAM,GAAG,MAAM,CAAC,aAAa,CAAC;oBACxD,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;wBACzB,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;wBAC7B,MAAM,OAAO,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;oBACnF,CAAC;gBACH,CAAC;gBACD,OAAO;oBACL,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE;oBAC/C,YAAY,EAAE,YAAY,CAAC,MAAM,CAAC;oBAClC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC;iBACzB,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,UAAU,GAAG,SAAS;IACrE,OAAO,WAAW,CAAC;QACjB,IAAI,EAAE,GAAG,UAAU,IAAI,OAAO,EAAE;QAChC,YAAY,EAAE,qBAAqB;QACnC,IAAI,EAAE,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE;KACxC,CAAC,CAAC;AACL,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,UAAU,GAAG,SAAS;IAClE,OAAO,QAAQ,CAAC;QACd,IAAI,EAAE,GAAG,UAAU,IAAI,OAAO,EAAE;QAChC,YAAY;QACZ,IAAI,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE;KACnC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { modelRef, z } from 'genkit';\nimport { embedderRef } from 'genkit/embedder';\nimport { embedder, genkitPluginV2, model } from 'genkit/plugin';\nimport { Qevrion, type ChatParams, type QevrionOptions, type Usage } from './index.js';\n\nexport interface QevrionGenkitOptions extends QevrionOptions {\n name?: string;\n}\n\nconst configSchema = z\n .object({\n // Genkit injects this field even when no model version was requested.\n version: z.undefined().optional(),\n maxOutputTokens: z.number().int().min(1).max(4096).optional(),\n temperature: z.number().min(0).max(2).optional(),\n topP: z.number().min(0).max(1).optional(),\n })\n .strict();\n\nconst supports = {\n multiturn: true,\n tools: false,\n media: false,\n systemRole: true,\n output: ['text' as const],\n};\n\nconst embeddingConfigSchema = z\n .object({\n version: z.undefined().optional(),\n dimensions: z.number().int().min(1).max(65536).optional(),\n inputType: z.string().min(1).max(100).optional(),\n })\n .strict();\n\nfunction usage(value?: Usage | null) {\n return value\n ? {\n inputTokens: value.prompt_tokens,\n outputTokens: value.completion_tokens,\n totalTokens: value.total_tokens,\n }\n : undefined;\n}\n\nfunction finishReason(value: string | null): 'stop' | 'length' | 'blocked' | 'other' {\n if (value === 'stop' || value === 'length') return value;\n return value === 'content_filter' ? 'blocked' : 'other';\n}\n\nexport function qevrion(options: QevrionGenkitOptions) {\n const client = new Qevrion(options);\n const name = options.name ?? 'qevrion';\n return genkitPluginV2({\n name,\n async resolve(actionType, actionName) {\n const id = actionName.startsWith(`${name}/`) ? actionName.slice(name.length + 1) : actionName;\n if (actionType === 'embedder') {\n return embedder(\n {\n name: `${name}/${id}`,\n configSchema: embeddingConfigSchema,\n info: { supports: { input: ['text'] } },\n },\n async (request, context) => {\n const config = embeddingConfigSchema.parse(request.options ?? {});\n const input = request.input.map((document) => {\n if (document.content.some((part) => typeof part.text !== 'string'))\n throw new TypeError('Qevrion embeddings support text documents only.');\n return document.text;\n });\n const result = await client.embeddings.create(\n { model: id, input, dimensions: config.dimensions, input_type: config.inputType },\n { signal: context.abortSignal },\n );\n return {\n embeddings: [...result.data]\n .sort((a, b) => a.index - b.index)\n .map((item) => ({ embedding: item.embedding })),\n };\n },\n );\n }\n if (actionType !== 'model') return undefined;\n return model({ name: `${name}/${id}`, supports, configSchema }, async (request, context) => {\n const config = configSchema.parse(request.config ?? {});\n if (request.tools?.length || (request.output?.format && request.output.format !== 'text')) {\n throw new TypeError('Qevrion supports text chat only.');\n }\n const params: ChatParams = {\n model: id,\n messages: request.messages.map((message) => {\n if (\n !['user', 'model', 'system'].includes(message.role) ||\n message.content.some((part) => typeof part.text !== 'string')\n ) {\n throw new TypeError(\n 'Qevrion supports text system, user, and assistant messages only.',\n );\n }\n return {\n role: message.role === 'model' ? 'assistant' : (message.role as 'system' | 'user'),\n content: message.content.map((part) => part.text).join(''),\n };\n }),\n max_tokens: config.maxOutputTokens,\n temperature: config.temperature,\n top_p: config.topP,\n };\n const requestOptions = { signal: context.abortSignal };\n if (!context.streamingRequested) {\n const result = await client.chat.completions.create(params, requestOptions);\n const choice = result.choices[0];\n if (!choice) throw new Error('Qevrion returned no completion choices.');\n return {\n message: { role: 'model', content: [{ text: choice.message.content ?? '' }] },\n finishReason: finishReason(choice.finish_reason),\n usage: usage(result.usage),\n raw: result,\n };\n }\n let text = '';\n let reason: string | null = null;\n let finalUsage: Usage | null | undefined;\n for await (const chunk of client.chat.completions.stream(params, requestOptions)) {\n if (chunk.usage) finalUsage = chunk.usage;\n const choice = chunk.choices.find((item) => item.index === 0);\n if (!choice) continue;\n if (choice.finish_reason) reason = choice.finish_reason;\n if (choice.delta.content) {\n text += choice.delta.content;\n await context.sendChunk({ index: 0, content: [{ text: choice.delta.content }] });\n }\n }\n return {\n message: { role: 'model', content: [{ text }] },\n finishReason: finishReason(reason),\n usage: usage(finalUsage),\n };\n });\n },\n });\n}\n\n/** Reference an enabled embedding model for ai.embed() or ai.embedMany(). */\nexport function qevrionEmbedder(modelId: string, pluginName = 'qevrion') {\n return embedderRef({\n name: `${pluginName}/${modelId}`,\n configSchema: embeddingConfigSchema,\n info: { supports: { input: ['text'] } },\n });\n}\n\n/** Pass a catalog model ID, including its provider, e.g. openai/gpt-4o-mini. */\nexport function qevrionModel(modelId: string, pluginName = 'qevrion') {\n return modelRef({\n name: `${pluginName}/${modelId}`,\n configSchema,\n info: { label: modelId, supports },\n });\n}\n"]}
@@ -0,0 +1,36 @@
1
+ import type { ChatChunk, ChatCompletion, ChatParams, EmbeddingParams, EmbeddingResponse, ModelList, ModelListOptions, QevrionOptions, RequestOptions } from './types.js';
2
+ export type * from './types.js';
3
+ export declare const DEFAULT_BASE_URL = "https://useqevrion.com/v1";
4
+ export declare class QevrionAPIError extends Error {
5
+ readonly status: number;
6
+ readonly type?: string;
7
+ readonly code?: string;
8
+ readonly requestId?: string;
9
+ constructor(message: string, status: number, details?: {
10
+ type?: string;
11
+ code?: string;
12
+ requestId?: string;
13
+ });
14
+ }
15
+ export declare class QevrionProtocolError extends Error {
16
+ constructor(message: string, options?: ErrorOptions);
17
+ }
18
+ export declare function normalizeBaseURL(value?: string): string;
19
+ export declare function validateApiKey(apiKey: string): void;
20
+ /** Server-side ESM client. Requests are never automatically retried. */
21
+ export declare class Qevrion {
22
+ #private;
23
+ constructor(options: QevrionOptions);
24
+ readonly models: {
25
+ list: (options?: ModelListOptions) => Promise<ModelList>;
26
+ };
27
+ readonly embeddings: {
28
+ create: <Encoding extends "float" | "base64" = "float">(params: EmbeddingParams<Encoding>, options?: RequestOptions) => Promise<EmbeddingResponse<Encoding>>;
29
+ };
30
+ readonly chat: {
31
+ completions: {
32
+ create: (params: ChatParams, options?: RequestOptions) => Promise<ChatCompletion>;
33
+ stream: (params: ChatParams, options?: RequestOptions) => AsyncGenerator<ChatChunk>;
34
+ };
35
+ };
36
+ }
package/dist/index.js ADDED
@@ -0,0 +1,195 @@
1
+ export const DEFAULT_BASE_URL = 'https://useqevrion.com/v1';
2
+ export class QevrionAPIError extends Error {
3
+ status;
4
+ type;
5
+ code;
6
+ requestId;
7
+ constructor(message, status, details = {}) {
8
+ super(message);
9
+ this.name = 'QevrionAPIError';
10
+ this.status = status;
11
+ this.type = details.type;
12
+ this.code = details.code;
13
+ this.requestId = details.requestId;
14
+ }
15
+ }
16
+ export class QevrionProtocolError extends Error {
17
+ constructor(message, options) {
18
+ super(message, options);
19
+ this.name = 'QevrionProtocolError';
20
+ }
21
+ }
22
+ export function normalizeBaseURL(value = DEFAULT_BASE_URL) {
23
+ const url = new URL(value);
24
+ if (!['http:', 'https:'].includes(url.protocol) ||
25
+ url.username ||
26
+ url.password ||
27
+ url.search ||
28
+ url.hash) {
29
+ throw new TypeError('baseURL must be an HTTP(S) API root without credentials, query, or fragment.');
30
+ }
31
+ return url.href.replace(/\/+$/, '');
32
+ }
33
+ export function validateApiKey(apiKey) {
34
+ if (typeof apiKey !== 'string' || !/^qv_[a-zA-Z0-9_-]+$/.test(apiKey)) {
35
+ throw new TypeError('A Qevrion API key beginning with qv_ is required.');
36
+ }
37
+ }
38
+ function validateTimeout(timeout) {
39
+ if (!Number.isInteger(timeout) || timeout < 1 || timeout > 2_147_483_647) {
40
+ throw new TypeError('timeoutMs must be a positive integer no greater than 2147483647.');
41
+ }
42
+ }
43
+ function apiError(body, response) {
44
+ const error = body
45
+ ?.error;
46
+ return new QevrionAPIError(typeof error?.message === 'string'
47
+ ? error.message
48
+ : `Qevrion request failed (${response.status}).`, response.status, {
49
+ type: typeof error?.type === 'string' ? error.type : undefined,
50
+ code: typeof error?.code === 'string' ? error.code : undefined,
51
+ requestId: response.headers.get('x-qevrionai-request-id') ?? undefined,
52
+ });
53
+ }
54
+ /** Server-side ESM client. Requests are never automatically retried. */
55
+ export class Qevrion {
56
+ #apiKey;
57
+ #baseURL;
58
+ #timeoutMs;
59
+ #fetch;
60
+ constructor(options) {
61
+ validateApiKey(options.apiKey);
62
+ this.#apiKey = options.apiKey;
63
+ this.#baseURL = normalizeBaseURL(options.baseURL);
64
+ this.#timeoutMs = options.timeoutMs ?? 120_000;
65
+ validateTimeout(this.#timeoutMs);
66
+ this.#fetch = options.fetch ?? globalThis.fetch.bind(globalThis);
67
+ }
68
+ models = {
69
+ list: (options) => this.#json(options?.type ? `/models?type=${encodeURIComponent(options.type)}` : '/models', undefined, options),
70
+ };
71
+ embeddings = {
72
+ create: (params, options) => this.#json('/embeddings', params, options),
73
+ };
74
+ chat = {
75
+ completions: {
76
+ create: (params, options) => this.#json('/chat/completions', { ...params, stream: false }, options),
77
+ stream: (params, options) => this.#stream(params, options),
78
+ },
79
+ };
80
+ async #request(path, body, options = {}) {
81
+ const timeout = options.timeoutMs ?? this.#timeoutMs;
82
+ validateTimeout(timeout);
83
+ const controller = new AbortController();
84
+ const timer = setTimeout(() => controller.abort(new DOMException('Qevrion request timed out.', 'TimeoutError')), timeout);
85
+ const signal = options.signal
86
+ ? AbortSignal.any([options.signal, controller.signal])
87
+ : controller.signal;
88
+ try {
89
+ const response = await this.#fetch(`${this.#baseURL}${path}`, {
90
+ method: body === undefined ? 'GET' : 'POST',
91
+ headers: {
92
+ Authorization: `Bearer ${this.#apiKey}`,
93
+ ...(body === undefined ? {} : { 'Content-Type': 'application/json' }),
94
+ },
95
+ body: body === undefined ? undefined : JSON.stringify(body),
96
+ signal,
97
+ redirect: 'error',
98
+ });
99
+ if (!response.ok) {
100
+ const text = await response.text();
101
+ let parsed;
102
+ try {
103
+ parsed = JSON.parse(text);
104
+ }
105
+ catch {
106
+ /* Proxy errors can be HTML. */
107
+ }
108
+ throw apiError(parsed, response);
109
+ }
110
+ return {
111
+ response,
112
+ dispose: () => {
113
+ clearTimeout(timer);
114
+ controller.abort();
115
+ },
116
+ };
117
+ }
118
+ catch (error) {
119
+ clearTimeout(timer);
120
+ controller.abort();
121
+ throw error;
122
+ }
123
+ }
124
+ async #json(path, body, options) {
125
+ const { response, dispose } = await this.#request(path, body, options);
126
+ try {
127
+ const text = await response.text();
128
+ try {
129
+ return JSON.parse(text);
130
+ }
131
+ catch (cause) {
132
+ throw new QevrionProtocolError('Qevrion returned invalid JSON.', { cause });
133
+ }
134
+ }
135
+ finally {
136
+ dispose();
137
+ }
138
+ }
139
+ async *#stream(params, options) {
140
+ const { response, dispose } = await this.#request('/chat/completions', { ...params, stream: true }, options);
141
+ let reader;
142
+ try {
143
+ if (!response.headers.get('content-type')?.toLowerCase().startsWith('text/event-stream') ||
144
+ !response.body) {
145
+ throw new QevrionProtocolError('Expected a text/event-stream response.');
146
+ }
147
+ reader = response.body.getReader();
148
+ const decoder = new TextDecoder();
149
+ let buffer = '';
150
+ while (true) {
151
+ const { value, done } = await reader.read();
152
+ buffer += decoder.decode(value, { stream: !done });
153
+ let boundary;
154
+ while ((boundary = /\r?\n\r?\n/.exec(buffer)) !== null || (done && buffer.length > 0)) {
155
+ const frame = boundary ? buffer.slice(0, boundary.index) : buffer;
156
+ buffer = boundary ? buffer.slice(boundary.index + boundary[0].length) : '';
157
+ const data = frame
158
+ .split(/\r?\n/)
159
+ .filter((line) => line.startsWith('data:'))
160
+ .map((line) => line.slice(5).replace(/^ /, ''))
161
+ .join('\n');
162
+ if (!data)
163
+ continue;
164
+ if (data.trim() === '[DONE]')
165
+ return;
166
+ let chunk;
167
+ try {
168
+ chunk = JSON.parse(data);
169
+ }
170
+ catch (cause) {
171
+ throw new QevrionProtocolError('Invalid JSON in Qevrion stream.', { cause });
172
+ }
173
+ if (chunk && typeof chunk === 'object' && 'error' in chunk)
174
+ throw apiError(chunk, response);
175
+ yield chunk;
176
+ }
177
+ if (done)
178
+ throw new QevrionProtocolError('Qevrion stream ended before [DONE].');
179
+ }
180
+ }
181
+ finally {
182
+ dispose();
183
+ if (reader) {
184
+ try {
185
+ await reader.cancel();
186
+ }
187
+ catch {
188
+ /* An aborted reader may already be closed. */
189
+ }
190
+ reader.releaseLock();
191
+ }
192
+ }
193
+ }
194
+ }
195
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,MAAM,CAAC,MAAM,gBAAgB,GAAG,2BAA2B,CAAC;AAE5D,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAC/B,MAAM,CAAS;IACf,IAAI,CAAU;IACd,IAAI,CAAU;IACd,SAAS,CAAU;IAE5B,YACE,OAAe,EACf,MAAc,EACd,UAII,EAAE;QAEN,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QACzB,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IACrC,CAAC;CACF;AAED,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,OAAe,EAAE,OAAsB;QACjD,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAED,MAAM,UAAU,gBAAgB,CAAC,QAAgB,gBAAgB;IAC/D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IAC3B,IACE,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC3C,GAAG,CAAC,QAAQ;QACZ,GAAG,CAAC,QAAQ;QACZ,GAAG,CAAC,MAAM;QACV,GAAG,CAAC,IAAI,EACR,CAAC;QACD,MAAM,IAAI,SAAS,CACjB,8EAA8E,CAC/E,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,SAAS,CAAC,mDAAmD,CAAC,CAAC;IAC3E,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,OAAe;IACtC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,GAAG,aAAa,EAAE,CAAC;QACzE,MAAM,IAAI,SAAS,CAAC,kEAAkE,CAAC,CAAC;IAC1F,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,IAAa,EAAE,QAAkB;IACjD,MAAM,KAAK,GAAI,IAAiF;QAC9F,EAAE,KAAK,CAAC;IACV,OAAO,IAAI,eAAe,CACxB,OAAO,KAAK,EAAE,OAAO,KAAK,QAAQ;QAChC,CAAC,CAAC,KAAK,CAAC,OAAO;QACf,CAAC,CAAC,2BAA2B,QAAQ,CAAC,MAAM,IAAI,EAClD,QAAQ,CAAC,MAAM,EACf;QACE,IAAI,EAAE,OAAO,KAAK,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;QAC9D,IAAI,EAAE,OAAO,KAAK,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;QAC9D,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,IAAI,SAAS;KACvE,CACF,CAAC;AACJ,CAAC;AAED,wEAAwE;AACxE,MAAM,OAAO,OAAO;IACT,OAAO,CAAS;IAChB,QAAQ,CAAS;IACjB,UAAU,CAAS;IACnB,MAAM,CAA0B;IAEzC,YAAY,OAAuB;QACjC,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;QAC9B,IAAI,CAAC,QAAQ,GAAG,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAClD,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC;QAC/C,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACjC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACnE,CAAC;IAEQ,MAAM,GAAG;QAChB,IAAI,EAAE,CAAC,OAA0B,EAAsB,EAAE,CACvD,IAAI,CAAC,KAAK,CACR,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,gBAAgB,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,EAC9E,SAAS,EACT,OAAO,CACR;KACJ,CAAC;IAEO,UAAU,GAAG;QACpB,MAAM,EAAE,CACN,MAAiC,EACjC,OAAwB,EACc,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC;KACtF,CAAC;IAEO,IAAI,GAAG;QACd,WAAW,EAAE;YACX,MAAM,EAAE,CAAC,MAAkB,EAAE,OAAwB,EAA2B,EAAE,CAChF,IAAI,CAAC,KAAK,CAAC,mBAAmB,EAAE,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,OAAO,CAAC;YACxE,MAAM,EAAE,CAAC,MAAkB,EAAE,OAAwB,EAA6B,EAAE,CAClF,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC;SAChC;KACF,CAAC;IAEF,KAAK,CAAC,QAAQ,CAAC,IAAY,EAAE,IAAa,EAAE,UAA0B,EAAE;QACtE,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC,UAAU,CAAC;QACrD,eAAe,CAAC,OAAO,CAAC,CAAC;QACzB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,UAAU,CACtB,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,4BAA4B,EAAE,cAAc,CAAC,CAAC,EACtF,OAAO,CACR,CAAC;QACF,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM;YAC3B,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;YACtD,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC;QACtB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,GAAG,IAAI,EAAE,EAAE;gBAC5D,MAAM,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM;gBAC3C,OAAO,EAAE;oBACP,aAAa,EAAE,UAAU,IAAI,CAAC,OAAO,EAAE;oBACvC,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC;iBACtE;gBACD,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;gBAC3D,MAAM;gBACN,QAAQ,EAAE,OAAO;aAClB,CAAC,CAAC;YACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACnC,IAAI,MAAe,CAAC;gBACpB,IAAI,CAAC;oBACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC5B,CAAC;gBAAC,MAAM,CAAC;oBACP,+BAA+B;gBACjC,CAAC;gBACD,MAAM,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YACnC,CAAC;YACD,OAAO;gBACL,QAAQ;gBACR,OAAO,EAAE,GAAG,EAAE;oBACZ,YAAY,CAAC,KAAK,CAAC,CAAC;oBACpB,UAAU,CAAC,KAAK,EAAE,CAAC;gBACrB,CAAC;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,UAAU,CAAC,KAAK,EAAE,CAAC;YACnB,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK,CAAI,IAAY,EAAE,IAAc,EAAE,OAAwB;QACnE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QACvE,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnC,IAAI,CAAC;gBACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAM,CAAC;YAC/B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,IAAI,oBAAoB,CAAC,gCAAgC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;YAC9E,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,CAAC,OAAO,CAAC,MAAkB,EAAE,OAAwB;QACzD,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ,CAC/C,mBAAmB,EACnB,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,EAC3B,OAAO,CACR,CAAC;QACF,IAAI,MAA2D,CAAC;QAChE,IAAI,CAAC;YACH,IACE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,WAAW,EAAE,CAAC,UAAU,CAAC,mBAAmB,CAAC;gBACpF,CAAC,QAAQ,CAAC,IAAI,EACd,CAAC;gBACD,MAAM,IAAI,oBAAoB,CAAC,wCAAwC,CAAC,CAAC;YAC3E,CAAC;YACD,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACnC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;YAClC,IAAI,MAAM,GAAG,EAAE,CAAC;YAChB,OAAO,IAAI,EAAE,CAAC;gBACZ,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;gBAC5C,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;gBACnD,IAAI,QAAgC,CAAC;gBACrC,OAAO,CAAC,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;oBACtF,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;oBAClE,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC3E,MAAM,IAAI,GAAG,KAAK;yBACf,KAAK,CAAC,OAAO,CAAC;yBACd,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;yBAC1C,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;yBAC9C,IAAI,CAAC,IAAI,CAAC,CAAC;oBACd,IAAI,CAAC,IAAI;wBAAE,SAAS;oBACpB,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,QAAQ;wBAAE,OAAO;oBACrC,IAAI,KAAgB,CAAC;oBACrB,IAAI,CAAC;wBACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAc,CAAC;oBACxC,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,MAAM,IAAI,oBAAoB,CAAC,iCAAiC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;oBAC/E,CAAC;oBACD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,IAAI,KAAK;wBACxD,MAAM,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;oBAClC,MAAM,KAAK,CAAC;gBACd,CAAC;gBACD,IAAI,IAAI;oBAAE,MAAM,IAAI,oBAAoB,CAAC,qCAAqC,CAAC,CAAC;YAClF,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,OAAO,EAAE,CAAC;YACV,IAAI,MAAM,EAAE,CAAC;gBACX,IAAI,CAAC;oBACH,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;gBACxB,CAAC;gBAAC,MAAM,CAAC;oBACP,8CAA8C;gBAChD,CAAC;gBACD,MAAM,CAAC,WAAW,EAAE,CAAC;YACvB,CAAC;QACH,CAAC;IACH,CAAC;CACF","sourcesContent":["import type {\n ChatChunk,\n ChatCompletion,\n ChatParams,\n EmbeddingParams,\n EmbeddingResponse,\n ModelList,\n ModelListOptions,\n QevrionOptions,\n RequestOptions,\n} from './types.js';\nexport type * from './types.js';\n\nexport const DEFAULT_BASE_URL = 'https://useqevrion.com/v1';\n\nexport class QevrionAPIError extends Error {\n readonly status: number;\n readonly type?: string;\n readonly code?: string;\n readonly requestId?: string;\n\n constructor(\n message: string,\n status: number,\n details: {\n type?: string;\n code?: string;\n requestId?: string;\n } = {},\n ) {\n super(message);\n this.name = 'QevrionAPIError';\n this.status = status;\n this.type = details.type;\n this.code = details.code;\n this.requestId = details.requestId;\n }\n}\n\nexport class QevrionProtocolError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = 'QevrionProtocolError';\n }\n}\n\nexport function normalizeBaseURL(value: string = DEFAULT_BASE_URL): string {\n const url = new URL(value);\n if (\n !['http:', 'https:'].includes(url.protocol) ||\n url.username ||\n url.password ||\n url.search ||\n url.hash\n ) {\n throw new TypeError(\n 'baseURL must be an HTTP(S) API root without credentials, query, or fragment.',\n );\n }\n return url.href.replace(/\\/+$/, '');\n}\n\nexport function validateApiKey(apiKey: string): void {\n if (typeof apiKey !== 'string' || !/^qv_[a-zA-Z0-9_-]+$/.test(apiKey)) {\n throw new TypeError('A Qevrion API key beginning with qv_ is required.');\n }\n}\n\nfunction validateTimeout(timeout: number): void {\n if (!Number.isInteger(timeout) || timeout < 1 || timeout > 2_147_483_647) {\n throw new TypeError('timeoutMs must be a positive integer no greater than 2147483647.');\n }\n}\n\nfunction apiError(body: unknown, response: Response): QevrionAPIError {\n const error = (body as { error?: { message?: unknown; type?: unknown; code?: unknown } } | null)\n ?.error;\n return new QevrionAPIError(\n typeof error?.message === 'string'\n ? error.message\n : `Qevrion request failed (${response.status}).`,\n response.status,\n {\n type: typeof error?.type === 'string' ? error.type : undefined,\n code: typeof error?.code === 'string' ? error.code : undefined,\n requestId: response.headers.get('x-qevrionai-request-id') ?? undefined,\n },\n );\n}\n\n/** Server-side ESM client. Requests are never automatically retried. */\nexport class Qevrion {\n readonly #apiKey: string;\n readonly #baseURL: string;\n readonly #timeoutMs: number;\n readonly #fetch: typeof globalThis.fetch;\n\n constructor(options: QevrionOptions) {\n validateApiKey(options.apiKey);\n this.#apiKey = options.apiKey;\n this.#baseURL = normalizeBaseURL(options.baseURL);\n this.#timeoutMs = options.timeoutMs ?? 120_000;\n validateTimeout(this.#timeoutMs);\n this.#fetch = options.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n readonly models = {\n list: (options?: ModelListOptions): Promise<ModelList> =>\n this.#json(\n options?.type ? `/models?type=${encodeURIComponent(options.type)}` : '/models',\n undefined,\n options,\n ),\n };\n\n readonly embeddings = {\n create: <Encoding extends 'float' | 'base64' = 'float'>(\n params: EmbeddingParams<Encoding>,\n options?: RequestOptions,\n ): Promise<EmbeddingResponse<Encoding>> => this.#json('/embeddings', params, options),\n };\n\n readonly chat = {\n completions: {\n create: (params: ChatParams, options?: RequestOptions): Promise<ChatCompletion> =>\n this.#json('/chat/completions', { ...params, stream: false }, options),\n stream: (params: ChatParams, options?: RequestOptions): AsyncGenerator<ChatChunk> =>\n this.#stream(params, options),\n },\n };\n\n async #request(path: string, body: unknown, options: RequestOptions = {}) {\n const timeout = options.timeoutMs ?? this.#timeoutMs;\n validateTimeout(timeout);\n const controller = new AbortController();\n const timer = setTimeout(\n () => controller.abort(new DOMException('Qevrion request timed out.', 'TimeoutError')),\n timeout,\n );\n const signal = options.signal\n ? AbortSignal.any([options.signal, controller.signal])\n : controller.signal;\n try {\n const response = await this.#fetch(`${this.#baseURL}${path}`, {\n method: body === undefined ? 'GET' : 'POST',\n headers: {\n Authorization: `Bearer ${this.#apiKey}`,\n ...(body === undefined ? {} : { 'Content-Type': 'application/json' }),\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n signal,\n redirect: 'error',\n });\n if (!response.ok) {\n const text = await response.text();\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n /* Proxy errors can be HTML. */\n }\n throw apiError(parsed, response);\n }\n return {\n response,\n dispose: () => {\n clearTimeout(timer);\n controller.abort();\n },\n };\n } catch (error) {\n clearTimeout(timer);\n controller.abort();\n throw error;\n }\n }\n\n async #json<T>(path: string, body?: unknown, options?: RequestOptions): Promise<T> {\n const { response, dispose } = await this.#request(path, body, options);\n try {\n const text = await response.text();\n try {\n return JSON.parse(text) as T;\n } catch (cause) {\n throw new QevrionProtocolError('Qevrion returned invalid JSON.', { cause });\n }\n } finally {\n dispose();\n }\n }\n\n async *#stream(params: ChatParams, options?: RequestOptions): AsyncGenerator<ChatChunk> {\n const { response, dispose } = await this.#request(\n '/chat/completions',\n { ...params, stream: true },\n options,\n );\n let reader: ReadableStreamDefaultReader<Uint8Array> | undefined;\n try {\n if (\n !response.headers.get('content-type')?.toLowerCase().startsWith('text/event-stream') ||\n !response.body\n ) {\n throw new QevrionProtocolError('Expected a text/event-stream response.');\n }\n reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n while (true) {\n const { value, done } = await reader.read();\n buffer += decoder.decode(value, { stream: !done });\n let boundary: RegExpExecArray | null;\n while ((boundary = /\\r?\\n\\r?\\n/.exec(buffer)) !== null || (done && buffer.length > 0)) {\n const frame = boundary ? buffer.slice(0, boundary.index) : buffer;\n buffer = boundary ? buffer.slice(boundary.index + boundary[0].length) : '';\n const data = frame\n .split(/\\r?\\n/)\n .filter((line) => line.startsWith('data:'))\n .map((line) => line.slice(5).replace(/^ /, ''))\n .join('\\n');\n if (!data) continue;\n if (data.trim() === '[DONE]') return;\n let chunk: ChatChunk;\n try {\n chunk = JSON.parse(data) as ChatChunk;\n } catch (cause) {\n throw new QevrionProtocolError('Invalid JSON in Qevrion stream.', { cause });\n }\n if (chunk && typeof chunk === 'object' && 'error' in chunk)\n throw apiError(chunk, response);\n yield chunk;\n }\n if (done) throw new QevrionProtocolError('Qevrion stream ended before [DONE].');\n }\n } finally {\n dispose();\n if (reader) {\n try {\n await reader.cancel();\n } catch {\n /* An aborted reader may already be closed. */\n }\n reader.releaseLock();\n }\n }\n }\n}\n"]}
@@ -0,0 +1,102 @@
1
+ export interface Message {
2
+ role: 'system' | 'user' | 'assistant';
3
+ content: string;
4
+ }
5
+ export interface ChatParams {
6
+ model: string;
7
+ messages: Message[];
8
+ /** Between 1 and 4096. Server default: 1024. */
9
+ max_tokens?: number;
10
+ temperature?: number;
11
+ top_p?: number;
12
+ }
13
+ export interface Usage {
14
+ prompt_tokens: number;
15
+ completion_tokens: number;
16
+ total_tokens: number;
17
+ /** Upstream cost, when present; not the final Qevrion account charge. */
18
+ cost?: number;
19
+ }
20
+ export interface ChatCompletion {
21
+ id: string;
22
+ object: 'chat.completion';
23
+ created: number;
24
+ model: string;
25
+ choices: Array<{
26
+ index: number;
27
+ message: {
28
+ role: 'assistant';
29
+ content: string | null;
30
+ };
31
+ finish_reason: string | null;
32
+ }>;
33
+ usage?: Usage;
34
+ }
35
+ export interface ChatChunk {
36
+ id: string;
37
+ object: 'chat.completion.chunk';
38
+ created: number;
39
+ model: string;
40
+ choices: Array<{
41
+ index: number;
42
+ delta: {
43
+ role?: 'assistant';
44
+ content?: string | null;
45
+ };
46
+ finish_reason: string | null;
47
+ }>;
48
+ usage?: Usage | null;
49
+ }
50
+ export interface Model {
51
+ id: string;
52
+ type: 'chat' | 'embedding';
53
+ object: 'model';
54
+ owned_by: string;
55
+ name: string;
56
+ context_length: number;
57
+ }
58
+ export interface ModelList {
59
+ object: 'list';
60
+ data: Model[];
61
+ }
62
+ export interface RequestOptions {
63
+ signal?: AbortSignal;
64
+ /** Deadline for the entire request, including stream consumption. */
65
+ timeoutMs?: number;
66
+ }
67
+ export interface ModelListOptions extends RequestOptions {
68
+ type?: 'chat' | 'embedding';
69
+ }
70
+ export interface EmbeddingParams<Encoding extends 'float' | 'base64' = 'float'> {
71
+ model: string;
72
+ /** A non-empty string or a batch of 1 to 100 non-empty strings. */
73
+ input: string | string[];
74
+ encoding_format?: Encoding;
75
+ /** Between 1 and 65536; support depends on the model. */
76
+ dimensions?: number;
77
+ /** Provider-specific task hint, e.g. search_query or search_document. */
78
+ input_type?: string;
79
+ }
80
+ export interface EmbeddingResponse<Encoding extends 'float' | 'base64' = 'float'> {
81
+ id?: string;
82
+ object: 'list';
83
+ model: string;
84
+ data: Array<{
85
+ object: 'embedding';
86
+ index: number;
87
+ embedding: Encoding extends 'base64' ? string : number[];
88
+ }>;
89
+ usage?: {
90
+ prompt_tokens: number;
91
+ total_tokens: number;
92
+ cost?: number;
93
+ };
94
+ }
95
+ export interface QevrionOptions {
96
+ apiKey: string;
97
+ /** API root including /v1. */
98
+ baseURL?: string;
99
+ /** Default: 120000 milliseconds. */
100
+ timeoutMs?: number;
101
+ fetch?: typeof globalThis.fetch;
102
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["export interface Message {\n role: 'system' | 'user' | 'assistant';\n content: string;\n}\n\nexport interface ChatParams {\n model: string;\n messages: Message[];\n /** Between 1 and 4096. Server default: 1024. */\n max_tokens?: number;\n temperature?: number;\n top_p?: number;\n}\n\nexport interface Usage {\n prompt_tokens: number;\n completion_tokens: number;\n total_tokens: number;\n /** Upstream cost, when present; not the final Qevrion account charge. */\n cost?: number;\n}\n\nexport interface ChatCompletion {\n id: string;\n object: 'chat.completion';\n created: number;\n model: string;\n choices: Array<{\n index: number;\n message: { role: 'assistant'; content: string | null };\n finish_reason: string | null;\n }>;\n usage?: Usage;\n}\n\nexport interface ChatChunk {\n id: string;\n object: 'chat.completion.chunk';\n created: number;\n model: string;\n choices: Array<{\n index: number;\n delta: { role?: 'assistant'; content?: string | null };\n finish_reason: string | null;\n }>;\n usage?: Usage | null;\n}\n\nexport interface Model {\n id: string;\n type: 'chat' | 'embedding';\n object: 'model';\n owned_by: string;\n name: string;\n context_length: number;\n}\n\nexport interface ModelList {\n object: 'list';\n data: Model[];\n}\n\nexport interface RequestOptions {\n signal?: AbortSignal;\n /** Deadline for the entire request, including stream consumption. */\n timeoutMs?: number;\n}\n\nexport interface ModelListOptions extends RequestOptions {\n type?: 'chat' | 'embedding';\n}\n\nexport interface EmbeddingParams<Encoding extends 'float' | 'base64' = 'float'> {\n model: string;\n /** A non-empty string or a batch of 1 to 100 non-empty strings. */\n input: string | string[];\n encoding_format?: Encoding;\n /** Between 1 and 65536; support depends on the model. */\n dimensions?: number;\n /** Provider-specific task hint, e.g. search_query or search_document. */\n input_type?: string;\n}\n\nexport interface EmbeddingResponse<Encoding extends 'float' | 'base64' = 'float'> {\n id?: string;\n object: 'list';\n model: string;\n data: Array<{\n object: 'embedding';\n index: number;\n embedding: Encoding extends 'base64' ? string : number[];\n }>;\n usage?: { prompt_tokens: number; total_tokens: number; cost?: number };\n}\n\nexport interface QevrionOptions {\n apiKey: string;\n /** API root including /v1. */\n baseURL?: string;\n /** Default: 120000 milliseconds. */\n timeoutMs?: number;\n fetch?: typeof globalThis.fetch;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,54 @@
1
1
  {
2
2
  "name": "@qevrion/sdk",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.0",
4
+ "description": "Small TypeScript client for QevrionAI with optional Genkit integration",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./genkit": {
14
+ "types": "./dist/genkit.d.ts",
15
+ "import": "./dist/genkit.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "README.md"
21
+ ],
22
+ "sideEffects": false,
23
+ "engines": {
24
+ "node": ">=20.3"
25
+ },
26
+ "license": "UNLICENSED",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git+https://github.com/ultimaterichy/useqevrion.git",
30
+ "directory": "packages/sdk"
31
+ },
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "scripts": {
36
+ "build": "tsc -p tsconfig.json",
37
+ "typecheck": "tsc -p tsconfig.json --noEmit",
38
+ "test": "npm run build && node --test test/*.test.mjs",
39
+ "prepack": "npm run build",
40
+ "prepublishOnly": "npm test"
41
+ },
42
+ "peerDependencies": {
43
+ "genkit": "^1.42.0"
44
+ },
45
+ "peerDependenciesMeta": {
46
+ "genkit": {
47
+ "optional": true
48
+ }
49
+ },
50
+ "devDependencies": {
51
+ "genkit": "^1.42.0",
52
+ "typescript": "^5.9.3"
53
+ }
54
+ }