@ai-sdk/quiverai 2.0.46 → 2.0.48
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/CHANGELOG.md +20 -0
- package/README.md +15 -1
- package/dist/index.d.ts +29 -2
- package/dist/index.js +263 -121
- package/dist/index.js.map +1 -1
- package/docs/180-quiverai.mdx +115 -2
- package/package.json +4 -3
- package/src/index.ts +3 -0
- package/src/quiverai-error.ts +28 -0
- package/src/quiverai-image-model.ts +1 -14
- package/src/quiverai-language-model-options.ts +11 -0
- package/src/quiverai-language-model-settings.ts +4 -0
- package/src/quiverai-language-model.ts +162 -0
- package/src/quiverai-provider.ts +69 -24
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import {
|
|
2
|
+
InvalidArgumentError,
|
|
3
|
+
type LanguageModelV4,
|
|
4
|
+
type LanguageModelV4CallOptions,
|
|
5
|
+
type LanguageModelV4StreamPart,
|
|
6
|
+
type SharedV4ProviderMetadata,
|
|
7
|
+
type SharedV4Warning,
|
|
8
|
+
} from '@ai-sdk/provider';
|
|
9
|
+
import {
|
|
10
|
+
createOpenResponses,
|
|
11
|
+
type OpenResponsesProviderSettings,
|
|
12
|
+
} from '@ai-sdk/open-responses';
|
|
13
|
+
import {
|
|
14
|
+
serializeModelOptions,
|
|
15
|
+
WORKFLOW_DESERIALIZE,
|
|
16
|
+
WORKFLOW_SERIALIZE,
|
|
17
|
+
} from '@ai-sdk/provider-utils';
|
|
18
|
+
import {
|
|
19
|
+
getQuiverAIResponseErrorMetadata,
|
|
20
|
+
quiveraiFailedResponseHandler,
|
|
21
|
+
} from './quiverai-error';
|
|
22
|
+
|
|
23
|
+
/** Applies QuiverAI's request policy while reusing the Open Responses transport. */
|
|
24
|
+
export class QuiverAILanguageModel implements LanguageModelV4 {
|
|
25
|
+
readonly specificationVersion = 'v4';
|
|
26
|
+
|
|
27
|
+
static [WORKFLOW_SERIALIZE](model: QuiverAILanguageModel) {
|
|
28
|
+
return serializeModelOptions({
|
|
29
|
+
modelId: model.modelId,
|
|
30
|
+
config: model.config,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static [WORKFLOW_DESERIALIZE](options: {
|
|
35
|
+
modelId: string;
|
|
36
|
+
config: OpenResponsesProviderSettings;
|
|
37
|
+
}) {
|
|
38
|
+
// Restore QuiverAI's handlers, which cannot cross workflow boundaries.
|
|
39
|
+
const config: OpenResponsesProviderSettings = {
|
|
40
|
+
...options.config,
|
|
41
|
+
failedResponseHandler: quiveraiFailedResponseHandler,
|
|
42
|
+
getResponseErrorMetadata: getQuiverAIResponseErrorMetadata,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return new QuiverAILanguageModel(
|
|
46
|
+
createOpenResponses(config).languageModel(options.modelId),
|
|
47
|
+
config,
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
constructor(
|
|
52
|
+
private readonly model: LanguageModelV4,
|
|
53
|
+
private readonly config: OpenResponsesProviderSettings,
|
|
54
|
+
) {}
|
|
55
|
+
|
|
56
|
+
get modelId() {
|
|
57
|
+
return this.model.modelId;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
get provider() {
|
|
61
|
+
return this.model.provider;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
get supportedUrls() {
|
|
65
|
+
return this.model.supportedUrls;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async doGenerate(options: LanguageModelV4CallOptions) {
|
|
69
|
+
const prepared = prepareQuiverAICall(options);
|
|
70
|
+
const result = await this.model.doGenerate(prepared.options);
|
|
71
|
+
return { ...result, warnings: [...prepared.warnings, ...result.warnings] };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async doStream(options: LanguageModelV4CallOptions) {
|
|
75
|
+
const prepared = prepareQuiverAICall(options);
|
|
76
|
+
const result = await this.model.doStream(prepared.options);
|
|
77
|
+
if (prepared.warnings.length === 0) return result;
|
|
78
|
+
return {
|
|
79
|
+
...result,
|
|
80
|
+
stream: result.stream.pipeThrough(
|
|
81
|
+
new TransformStream<
|
|
82
|
+
LanguageModelV4StreamPart,
|
|
83
|
+
LanguageModelV4StreamPart
|
|
84
|
+
>({
|
|
85
|
+
transform(part, controller) {
|
|
86
|
+
controller.enqueue(
|
|
87
|
+
part.type === 'stream-start'
|
|
88
|
+
? {
|
|
89
|
+
...part,
|
|
90
|
+
warnings: [...prepared.warnings, ...part.warnings],
|
|
91
|
+
}
|
|
92
|
+
: part,
|
|
93
|
+
);
|
|
94
|
+
},
|
|
95
|
+
}),
|
|
96
|
+
),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function prepareQuiverAICall(options: LanguageModelV4CallOptions): {
|
|
102
|
+
options: LanguageModelV4CallOptions;
|
|
103
|
+
warnings: SharedV4Warning[];
|
|
104
|
+
} {
|
|
105
|
+
const { reasoningEffort, reasoningSummary } =
|
|
106
|
+
options.providerOptions?.quiverai ?? {};
|
|
107
|
+
if (
|
|
108
|
+
reasoningEffort != null &&
|
|
109
|
+
(typeof reasoningEffort !== 'string' ||
|
|
110
|
+
!['low', 'medium', 'high', 'xhigh'].includes(reasoningEffort))
|
|
111
|
+
) {
|
|
112
|
+
throw new InvalidArgumentError({
|
|
113
|
+
argument: 'providerOptions',
|
|
114
|
+
message: `Unsupported reasoning effort: ${reasoningEffort}`,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
if (reasoningSummary != null && reasoningSummary !== 'auto') {
|
|
118
|
+
throw new InvalidArgumentError({
|
|
119
|
+
argument: 'providerOptions',
|
|
120
|
+
message: `Unsupported reasoning summary: ${reasoningSummary}`,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const warnings: SharedV4Warning[] = [];
|
|
125
|
+
const omitReasoning = options.reasoning === 'none' && reasoningEffort == null;
|
|
126
|
+
if (omitReasoning) {
|
|
127
|
+
warnings.push({ type: 'unsupported', feature: 'reasoning effort none' });
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
warnings,
|
|
132
|
+
options: {
|
|
133
|
+
...options,
|
|
134
|
+
reasoning: omitReasoning ? undefined : options.reasoning,
|
|
135
|
+
prompt: options.prompt.map(message =>
|
|
136
|
+
message.role !== 'assistant'
|
|
137
|
+
? message
|
|
138
|
+
: {
|
|
139
|
+
...message,
|
|
140
|
+
content: message.content.map(part => {
|
|
141
|
+
if (part.type !== 'reasoning') return part;
|
|
142
|
+
const metadata =
|
|
143
|
+
part.providerOptions?.quiverai ??
|
|
144
|
+
(part as { providerMetadata?: SharedV4ProviderMetadata })
|
|
145
|
+
.providerMetadata?.quiverai;
|
|
146
|
+
return {
|
|
147
|
+
...part,
|
|
148
|
+
text: '',
|
|
149
|
+
providerOptions: {
|
|
150
|
+
...part.providerOptions,
|
|
151
|
+
quiverai: {
|
|
152
|
+
itemId: metadata?.itemId,
|
|
153
|
+
reasoningSummary: metadata?.reasoningSummary,
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
}),
|
|
158
|
+
},
|
|
159
|
+
),
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|
package/src/quiverai-provider.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
NoSuchModelError,
|
|
3
3
|
type ImageModelV4,
|
|
4
|
+
type LanguageModelV4,
|
|
4
5
|
type ProviderV4,
|
|
5
6
|
} from '@ai-sdk/provider';
|
|
7
|
+
import {
|
|
8
|
+
createOpenResponses,
|
|
9
|
+
type OpenResponsesProviderSettings,
|
|
10
|
+
} from '@ai-sdk/open-responses';
|
|
6
11
|
import {
|
|
7
12
|
loadApiKey,
|
|
8
13
|
loadOptionalSetting,
|
|
@@ -10,8 +15,14 @@ import {
|
|
|
10
15
|
withUserAgentSuffix,
|
|
11
16
|
type FetchFunction,
|
|
12
17
|
} from '@ai-sdk/provider-utils';
|
|
18
|
+
import {
|
|
19
|
+
getQuiverAIResponseErrorMetadata,
|
|
20
|
+
quiveraiFailedResponseHandler,
|
|
21
|
+
} from './quiverai-error';
|
|
22
|
+
import { QuiverAILanguageModel } from './quiverai-language-model';
|
|
13
23
|
import { QuiverAIImageModel } from './quiverai-image-model';
|
|
14
24
|
import type { QuiverAIImageModelId } from './quiverai-image-settings';
|
|
25
|
+
import type { QuiverAILanguageModelId } from './quiverai-language-model-settings';
|
|
15
26
|
import { VERSION } from './version';
|
|
16
27
|
|
|
17
28
|
export interface QuiverAIProviderSettings {
|
|
@@ -40,6 +51,16 @@ export interface QuiverAIProviderSettings {
|
|
|
40
51
|
}
|
|
41
52
|
|
|
42
53
|
export interface QuiverAIProvider extends ProviderV4 {
|
|
54
|
+
/**
|
|
55
|
+
* Creates a language model for the QuiverAI Responses API.
|
|
56
|
+
*/
|
|
57
|
+
(modelId: QuiverAILanguageModelId): LanguageModelV4;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Creates a language model for the QuiverAI Responses API.
|
|
61
|
+
*/
|
|
62
|
+
languageModel(modelId: QuiverAILanguageModelId): LanguageModelV4;
|
|
63
|
+
|
|
43
64
|
/**
|
|
44
65
|
* Creates a model for image generation.
|
|
45
66
|
*/
|
|
@@ -54,6 +75,11 @@ export interface QuiverAIProvider extends ProviderV4 {
|
|
|
54
75
|
* @deprecated Use `embeddingModel` instead.
|
|
55
76
|
*/
|
|
56
77
|
textEmbeddingModel(modelId: string): never;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* QuiverAI caller-executed tools.
|
|
81
|
+
*/
|
|
82
|
+
tools: ReturnType<typeof createOpenResponses>['tools'];
|
|
57
83
|
}
|
|
58
84
|
|
|
59
85
|
const defaultBaseURL = 'https://api.quiver.ai/v1';
|
|
@@ -69,24 +95,43 @@ export function createQuiverAI(
|
|
|
69
95
|
}),
|
|
70
96
|
) ?? defaultBaseURL;
|
|
71
97
|
|
|
72
|
-
const getHeaders = () =>
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
98
|
+
const getHeaders = () => ({
|
|
99
|
+
Authorization: `Bearer ${loadApiKey({
|
|
100
|
+
apiKey: options.apiKey,
|
|
101
|
+
environmentVariableName: 'QUIVERAI_API_KEY',
|
|
102
|
+
description: 'QuiverAI',
|
|
103
|
+
})}`,
|
|
104
|
+
...options.headers,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const getImageHeaders = () =>
|
|
108
|
+
withUserAgentSuffix(getHeaders(), `ai-sdk/quiverai/${VERSION}`);
|
|
109
|
+
|
|
110
|
+
const responsesConfig: OpenResponsesProviderSettings = {
|
|
111
|
+
name: 'quiverai',
|
|
112
|
+
url: `${baseURL}/responses`,
|
|
113
|
+
headers: getHeaders,
|
|
114
|
+
fetch: options.fetch,
|
|
115
|
+
failedResponseHandler: quiveraiFailedResponseHandler,
|
|
116
|
+
getResponseErrorMetadata: getQuiverAIResponseErrorMetadata,
|
|
117
|
+
strictResponseInput: true,
|
|
118
|
+
customToolId: 'quiverai.custom',
|
|
119
|
+
structuredOutputs: false,
|
|
120
|
+
userAgentSuffix: `ai-sdk/quiverai/${VERSION}`,
|
|
121
|
+
};
|
|
122
|
+
const responsesProvider = createOpenResponses(responsesConfig);
|
|
123
|
+
|
|
124
|
+
const createLanguageModel = (modelId: QuiverAILanguageModelId) =>
|
|
125
|
+
new QuiverAILanguageModel(
|
|
126
|
+
responsesProvider.languageModel(modelId),
|
|
127
|
+
responsesConfig,
|
|
83
128
|
);
|
|
84
129
|
|
|
85
130
|
const createImageModel = (modelId: QuiverAIImageModelId) =>
|
|
86
131
|
new QuiverAIImageModel(modelId, {
|
|
87
132
|
provider: 'quiverai.image',
|
|
88
133
|
baseURL,
|
|
89
|
-
headers:
|
|
134
|
+
headers: getImageHeaders,
|
|
90
135
|
fetch: options.fetch,
|
|
91
136
|
});
|
|
92
137
|
|
|
@@ -97,19 +142,19 @@ export function createQuiverAI(
|
|
|
97
142
|
});
|
|
98
143
|
};
|
|
99
144
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
image: createImageModel,
|
|
103
|
-
imageModel: createImageModel,
|
|
104
|
-
languageModel: (modelId: string) => {
|
|
105
|
-
throw new NoSuchModelError({
|
|
106
|
-
modelId,
|
|
107
|
-
modelType: 'languageModel',
|
|
108
|
-
});
|
|
109
|
-
},
|
|
110
|
-
embeddingModel,
|
|
111
|
-
textEmbeddingModel: embeddingModel,
|
|
145
|
+
const provider = function (modelId: QuiverAILanguageModelId) {
|
|
146
|
+
return createLanguageModel(modelId);
|
|
112
147
|
};
|
|
148
|
+
|
|
149
|
+
provider.specificationVersion = 'v4' as const;
|
|
150
|
+
provider.languageModel = createLanguageModel;
|
|
151
|
+
provider.image = createImageModel;
|
|
152
|
+
provider.imageModel = createImageModel;
|
|
153
|
+
provider.embeddingModel = embeddingModel;
|
|
154
|
+
provider.textEmbeddingModel = embeddingModel;
|
|
155
|
+
provider.tools = responsesProvider.tools;
|
|
156
|
+
|
|
157
|
+
return provider as QuiverAIProvider;
|
|
113
158
|
}
|
|
114
159
|
|
|
115
160
|
export const quiverai = createQuiverAI();
|