@providerprotocol/ai 0.0.5 → 0.0.7
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/dist/anthropic/index.js +1 -24
- package/dist/anthropic/index.js.map +1 -1
- package/dist/google/index.js +3 -46
- package/dist/google/index.js.map +1 -1
- package/dist/ollama/index.js +13 -44
- package/dist/ollama/index.js.map +1 -1
- package/dist/openai/index.d.ts +46 -27
- package/dist/openai/index.js +2 -116
- package/dist/openai/index.js.map +1 -1
- package/dist/openrouter/index.d.ts +23 -10
- package/dist/openrouter/index.js +2 -85
- package/dist/openrouter/index.js.map +1 -1
- package/dist/xai/index.d.ts +59 -35
- package/dist/xai/index.js +3 -119
- package/dist/xai/index.js.map +1 -1
- package/package.json +2 -1
- package/src/openai/index.ts +2 -1
- package/src/openrouter/index.ts +2 -1
- package/src/providers/anthropic/transform.ts +7 -29
- package/src/providers/google/transform.ts +9 -49
- package/src/providers/ollama/transform.ts +27 -49
- package/src/providers/openai/index.ts +12 -8
- package/src/providers/openai/llm.completions.ts +9 -9
- package/src/providers/openai/llm.responses.ts +9 -9
- package/src/providers/openai/transform.completions.ts +12 -79
- package/src/providers/openai/transform.responses.ts +12 -54
- package/src/providers/openai/types.ts +54 -31
- package/src/providers/openrouter/index.ts +12 -8
- package/src/providers/openrouter/llm.completions.ts +9 -9
- package/src/providers/openrouter/llm.responses.ts +9 -9
- package/src/providers/openrouter/transform.completions.ts +12 -79
- package/src/providers/openrouter/transform.responses.ts +12 -25
- package/src/providers/openrouter/types.ts +22 -28
- package/src/providers/xai/index.ts +15 -10
- package/src/providers/xai/llm.completions.ts +9 -9
- package/src/providers/xai/llm.messages.ts +9 -9
- package/src/providers/xai/llm.responses.ts +9 -9
- package/src/providers/xai/transform.completions.ts +12 -64
- package/src/providers/xai/transform.messages.ts +11 -30
- package/src/providers/xai/transform.responses.ts +12 -51
- package/src/providers/xai/types.ts +68 -38
- package/src/xai/index.ts +3 -1
|
@@ -25,6 +25,10 @@ import type {
|
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Transform UPP request to Anthropic format
|
|
28
|
+
*
|
|
29
|
+
* Params are spread directly to allow pass-through of any Anthropic API fields,
|
|
30
|
+
* even those not explicitly defined in our type. This enables developers to
|
|
31
|
+
* use new API features without waiting for library updates.
|
|
28
32
|
*/
|
|
29
33
|
export function transformRequest<TParams extends AnthropicLLMParams>(
|
|
30
34
|
request: LLMRequest<TParams>,
|
|
@@ -32,45 +36,19 @@ export function transformRequest<TParams extends AnthropicLLMParams>(
|
|
|
32
36
|
): AnthropicRequest {
|
|
33
37
|
const params = (request.params ?? {}) as AnthropicLLMParams;
|
|
34
38
|
|
|
39
|
+
// Spread params to pass through all fields, then set required fields
|
|
35
40
|
const anthropicRequest: AnthropicRequest = {
|
|
41
|
+
...params,
|
|
36
42
|
model: modelId,
|
|
37
43
|
messages: request.messages.map(transformMessage),
|
|
38
44
|
};
|
|
39
45
|
|
|
40
|
-
// Only include max_tokens if provided - let Anthropic API enforce its requirement
|
|
41
|
-
if (params.max_tokens !== undefined) {
|
|
42
|
-
anthropicRequest.max_tokens = params.max_tokens;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
46
|
// System prompt (top-level in Anthropic)
|
|
46
47
|
if (request.system) {
|
|
47
48
|
anthropicRequest.system = request.system;
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
//
|
|
51
|
-
if (params.temperature !== undefined) {
|
|
52
|
-
anthropicRequest.temperature = params.temperature;
|
|
53
|
-
}
|
|
54
|
-
if (params.top_p !== undefined) {
|
|
55
|
-
anthropicRequest.top_p = params.top_p;
|
|
56
|
-
}
|
|
57
|
-
if (params.top_k !== undefined) {
|
|
58
|
-
anthropicRequest.top_k = params.top_k;
|
|
59
|
-
}
|
|
60
|
-
if (params.stop_sequences) {
|
|
61
|
-
anthropicRequest.stop_sequences = params.stop_sequences;
|
|
62
|
-
}
|
|
63
|
-
if (params.metadata) {
|
|
64
|
-
anthropicRequest.metadata = params.metadata;
|
|
65
|
-
}
|
|
66
|
-
if (params.thinking) {
|
|
67
|
-
anthropicRequest.thinking = params.thinking;
|
|
68
|
-
}
|
|
69
|
-
if (params.service_tier !== undefined) {
|
|
70
|
-
anthropicRequest.service_tier = params.service_tier;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Tools
|
|
51
|
+
// Tools come from request, not params
|
|
74
52
|
if (request.tools && request.tools.length > 0) {
|
|
75
53
|
anthropicRequest.tools = request.tools.map(transformTool);
|
|
76
54
|
anthropicRequest.tool_choice = { type: 'auto' };
|
|
@@ -23,6 +23,10 @@ import type {
|
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Transform UPP request to Google format
|
|
26
|
+
*
|
|
27
|
+
* Params are spread into generationConfig to allow pass-through of any Google API fields,
|
|
28
|
+
* even those not explicitly defined in our type. This enables developers to
|
|
29
|
+
* use new API features without waiting for library updates.
|
|
26
30
|
*/
|
|
27
31
|
export function transformRequest<TParams extends GoogleLLMParams>(
|
|
28
32
|
request: LLMRequest<TParams>,
|
|
@@ -41,54 +45,10 @@ export function transformRequest<TParams extends GoogleLLMParams>(
|
|
|
41
45
|
};
|
|
42
46
|
}
|
|
43
47
|
|
|
44
|
-
//
|
|
45
|
-
const generationConfig: NonNullable<GoogleRequest['generationConfig']> = {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
generationConfig.maxOutputTokens = params.maxOutputTokens;
|
|
49
|
-
}
|
|
50
|
-
if (params.temperature !== undefined) {
|
|
51
|
-
generationConfig.temperature = params.temperature;
|
|
52
|
-
}
|
|
53
|
-
if (params.topP !== undefined) {
|
|
54
|
-
generationConfig.topP = params.topP;
|
|
55
|
-
}
|
|
56
|
-
if (params.topK !== undefined) {
|
|
57
|
-
generationConfig.topK = params.topK;
|
|
58
|
-
}
|
|
59
|
-
if (params.stopSequences !== undefined) {
|
|
60
|
-
generationConfig.stopSequences = params.stopSequences;
|
|
61
|
-
}
|
|
62
|
-
if (params.candidateCount !== undefined) {
|
|
63
|
-
generationConfig.candidateCount = params.candidateCount;
|
|
64
|
-
}
|
|
65
|
-
if (params.responseMimeType !== undefined) {
|
|
66
|
-
generationConfig.responseMimeType = params.responseMimeType;
|
|
67
|
-
}
|
|
68
|
-
if (params.responseSchema !== undefined) {
|
|
69
|
-
generationConfig.responseSchema = params.responseSchema as Record<string, unknown>;
|
|
70
|
-
}
|
|
71
|
-
if (params.presencePenalty !== undefined) {
|
|
72
|
-
generationConfig.presencePenalty = params.presencePenalty;
|
|
73
|
-
}
|
|
74
|
-
if (params.frequencyPenalty !== undefined) {
|
|
75
|
-
generationConfig.frequencyPenalty = params.frequencyPenalty;
|
|
76
|
-
}
|
|
77
|
-
if (params.seed !== undefined) {
|
|
78
|
-
generationConfig.seed = params.seed;
|
|
79
|
-
}
|
|
80
|
-
if (params.responseLogprobs !== undefined) {
|
|
81
|
-
generationConfig.responseLogprobs = params.responseLogprobs;
|
|
82
|
-
}
|
|
83
|
-
if (params.logprobs !== undefined) {
|
|
84
|
-
generationConfig.logprobs = params.logprobs;
|
|
85
|
-
}
|
|
86
|
-
if (params.audioTimestamp !== undefined) {
|
|
87
|
-
generationConfig.audioTimestamp = params.audioTimestamp;
|
|
88
|
-
}
|
|
89
|
-
if (params.thinkingConfig !== undefined) {
|
|
90
|
-
generationConfig.thinkingConfig = params.thinkingConfig;
|
|
91
|
-
}
|
|
48
|
+
// Spread params into generationConfig to pass through all fields
|
|
49
|
+
const generationConfig: NonNullable<GoogleRequest['generationConfig']> = {
|
|
50
|
+
...params,
|
|
51
|
+
};
|
|
92
52
|
|
|
93
53
|
// Protocol-level structured output (overrides provider-specific settings)
|
|
94
54
|
if (request.structure) {
|
|
@@ -100,7 +60,7 @@ export function transformRequest<TParams extends GoogleLLMParams>(
|
|
|
100
60
|
googleRequest.generationConfig = generationConfig;
|
|
101
61
|
}
|
|
102
62
|
|
|
103
|
-
// Tools
|
|
63
|
+
// Tools come from request, not params
|
|
104
64
|
if (request.tools && request.tools.length > 0) {
|
|
105
65
|
googleRequest.tools = [
|
|
106
66
|
{
|
|
@@ -23,6 +23,14 @@ import type {
|
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Transform UPP request to Ollama format
|
|
26
|
+
*
|
|
27
|
+
* Params are spread to allow pass-through of any Ollama API fields,
|
|
28
|
+
* even those not explicitly defined in our type. This enables developers to
|
|
29
|
+
* use new API features without waiting for library updates.
|
|
30
|
+
*
|
|
31
|
+
* Note: Ollama uses nested 'options' for model parameters. Params that belong
|
|
32
|
+
* in options (like temperature, top_p, etc.) are spread into options, while
|
|
33
|
+
* top-level params (like keep_alive, think) are spread at the request level.
|
|
26
34
|
*/
|
|
27
35
|
export function transformRequest<TParams extends OllamaLLMParams>(
|
|
28
36
|
request: LLMRequest<TParams>,
|
|
@@ -30,63 +38,33 @@ export function transformRequest<TParams extends OllamaLLMParams>(
|
|
|
30
38
|
): OllamaRequest {
|
|
31
39
|
const params = (request.params ?? {}) as OllamaLLMParams;
|
|
32
40
|
|
|
41
|
+
// Extract top-level params vs options params
|
|
42
|
+
const {
|
|
43
|
+
keep_alive,
|
|
44
|
+
think,
|
|
45
|
+
logprobs,
|
|
46
|
+
top_logprobs,
|
|
47
|
+
...optionsParams
|
|
48
|
+
} = params;
|
|
49
|
+
|
|
50
|
+
// Spread params to pass through all fields, then set required fields
|
|
33
51
|
const ollamaRequest: OllamaRequest = {
|
|
34
52
|
model: modelId,
|
|
35
53
|
messages: transformMessages(request.messages, request.system),
|
|
36
54
|
};
|
|
37
55
|
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (
|
|
42
|
-
if (
|
|
43
|
-
if (params.top_p !== undefined) options.top_p = params.top_p;
|
|
44
|
-
if (params.top_k !== undefined) options.top_k = params.top_k;
|
|
45
|
-
if (params.min_p !== undefined) options.min_p = params.min_p;
|
|
46
|
-
if (params.typical_p !== undefined) options.typical_p = params.typical_p;
|
|
47
|
-
if (params.repeat_penalty !== undefined) options.repeat_penalty = params.repeat_penalty;
|
|
48
|
-
if (params.repeat_last_n !== undefined) options.repeat_last_n = params.repeat_last_n;
|
|
49
|
-
if (params.presence_penalty !== undefined) options.presence_penalty = params.presence_penalty;
|
|
50
|
-
if (params.frequency_penalty !== undefined) options.frequency_penalty = params.frequency_penalty;
|
|
51
|
-
if (params.mirostat !== undefined) options.mirostat = params.mirostat;
|
|
52
|
-
if (params.mirostat_eta !== undefined) options.mirostat_eta = params.mirostat_eta;
|
|
53
|
-
if (params.mirostat_tau !== undefined) options.mirostat_tau = params.mirostat_tau;
|
|
54
|
-
if (params.penalize_newline !== undefined) options.penalize_newline = params.penalize_newline;
|
|
55
|
-
if (params.stop !== undefined) options.stop = params.stop;
|
|
56
|
-
if (params.seed !== undefined) options.seed = params.seed;
|
|
57
|
-
if (params.num_keep !== undefined) options.num_keep = params.num_keep;
|
|
58
|
-
if (params.num_ctx !== undefined) options.num_ctx = params.num_ctx;
|
|
59
|
-
if (params.num_batch !== undefined) options.num_batch = params.num_batch;
|
|
60
|
-
if (params.num_thread !== undefined) options.num_thread = params.num_thread;
|
|
61
|
-
if (params.num_gpu !== undefined) options.num_gpu = params.num_gpu;
|
|
62
|
-
if (params.main_gpu !== undefined) options.main_gpu = params.main_gpu;
|
|
63
|
-
if (params.low_vram !== undefined) options.low_vram = params.low_vram;
|
|
64
|
-
if (params.f16_kv !== undefined) options.f16_kv = params.f16_kv;
|
|
65
|
-
if (params.use_mmap !== undefined) options.use_mmap = params.use_mmap;
|
|
66
|
-
if (params.use_mlock !== undefined) options.use_mlock = params.use_mlock;
|
|
67
|
-
if (params.vocab_only !== undefined) options.vocab_only = params.vocab_only;
|
|
68
|
-
if (params.numa !== undefined) options.numa = params.numa;
|
|
69
|
-
if (params.tfs_z !== undefined) options.tfs_z = params.tfs_z;
|
|
70
|
-
|
|
71
|
-
if (Object.keys(options).length > 0) {
|
|
72
|
-
ollamaRequest.options = options;
|
|
73
|
-
}
|
|
56
|
+
// Add top-level params if provided
|
|
57
|
+
if (keep_alive !== undefined) ollamaRequest.keep_alive = keep_alive;
|
|
58
|
+
if (think !== undefined) ollamaRequest.think = think;
|
|
59
|
+
if (logprobs !== undefined) ollamaRequest.logprobs = logprobs;
|
|
60
|
+
if (top_logprobs !== undefined) ollamaRequest.top_logprobs = top_logprobs;
|
|
74
61
|
|
|
75
|
-
//
|
|
76
|
-
if (
|
|
77
|
-
ollamaRequest.
|
|
78
|
-
}
|
|
79
|
-
if (params.think !== undefined) {
|
|
80
|
-
ollamaRequest.think = params.think;
|
|
81
|
-
}
|
|
82
|
-
if (params.logprobs !== undefined) {
|
|
83
|
-
ollamaRequest.logprobs = params.logprobs;
|
|
84
|
-
}
|
|
85
|
-
if (params.top_logprobs !== undefined) {
|
|
86
|
-
ollamaRequest.top_logprobs = params.top_logprobs;
|
|
62
|
+
// Spread remaining params into options to pass through all model parameters
|
|
63
|
+
if (Object.keys(optionsParams).length > 0) {
|
|
64
|
+
ollamaRequest.options = optionsParams as OllamaOptions;
|
|
87
65
|
}
|
|
88
66
|
|
|
89
|
-
// Tools
|
|
67
|
+
// Tools come from request, not params
|
|
90
68
|
if (request.tools && request.tools.length > 0) {
|
|
91
69
|
ollamaRequest.tools = request.tools.map(transformTool);
|
|
92
70
|
}
|
|
@@ -6,7 +6,10 @@ import type {
|
|
|
6
6
|
} from '../../types/provider.ts';
|
|
7
7
|
import { createCompletionsLLMHandler } from './llm.completions.ts';
|
|
8
8
|
import { createResponsesLLMHandler } from './llm.responses.ts';
|
|
9
|
-
import type {
|
|
9
|
+
import type { OpenAICompletionsParams, OpenAIResponsesParams, OpenAIConfig } from './types.ts';
|
|
10
|
+
|
|
11
|
+
/** Union type for modalities interface */
|
|
12
|
+
type OpenAILLMParamsUnion = OpenAICompletionsParams | OpenAIResponsesParams;
|
|
10
13
|
|
|
11
14
|
/**
|
|
12
15
|
* OpenAI provider options
|
|
@@ -51,7 +54,7 @@ export interface OpenAIProvider extends Provider<OpenAIProviderOptions> {
|
|
|
51
54
|
|
|
52
55
|
/** Supported modalities */
|
|
53
56
|
readonly modalities: {
|
|
54
|
-
llm: LLMHandler<
|
|
57
|
+
llm: LLMHandler<OpenAILLMParamsUnion>;
|
|
55
58
|
};
|
|
56
59
|
}
|
|
57
60
|
|
|
@@ -77,10 +80,10 @@ function createOpenAIProvider(): OpenAIProvider {
|
|
|
77
80
|
|
|
78
81
|
// Create a dynamic modalities object that returns the correct handler
|
|
79
82
|
const modalities = {
|
|
80
|
-
get llm(): LLMHandler<
|
|
83
|
+
get llm(): LLMHandler<OpenAILLMParamsUnion> {
|
|
81
84
|
return currentApiMode === 'completions'
|
|
82
|
-
? completionsHandler
|
|
83
|
-
: responsesHandler;
|
|
85
|
+
? (completionsHandler as unknown as LLMHandler<OpenAILLMParamsUnion>)
|
|
86
|
+
: (responsesHandler as unknown as LLMHandler<OpenAILLMParamsUnion>);
|
|
84
87
|
},
|
|
85
88
|
};
|
|
86
89
|
|
|
@@ -106,8 +109,8 @@ function createOpenAIProvider(): OpenAIProvider {
|
|
|
106
109
|
const provider = fn as OpenAIProvider;
|
|
107
110
|
|
|
108
111
|
// Inject provider reference into both handlers (spec compliance)
|
|
109
|
-
responsesHandler._setProvider?.(provider as unknown as LLMProvider<
|
|
110
|
-
completionsHandler._setProvider?.(provider as unknown as LLMProvider<
|
|
112
|
+
responsesHandler._setProvider?.(provider as unknown as LLMProvider<OpenAIResponsesParams>);
|
|
113
|
+
completionsHandler._setProvider?.(provider as unknown as LLMProvider<OpenAICompletionsParams>);
|
|
111
114
|
|
|
112
115
|
return provider;
|
|
113
116
|
}
|
|
@@ -143,7 +146,8 @@ export const openai = createOpenAIProvider();
|
|
|
143
146
|
|
|
144
147
|
// Re-export types
|
|
145
148
|
export type {
|
|
146
|
-
|
|
149
|
+
OpenAICompletionsParams,
|
|
150
|
+
OpenAIResponsesParams,
|
|
147
151
|
OpenAIConfig,
|
|
148
152
|
OpenAIAPIMode,
|
|
149
153
|
OpenAIModelOptions,
|
|
@@ -6,7 +6,7 @@ import { resolveApiKey } from '../../http/keys.ts';
|
|
|
6
6
|
import { doFetch, doStreamFetch } from '../../http/fetch.ts';
|
|
7
7
|
import { parseSSEStream } from '../../http/sse.ts';
|
|
8
8
|
import { normalizeHttpError } from '../../http/errors.ts';
|
|
9
|
-
import type {
|
|
9
|
+
import type { OpenAICompletionsParams, OpenAICompletionsResponse, OpenAICompletionsStreamChunk } from './types.ts';
|
|
10
10
|
import {
|
|
11
11
|
transformRequest,
|
|
12
12
|
transformResponse,
|
|
@@ -32,16 +32,16 @@ const OPENAI_CAPABILITIES: LLMCapabilities = {
|
|
|
32
32
|
/**
|
|
33
33
|
* Create OpenAI Chat Completions LLM handler
|
|
34
34
|
*/
|
|
35
|
-
export function createCompletionsLLMHandler(): LLMHandler<
|
|
35
|
+
export function createCompletionsLLMHandler(): LLMHandler<OpenAICompletionsParams> {
|
|
36
36
|
// Provider reference injected by createProvider() or OpenAI's custom factory
|
|
37
|
-
let providerRef: LLMProvider<
|
|
37
|
+
let providerRef: LLMProvider<OpenAICompletionsParams> | null = null;
|
|
38
38
|
|
|
39
39
|
return {
|
|
40
|
-
_setProvider(provider: LLMProvider<
|
|
40
|
+
_setProvider(provider: LLMProvider<OpenAICompletionsParams>) {
|
|
41
41
|
providerRef = provider;
|
|
42
42
|
},
|
|
43
43
|
|
|
44
|
-
bind(modelId: string): BoundLLMModel<
|
|
44
|
+
bind(modelId: string): BoundLLMModel<OpenAICompletionsParams> {
|
|
45
45
|
// Use the injected provider reference
|
|
46
46
|
if (!providerRef) {
|
|
47
47
|
throw new UPPError(
|
|
@@ -52,15 +52,15 @@ export function createCompletionsLLMHandler(): LLMHandler<OpenAILLMParams> {
|
|
|
52
52
|
);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
const model: BoundLLMModel<
|
|
55
|
+
const model: BoundLLMModel<OpenAICompletionsParams> = {
|
|
56
56
|
modelId,
|
|
57
57
|
capabilities: OPENAI_CAPABILITIES,
|
|
58
58
|
|
|
59
|
-
get provider(): LLMProvider<
|
|
59
|
+
get provider(): LLMProvider<OpenAICompletionsParams> {
|
|
60
60
|
return providerRef!;
|
|
61
61
|
},
|
|
62
62
|
|
|
63
|
-
async complete(request: LLMRequest<
|
|
63
|
+
async complete(request: LLMRequest<OpenAICompletionsParams>): Promise<LLMResponse> {
|
|
64
64
|
const apiKey = await resolveApiKey(
|
|
65
65
|
request.config,
|
|
66
66
|
'OPENAI_API_KEY',
|
|
@@ -91,7 +91,7 @@ export function createCompletionsLLMHandler(): LLMHandler<OpenAILLMParams> {
|
|
|
91
91
|
return transformResponse(data);
|
|
92
92
|
},
|
|
93
93
|
|
|
94
|
-
stream(request: LLMRequest<
|
|
94
|
+
stream(request: LLMRequest<OpenAICompletionsParams>): LLMStreamResult {
|
|
95
95
|
const state = createStreamState();
|
|
96
96
|
let responseResolve: (value: LLMResponse) => void;
|
|
97
97
|
let responseReject: (error: Error) => void;
|
|
@@ -6,7 +6,7 @@ import { resolveApiKey } from '../../http/keys.ts';
|
|
|
6
6
|
import { doFetch, doStreamFetch } from '../../http/fetch.ts';
|
|
7
7
|
import { parseSSEStream } from '../../http/sse.ts';
|
|
8
8
|
import { normalizeHttpError } from '../../http/errors.ts';
|
|
9
|
-
import type {
|
|
9
|
+
import type { OpenAIResponsesParams, OpenAIResponsesResponse, OpenAIResponsesStreamEvent, OpenAIResponseErrorEvent } from './types.ts';
|
|
10
10
|
import {
|
|
11
11
|
transformRequest,
|
|
12
12
|
transformResponse,
|
|
@@ -32,16 +32,16 @@ const OPENAI_CAPABILITIES: LLMCapabilities = {
|
|
|
32
32
|
/**
|
|
33
33
|
* Create OpenAI Responses API LLM handler
|
|
34
34
|
*/
|
|
35
|
-
export function createResponsesLLMHandler(): LLMHandler<
|
|
35
|
+
export function createResponsesLLMHandler(): LLMHandler<OpenAIResponsesParams> {
|
|
36
36
|
// Provider reference injected by createProvider() or OpenAI's custom factory
|
|
37
|
-
let providerRef: LLMProvider<
|
|
37
|
+
let providerRef: LLMProvider<OpenAIResponsesParams> | null = null;
|
|
38
38
|
|
|
39
39
|
return {
|
|
40
|
-
_setProvider(provider: LLMProvider<
|
|
40
|
+
_setProvider(provider: LLMProvider<OpenAIResponsesParams>) {
|
|
41
41
|
providerRef = provider;
|
|
42
42
|
},
|
|
43
43
|
|
|
44
|
-
bind(modelId: string): BoundLLMModel<
|
|
44
|
+
bind(modelId: string): BoundLLMModel<OpenAIResponsesParams> {
|
|
45
45
|
// Use the injected provider reference
|
|
46
46
|
if (!providerRef) {
|
|
47
47
|
throw new UPPError(
|
|
@@ -52,15 +52,15 @@ export function createResponsesLLMHandler(): LLMHandler<OpenAILLMParams> {
|
|
|
52
52
|
);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
const model: BoundLLMModel<
|
|
55
|
+
const model: BoundLLMModel<OpenAIResponsesParams> = {
|
|
56
56
|
modelId,
|
|
57
57
|
capabilities: OPENAI_CAPABILITIES,
|
|
58
58
|
|
|
59
|
-
get provider(): LLMProvider<
|
|
59
|
+
get provider(): LLMProvider<OpenAIResponsesParams> {
|
|
60
60
|
return providerRef!;
|
|
61
61
|
},
|
|
62
62
|
|
|
63
|
-
async complete(request: LLMRequest<
|
|
63
|
+
async complete(request: LLMRequest<OpenAIResponsesParams>): Promise<LLMResponse> {
|
|
64
64
|
const apiKey = await resolveApiKey(
|
|
65
65
|
request.config,
|
|
66
66
|
'OPENAI_API_KEY',
|
|
@@ -102,7 +102,7 @@ export function createResponsesLLMHandler(): LLMHandler<OpenAILLMParams> {
|
|
|
102
102
|
return transformResponse(data);
|
|
103
103
|
},
|
|
104
104
|
|
|
105
|
-
stream(request: LLMRequest<
|
|
105
|
+
stream(request: LLMRequest<OpenAIResponsesParams>): LLMStreamResult {
|
|
106
106
|
const state = createStreamState();
|
|
107
107
|
let responseResolve: (value: LLMResponse) => void;
|
|
108
108
|
let responseReject: (error: Error) => void;
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
isToolResultMessage,
|
|
12
12
|
} from '../../types/messages.ts';
|
|
13
13
|
import type {
|
|
14
|
-
|
|
14
|
+
OpenAICompletionsParams,
|
|
15
15
|
OpenAICompletionsRequest,
|
|
16
16
|
OpenAICompletionsMessage,
|
|
17
17
|
OpenAIUserContent,
|
|
@@ -23,94 +23,30 @@ import type {
|
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Transform UPP request to OpenAI Chat Completions format
|
|
26
|
+
*
|
|
27
|
+
* Params are spread directly to allow pass-through of any OpenAI API fields,
|
|
28
|
+
* even those not explicitly defined in our type. This enables developers to
|
|
29
|
+
* use new API features without waiting for library updates.
|
|
26
30
|
*/
|
|
27
|
-
export function transformRequest
|
|
28
|
-
request: LLMRequest<
|
|
31
|
+
export function transformRequest(
|
|
32
|
+
request: LLMRequest<OpenAICompletionsParams>,
|
|
29
33
|
modelId: string
|
|
30
34
|
): OpenAICompletionsRequest {
|
|
31
|
-
const params
|
|
35
|
+
const params = request.params ?? ({} as OpenAICompletionsParams);
|
|
32
36
|
|
|
37
|
+
// Spread params to pass through all fields, then set required fields
|
|
33
38
|
const openaiRequest: OpenAICompletionsRequest = {
|
|
39
|
+
...params,
|
|
34
40
|
model: modelId,
|
|
35
41
|
messages: transformMessages(request.messages, request.system),
|
|
36
42
|
};
|
|
37
43
|
|
|
38
|
-
//
|
|
39
|
-
if (params.temperature !== undefined) {
|
|
40
|
-
openaiRequest.temperature = params.temperature;
|
|
41
|
-
}
|
|
42
|
-
if (params.top_p !== undefined) {
|
|
43
|
-
openaiRequest.top_p = params.top_p;
|
|
44
|
-
}
|
|
45
|
-
if (params.max_completion_tokens !== undefined) {
|
|
46
|
-
openaiRequest.max_completion_tokens = params.max_completion_tokens;
|
|
47
|
-
} else if (params.max_tokens !== undefined) {
|
|
48
|
-
openaiRequest.max_tokens = params.max_tokens;
|
|
49
|
-
}
|
|
50
|
-
if (params.frequency_penalty !== undefined) {
|
|
51
|
-
openaiRequest.frequency_penalty = params.frequency_penalty;
|
|
52
|
-
}
|
|
53
|
-
if (params.presence_penalty !== undefined) {
|
|
54
|
-
openaiRequest.presence_penalty = params.presence_penalty;
|
|
55
|
-
}
|
|
56
|
-
if (params.stop !== undefined) {
|
|
57
|
-
openaiRequest.stop = params.stop;
|
|
58
|
-
}
|
|
59
|
-
if (params.n !== undefined) {
|
|
60
|
-
openaiRequest.n = params.n;
|
|
61
|
-
}
|
|
62
|
-
if (params.logprobs !== undefined) {
|
|
63
|
-
openaiRequest.logprobs = params.logprobs;
|
|
64
|
-
}
|
|
65
|
-
if (params.top_logprobs !== undefined) {
|
|
66
|
-
openaiRequest.top_logprobs = params.top_logprobs;
|
|
67
|
-
}
|
|
68
|
-
if (params.seed !== undefined) {
|
|
69
|
-
openaiRequest.seed = params.seed;
|
|
70
|
-
}
|
|
71
|
-
if (params.user !== undefined) {
|
|
72
|
-
openaiRequest.user = params.user;
|
|
73
|
-
}
|
|
74
|
-
if (params.logit_bias !== undefined) {
|
|
75
|
-
openaiRequest.logit_bias = params.logit_bias;
|
|
76
|
-
}
|
|
77
|
-
if (params.reasoning_effort !== undefined) {
|
|
78
|
-
openaiRequest.reasoning_effort = params.reasoning_effort;
|
|
79
|
-
}
|
|
80
|
-
if (params.verbosity !== undefined) {
|
|
81
|
-
openaiRequest.verbosity = params.verbosity;
|
|
82
|
-
}
|
|
83
|
-
if (params.service_tier !== undefined) {
|
|
84
|
-
openaiRequest.service_tier = params.service_tier;
|
|
85
|
-
}
|
|
86
|
-
if (params.store !== undefined) {
|
|
87
|
-
openaiRequest.store = params.store;
|
|
88
|
-
}
|
|
89
|
-
if (params.metadata !== undefined) {
|
|
90
|
-
openaiRequest.metadata = params.metadata;
|
|
91
|
-
}
|
|
92
|
-
if (params.prediction !== undefined) {
|
|
93
|
-
openaiRequest.prediction = params.prediction;
|
|
94
|
-
}
|
|
95
|
-
if (params.prompt_cache_key !== undefined) {
|
|
96
|
-
openaiRequest.prompt_cache_key = params.prompt_cache_key;
|
|
97
|
-
}
|
|
98
|
-
if (params.prompt_cache_retention !== undefined) {
|
|
99
|
-
openaiRequest.prompt_cache_retention = params.prompt_cache_retention;
|
|
100
|
-
}
|
|
101
|
-
if (params.safety_identifier !== undefined) {
|
|
102
|
-
openaiRequest.safety_identifier = params.safety_identifier;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Tools
|
|
44
|
+
// Tools come from request, not params
|
|
106
45
|
if (request.tools && request.tools.length > 0) {
|
|
107
46
|
openaiRequest.tools = request.tools.map(transformTool);
|
|
108
|
-
if (params.parallel_tool_calls !== undefined) {
|
|
109
|
-
openaiRequest.parallel_tool_calls = params.parallel_tool_calls;
|
|
110
|
-
}
|
|
111
47
|
}
|
|
112
48
|
|
|
113
|
-
// Structured output via response_format
|
|
49
|
+
// Structured output via response_format (overrides params.response_format if set)
|
|
114
50
|
if (request.structure) {
|
|
115
51
|
const schema: Record<string, unknown> = {
|
|
116
52
|
type: 'object',
|
|
@@ -133,9 +69,6 @@ export function transformRequest<TParams extends OpenAILLMParams>(
|
|
|
133
69
|
strict: true,
|
|
134
70
|
},
|
|
135
71
|
};
|
|
136
|
-
} else if (params.response_format !== undefined) {
|
|
137
|
-
// Pass through response_format from params if no structure is defined
|
|
138
|
-
openaiRequest.response_format = params.response_format;
|
|
139
72
|
}
|
|
140
73
|
|
|
141
74
|
return openaiRequest;
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
isToolResultMessage,
|
|
12
12
|
} from '../../types/messages.ts';
|
|
13
13
|
import type {
|
|
14
|
-
|
|
14
|
+
OpenAIResponsesParams,
|
|
15
15
|
OpenAIResponsesRequest,
|
|
16
16
|
OpenAIResponsesInputItem,
|
|
17
17
|
OpenAIResponsesContentPart,
|
|
@@ -25,72 +25,30 @@ import type {
|
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Transform UPP request to OpenAI Responses API format
|
|
28
|
+
*
|
|
29
|
+
* Params are spread directly to allow pass-through of any OpenAI API fields,
|
|
30
|
+
* even those not explicitly defined in our type. This enables developers to
|
|
31
|
+
* use new API features without waiting for library updates.
|
|
28
32
|
*/
|
|
29
|
-
export function transformRequest
|
|
30
|
-
request: LLMRequest<
|
|
33
|
+
export function transformRequest(
|
|
34
|
+
request: LLMRequest<OpenAIResponsesParams>,
|
|
31
35
|
modelId: string
|
|
32
36
|
): OpenAIResponsesRequest {
|
|
33
|
-
const params
|
|
37
|
+
const params = request.params ?? ({} as OpenAIResponsesParams);
|
|
34
38
|
|
|
39
|
+
// Spread params to pass through all fields, then set required fields
|
|
35
40
|
const openaiRequest: OpenAIResponsesRequest = {
|
|
41
|
+
...params,
|
|
36
42
|
model: modelId,
|
|
37
43
|
input: transformInputItems(request.messages, request.system),
|
|
38
44
|
};
|
|
39
45
|
|
|
40
|
-
//
|
|
41
|
-
if (params.temperature !== undefined) {
|
|
42
|
-
openaiRequest.temperature = params.temperature;
|
|
43
|
-
}
|
|
44
|
-
if (params.top_p !== undefined) {
|
|
45
|
-
openaiRequest.top_p = params.top_p;
|
|
46
|
-
}
|
|
47
|
-
if (params.max_output_tokens !== undefined) {
|
|
48
|
-
openaiRequest.max_output_tokens = params.max_output_tokens;
|
|
49
|
-
} else if (params.max_completion_tokens !== undefined) {
|
|
50
|
-
openaiRequest.max_output_tokens = params.max_completion_tokens;
|
|
51
|
-
} else if (params.max_tokens !== undefined) {
|
|
52
|
-
openaiRequest.max_output_tokens = params.max_tokens;
|
|
53
|
-
}
|
|
54
|
-
if (params.service_tier !== undefined) {
|
|
55
|
-
openaiRequest.service_tier = params.service_tier;
|
|
56
|
-
}
|
|
57
|
-
if (params.store !== undefined) {
|
|
58
|
-
openaiRequest.store = params.store;
|
|
59
|
-
}
|
|
60
|
-
if (params.metadata !== undefined) {
|
|
61
|
-
openaiRequest.metadata = params.metadata;
|
|
62
|
-
}
|
|
63
|
-
if (params.truncation !== undefined) {
|
|
64
|
-
openaiRequest.truncation = params.truncation;
|
|
65
|
-
}
|
|
66
|
-
if (params.include !== undefined) {
|
|
67
|
-
openaiRequest.include = params.include;
|
|
68
|
-
}
|
|
69
|
-
if (params.background !== undefined) {
|
|
70
|
-
openaiRequest.background = params.background;
|
|
71
|
-
}
|
|
72
|
-
if (params.previous_response_id !== undefined) {
|
|
73
|
-
openaiRequest.previous_response_id = params.previous_response_id;
|
|
74
|
-
}
|
|
75
|
-
if (params.reasoning !== undefined) {
|
|
76
|
-
openaiRequest.reasoning = { ...params.reasoning };
|
|
77
|
-
}
|
|
78
|
-
if (params.reasoning_effort !== undefined) {
|
|
79
|
-
openaiRequest.reasoning = {
|
|
80
|
-
...(openaiRequest.reasoning ?? {}),
|
|
81
|
-
effort: params.reasoning_effort,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Tools
|
|
46
|
+
// Tools come from request, not params
|
|
86
47
|
if (request.tools && request.tools.length > 0) {
|
|
87
48
|
openaiRequest.tools = request.tools.map(transformTool);
|
|
88
|
-
if (params.parallel_tool_calls !== undefined) {
|
|
89
|
-
openaiRequest.parallel_tool_calls = params.parallel_tool_calls;
|
|
90
|
-
}
|
|
91
49
|
}
|
|
92
50
|
|
|
93
|
-
// Structured output via text.format
|
|
51
|
+
// Structured output via text.format (overrides params.text if set)
|
|
94
52
|
if (request.structure) {
|
|
95
53
|
const schema: Record<string, unknown> = {
|
|
96
54
|
type: 'object',
|