@veryfront/ext-llm-openai 0.1.1241 → 0.1.1243

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.
@@ -3,6 +3,9 @@ export interface OpenAICompatibleLanguageOptions extends ModelRuntimeCallOptions
3
3
  serviceTier?: "auto" | "default" | "flex" | "scale";
4
4
  parallelToolCalls?: boolean;
5
5
  }
6
+ export type OpenAIChatRequestCapabilities = {
7
+ readonly reasoningWithFunctionTools?: boolean;
8
+ };
6
9
  /** @deprecated Import `ModelRuntimeToolDefinition` from `veryfront/provider` instead. */
7
10
  export type RuntimeToolDefinition = ModelRuntimeToolDefinition;
8
11
  type WarningCollector = {
@@ -19,6 +22,6 @@ type WarningCollector = {
19
22
  provider: string;
20
23
  }>;
21
24
  };
22
- export declare function buildOpenAIChatRequest(modelId: string, providerName: string, options: OpenAICompatibleLanguageOptions, stream: boolean, warnings: WarningCollector): OpenAICompatibleChatRequest;
25
+ export declare function buildOpenAIChatRequest(modelId: string, providerName: string, options: OpenAICompatibleLanguageOptions, stream: boolean, warnings: WarningCollector, capabilities?: OpenAIChatRequestCapabilities): OpenAICompatibleChatRequest;
23
26
  export {};
24
27
  //# sourceMappingURL=openai-chat-request-builder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"openai-chat-request-builder.d.ts","sourceRoot":"","sources":["../../../../src/extensions/ext-llm-openai/src/openai-chat-request-builder.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,uBAAuB,EACvB,0BAA0B,EAC1B,2BAA2B,EAC5B,MAAM,2BAA2B,CAAC;AAOnC,MAAM,WAAW,+BAAgC,SAAQ,uBAAuB;IAC9E,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IACpD,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,yFAAyF;AACzF,MAAM,MAAM,qBAAqB,GAAG,0BAA0B,CAAC;AAE/D,KAAK,gBAAgB,GAAG;IACtB,IAAI,CAAC,OAAO,EAAE;QACZ,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC;QACtC,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;KAClB,GAAG,IAAI,CAAC;IACT,KAAK,IAAI,KAAK,CAAC;QACb,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC;QACtC,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;CACJ,CAAC;AAUF,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,+BAA+B,EACxC,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,gBAAgB,GACzB,2BAA2B,CA+H7B"}
1
+ {"version":3,"file":"openai-chat-request-builder.d.ts","sourceRoot":"","sources":["../../../../src/extensions/ext-llm-openai/src/openai-chat-request-builder.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,uBAAuB,EACvB,0BAA0B,EAC1B,2BAA2B,EAC5B,MAAM,2BAA2B,CAAC;AAOnC,MAAM,WAAW,+BAAgC,SAAQ,uBAAuB;IAC9E,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IACpD,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,MAAM,6BAA6B,GAAG;IAC1C,QAAQ,CAAC,0BAA0B,CAAC,EAAE,OAAO,CAAC;CAC/C,CAAC;AAEF,yFAAyF;AACzF,MAAM,MAAM,qBAAqB,GAAG,0BAA0B,CAAC;AAE/D,KAAK,gBAAgB,GAAG;IACtB,IAAI,CAAC,OAAO,EAAE;QACZ,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC;QACtC,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;KAClB,GAAG,IAAI,CAAC;IACT,KAAK,IAAI,KAAK,CAAC;QACb,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC;QACtC,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;CACJ,CAAC;AAUF,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,+BAA+B,EACxC,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,gBAAgB,EAC1B,YAAY,CAAC,EAAE,6BAA6B,GAC3C,2BAA2B,CAiJ7B"}
@@ -7,8 +7,26 @@ function isNativeOpenAIModel(modelId) {
7
7
  function isFixedSamplingModel(modelId) {
8
8
  return /^kimi-k2\.5/.test(modelId);
9
9
  }
10
- export function buildOpenAIChatRequest(modelId, providerName, options, stream, warnings) {
11
- const reasoning = resolveOpenAIReasoningConfig(modelId, providerName, options.reasoning);
10
+ export function buildOpenAIChatRequest(modelId, providerName, options, stream, warnings, capabilities) {
11
+ const tools = toOpenAICompatibleTools(options.tools);
12
+ // Env-BYOK users historically registered options under "openai-compatible";
13
+ // keep merging that bucket at the lowest precedence. max_tokens is normalized
14
+ // per bucket BEFORE merging so a higher-precedence bucket's max_tokens
15
+ // override still beats a lower bucket's max_completion_tokens.
16
+ const bucketNames = [
17
+ ...(providerName === "openai" ? ["openai-compatible"] : []),
18
+ "openai",
19
+ providerName,
20
+ ];
21
+ const providerOpts = {};
22
+ for (const bucketName of bucketNames) {
23
+ defineOpenAIProviderOptions(providerOpts, normalizeNativeMaxTokens(readProviderOptions(options.providerOptions, bucketName), modelId));
24
+ }
25
+ const finalTools = Object.hasOwn(providerOpts, "tools") ? providerOpts.tools : tools;
26
+ const resolvedReasoning = resolveOpenAIReasoningConfig(modelId, providerName, options.reasoning);
27
+ const suppressReasoningForFunctionTools = hasOpenAIFunctionTools(finalTools) &&
28
+ capabilities?.reasoningWithFunctionTools === false;
29
+ const reasoning = suppressReasoningForFunctionTools ? undefined : resolvedReasoning;
12
30
  const reasoningEnabled = reasoning !== undefined;
13
31
  const samplingRejected = rejectsOpenAISamplingParams(modelId);
14
32
  const fixedSampling = isFixedSamplingModel(modelId);
@@ -63,9 +81,7 @@ export function buildOpenAIChatRequest(modelId, providerName, options, stream, w
63
81
  ...(options.stopSequences && options.stopSequences.length > 0
64
82
  ? { stop: [...options.stopSequences] }
65
83
  : {}),
66
- ...(toOpenAICompatibleTools(options.tools)
67
- ? { tools: toOpenAICompatibleTools(options.tools) }
68
- : {}),
84
+ ...(tools ? { tools } : {}),
69
85
  ...(options.toolChoice !== undefined ? { tool_choice: options.toolChoice } : {}),
70
86
  ...(options.seed !== undefined ? { seed: options.seed } : {}),
71
87
  ...(!dropSamplingParams && options.presencePenalty !== undefined
@@ -100,19 +116,6 @@ export function buildOpenAIChatRequest(modelId, providerName, options, stream, w
100
116
  }
101
117
  : {}),
102
118
  };
103
- // Env-BYOK users historically registered options under "openai-compatible";
104
- // keep merging that bucket at the lowest precedence. max_tokens is normalized
105
- // per bucket BEFORE merging so a higher-precedence bucket's max_tokens
106
- // override still beats a lower bucket's max_completion_tokens.
107
- const bucketNames = [
108
- ...(providerName === "openai" ? ["openai-compatible"] : []),
109
- "openai",
110
- providerName,
111
- ];
112
- const providerOpts = {};
113
- for (const bucketName of bucketNames) {
114
- defineOpenAIProviderOptions(providerOpts, normalizeNativeMaxTokens(readProviderOptions(options.providerOptions, bucketName), modelId));
115
- }
116
119
  defineOpenAIProviderOptions(body, providerOpts);
117
120
  // Provider-native options may tune request behavior, but they must not
118
121
  // replace the runtime-owned transport mode, model, or conversation.
@@ -126,8 +129,34 @@ export function buildOpenAIChatRequest(modelId, providerName, options, stream, w
126
129
  delete body.stream;
127
130
  delete body.stream_options;
128
131
  }
132
+ if (suppressReasoningForFunctionTools) {
133
+ if (resolvedReasoning !== undefined || body.reasoning_effort !== undefined) {
134
+ warnings.push({
135
+ type: "unsupported-setting",
136
+ provider: "openai",
137
+ setting: "reasoning",
138
+ details: "Veryfront drops reasoning because this Chat Completions transport " +
139
+ "does not support reasoning alongside function tools.",
140
+ });
141
+ }
142
+ delete body.reasoning_effort;
143
+ }
129
144
  return body;
130
145
  }
146
+ function hasOpenAIFunctionTools(value) {
147
+ if (!Array.isArray(value)) {
148
+ return false;
149
+ }
150
+ for (const tool of value) {
151
+ if (typeof tool === "object" &&
152
+ tool !== null &&
153
+ "type" in tool &&
154
+ tool.type === "function") {
155
+ return true;
156
+ }
157
+ }
158
+ return false;
159
+ }
131
160
  /** Normalizes max_tokens to max_completion_tokens for native OpenAI models. */
132
161
  function normalizeNativeMaxTokens(bucket, modelId) {
133
162
  if (!isNativeOpenAIModel(modelId) || !("max_tokens" in bucket)) {
@@ -1 +1 @@
1
- {"version":3,"file":"openai-chat-stream.d.ts","sourceRoot":"","sources":["../../../../src/extensions/ext-llm-openai/src/openai-chat-stream.ts"],"names":[],"mappings":"AA2BA,KAAK,4BAA4B,GAAG,QAAQ,GAAG,SAAS,GAAG,YAAY,CAAC;AAExE,KAAK,uBAAuB,GAAG;IAC7B,YAAY,CAAC,EAAE,4BAA4B,CAAC;IAC5C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AASF,eAAO,MAAM,4BAA4B,OAAQ,CAAC;AA4KlD,wBAAuB,2BAA2B,CAChD,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,OAAO,GAAE,uBAA4B,GACpC,aAAa,CAAC,OAAO,CAAC,CAsVxB"}
1
+ {"version":3,"file":"openai-chat-stream.d.ts","sourceRoot":"","sources":["../../../../src/extensions/ext-llm-openai/src/openai-chat-stream.ts"],"names":[],"mappings":"AA2BA,KAAK,4BAA4B,GAAG,QAAQ,GAAG,SAAS,GAAG,YAAY,CAAC;AAExE,KAAK,uBAAuB,GAAG;IAC7B,YAAY,CAAC,EAAE,4BAA4B,CAAC;IAC5C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AASF,eAAO,MAAM,4BAA4B,OAAQ,CAAC;AA4KlD,wBAAuB,2BAA2B,CAChD,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,OAAO,GAAE,uBAA4B,GACpC,aAAa,CAAC,OAAO,CAAC,CAyVxB"}
@@ -186,10 +186,13 @@ export async function* streamOpenAICompatibleParts(stream, context = {}) {
186
186
  if (!Array.isArray(record.choices)) {
187
187
  throw invalidOpenAIStream(context, "choices was not an array");
188
188
  }
189
+ // An empty `choices` array carries no content. Usage-only frames use this
190
+ // shape, and so does Azure OpenAI's `prompt_filter_results` preamble, which
191
+ // arrives before the first content chunk with neither choices nor usage.
192
+ // Both are informational, so skip the frame instead of failing the stream.
193
+ // The `choices` key being absent entirely is still rejected above — that is
194
+ // a malformed event rather than a content-free one.
189
195
  if (record.choices.length === 0) {
190
- if (!usageRecord) {
191
- throw invalidOpenAIStream(context, "empty choices event had no usage");
192
- }
193
196
  return;
194
197
  }
195
198
  if (sawFinishReason) {
@@ -10,7 +10,7 @@
10
10
  import type { LLMProvider, LLMProviderConfig } from "veryfront/extensions/llm";
11
11
  import type { EmbeddingRuntime, ModelRuntime, RuntimeAssistantContentPart } from "veryfront/provider/types";
12
12
  import { buildProviderError, isNumberArray, mergeUsage, parseRetryAfterMs, ProviderError, ProviderOverloadedError, ProviderQuotaError, ProviderRateLimitError, ProviderRequestError, TOOL_INPUT_PENDING_THRESHOLD_MS } from "veryfront/provider/shared";
13
- import { type OpenAICompatibleLanguageOptions } from "./openai-chat-request-builder.js";
13
+ import { type OpenAIChatRequestCapabilities, type OpenAICompatibleLanguageOptions } from "./openai-chat-request-builder.js";
14
14
  export { buildProviderError, isNumberArray, mergeUsage, parseRetryAfterMs, ProviderError, ProviderOverloadedError, ProviderQuotaError, ProviderRateLimitError, ProviderRequestError, TOOL_INPUT_PENDING_THRESHOLD_MS, };
15
15
  export interface OpenAIRuntimeConfig {
16
16
  apiKey: string;
@@ -19,6 +19,7 @@ export interface OpenAIRuntimeConfig {
19
19
  name?: string;
20
20
  /** Provider identity for OpenAI request defaults. Defaults to `name` in low-level factories. */
21
21
  providerName?: string;
22
+ chatRequestCapabilities?: OpenAIChatRequestCapabilities;
22
23
  fetch?: typeof globalThis.fetch;
23
24
  }
24
25
  export declare function createOpenAIModelRuntime(config: OpenAIRuntimeConfig, modelId: string): ModelRuntime<OpenAICompatibleLanguageOptions, RuntimeAssistantContentPart>;
@@ -1 +1 @@
1
- {"version":3,"file":"openai-provider.d.ts","sourceRoot":"","sources":["../../../../src/extensions/ext-llm-openai/src/openai-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACZ,2BAA2B,EAC5B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,kBAAkB,EAMlB,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,aAAa,EACb,uBAAuB,EACvB,kBAAkB,EAClB,sBAAsB,EACtB,oBAAoB,EAOpB,+BAA+B,EAChC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAEL,KAAK,+BAA+B,EACrC,MAAM,kCAAkC,CAAC;AA2B1C,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,aAAa,EACb,uBAAuB,EACvB,kBAAkB,EAClB,sBAAsB,EACtB,oBAAoB,EACpB,+BAA+B,GAChC,CAAC;AAEF,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gGAAgG;IAChG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AA26BD,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,MAAM,GACd,YAAY,CAAC,+BAA+B,EAAE,2BAA2B,CAAC,CAgF5E;AAED,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,MAAM,GACd,YAAY,CAAC,+BAA+B,EAAE,2BAA2B,CAAC,CA0F5E;AAgCD,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,MAAM,GACd,gBAAgB,CA2ClB;AAED,qBAAa,cAAe,YAAW,WAAW;IAChD,QAAQ,CAAC,EAAE,YAAY;IAEvB,WAAW,CACT,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,iBAAiB,GACxB,YAAY,CAAC,+BAA+B,EAAE,2BAA2B,CAAC;IAwB7E,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,GAAG,gBAAgB;IAa7E,eAAe,CACb,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,iBAAiB,GACxB,YAAY,CAAC,+BAA+B,EAAE,2BAA2B,CAAC;CAY9E"}
1
+ {"version":3,"file":"openai-provider.d.ts","sourceRoot":"","sources":["../../../../src/extensions/ext-llm-openai/src/openai-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACZ,2BAA2B,EAC5B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,kBAAkB,EAMlB,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,aAAa,EACb,uBAAuB,EACvB,kBAAkB,EAClB,sBAAsB,EACtB,oBAAoB,EAOpB,+BAA+B,EAChC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAEL,KAAK,6BAA6B,EAClC,KAAK,+BAA+B,EACrC,MAAM,kCAAkC,CAAC;AA2B1C,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,aAAa,EACb,uBAAuB,EACvB,kBAAkB,EAClB,sBAAsB,EACtB,oBAAoB,EACpB,+BAA+B,GAChC,CAAC;AAEF,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gGAAgG;IAChG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uBAAuB,CAAC,EAAE,6BAA6B,CAAC;IACxD,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAs7BD,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,MAAM,GACd,YAAY,CAAC,+BAA+B,EAAE,2BAA2B,CAAC,CAkF5E;AAED,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,MAAM,GACd,YAAY,CAAC,+BAA+B,EAAE,2BAA2B,CAAC,CA0F5E;AAwDD,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,MAAM,GACd,gBAAgB,CA2ClB;AAED,qBAAa,cAAe,YAAW,WAAW;IAChD,QAAQ,CAAC,EAAE,YAAY;IAEvB,WAAW,CACT,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,iBAAiB,GACxB,YAAY,CAAC,+BAA+B,EAAE,2BAA2B,CAAC;IAqC7E,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,GAAG,gBAAgB;IAa7E,eAAe,CACb,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,iBAAiB,GACxB,YAAY,CAAC,+BAA+B,EAAE,2BAA2B,CAAC;CAY9E"}
@@ -38,6 +38,15 @@ function getRuntimeOpenAIProviderName(config) {
38
38
  function getLLMOpenAIProviderName(config) {
39
39
  return normalizeOpenAIProviderName(config.providerName) ?? "openai";
40
40
  }
41
+ function getOpenAIModelTransport(config) {
42
+ const transport = config.openAITransport;
43
+ if (transport === undefined)
44
+ return "auto";
45
+ if (transport === "chat-completions" || transport === "responses") {
46
+ return transport;
47
+ }
48
+ throw new TypeError('OpenAI transport must be "chat-completions" or "responses"');
49
+ }
41
50
  function getOpenAICompatibleProviderKind(config) {
42
51
  const providerName = getRuntimeOpenAIProviderName(config).trim().toLowerCase();
43
52
  return providerName === "mistral" || providerName === "moonshotai" ? providerName : "openai";
@@ -697,7 +706,7 @@ export function createOpenAIModelRuntime(config, modelId) {
697
706
  doGenerate(options) {
698
707
  const url = getOpenAIChatCompletionsUrl(config.baseURL);
699
708
  const warnings = createWarningCollector();
700
- const body = buildOpenAIChatRequest(modelId, providerName, options, false, warnings);
709
+ const body = buildOpenAIChatRequest(modelId, providerName, options, false, warnings, config.chatRequestCapabilities);
701
710
  return requestJson({
702
711
  url,
703
712
  fetchImpl,
@@ -720,7 +729,7 @@ export function createOpenAIModelRuntime(config, modelId) {
720
729
  async doStream(options) {
721
730
  const url = getOpenAIChatCompletionsUrl(config.baseURL);
722
731
  const warnings = createWarningCollector();
723
- const body = buildOpenAIChatRequest(modelId, providerName, options, true, warnings);
732
+ const body = buildOpenAIChatRequest(modelId, providerName, options, true, warnings, config.chatRequestCapabilities);
724
733
  const providerAbortScope = createOpenAIProviderAbortScope(options.abortSignal);
725
734
  try {
726
735
  const responseStream = await requestStream({
@@ -829,6 +838,24 @@ function requestUsesOpenAIHostedTool(optionsForRuntime) {
829
838
  }
830
839
  return resolveOpenAIWebSearchDescriptor(options.tools) !== undefined;
831
840
  }
841
+ function createOpenAIChatCompletionsOnlyRuntime(chatRuntime) {
842
+ function assertHostedToolsSupported(options) {
843
+ if (requestUsesOpenAIHostedTool(options)) {
844
+ throw new TypeError("OpenAI hosted tools require the Responses API and are unavailable with Chat Completions");
845
+ }
846
+ }
847
+ return {
848
+ ...chatRuntime,
849
+ async doGenerate(optionsForRuntime) {
850
+ assertHostedToolsSupported(optionsForRuntime);
851
+ return await chatRuntime.doGenerate(optionsForRuntime);
852
+ },
853
+ async doStream(optionsForRuntime) {
854
+ assertHostedToolsSupported(optionsForRuntime);
855
+ return await chatRuntime.doStream(optionsForRuntime);
856
+ },
857
+ };
858
+ }
832
859
  function createOpenAIAdaptiveModelRuntime(chatRuntime, responsesRuntime) {
833
860
  return {
834
861
  ...chatRuntime,
@@ -897,13 +924,24 @@ export class OpenAIProvider {
897
924
  baseURL: config.baseURL,
898
925
  name: providerLabel,
899
926
  providerName,
927
+ chatRequestCapabilities: typeof config.openAIChatReasoningWithFunctionTools === "boolean"
928
+ ? {
929
+ reasoningWithFunctionTools: config.openAIChatReasoningWithFunctionTools,
930
+ }
931
+ : undefined,
900
932
  fetch: config.fetch,
901
933
  };
902
934
  const responsesRuntime = createOpenAIResponsesRuntime(runtimeConfig, modelId);
903
- if (isOpenAIReasoningModel(modelId, providerName)) {
935
+ const chatRuntime = createOpenAIModelRuntime(runtimeConfig, modelId);
936
+ const transport = getOpenAIModelTransport(config);
937
+ if (transport === "responses" ||
938
+ (transport === "auto" && isOpenAIReasoningModel(modelId, providerName))) {
904
939
  return responsesRuntime;
905
940
  }
906
- return createOpenAIAdaptiveModelRuntime(createOpenAIModelRuntime(runtimeConfig, modelId), responsesRuntime);
941
+ if (transport === "chat-completions") {
942
+ return createOpenAIChatCompletionsOnlyRuntime(chatRuntime);
943
+ }
944
+ return createOpenAIAdaptiveModelRuntime(chatRuntime, responsesRuntime);
907
945
  }
908
946
  createEmbedding(modelId, config) {
909
947
  return createOpenAIEmbeddingRuntime({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@veryfront/ext-llm-openai",
3
- "version": "0.1.1241",
3
+ "version": "0.1.1243",
4
4
  "description": "Veryfront first-party extension package for ext-llm-openai",
5
5
  "keywords": [
6
6
  "veryfront",
@@ -45,7 +45,7 @@
45
45
  "capabilities": []
46
46
  },
47
47
  "peerDependencies": {
48
- "veryfront": "^0.1.1241"
48
+ "veryfront": "^0.1.1243"
49
49
  },
50
50
  "type": "module",
51
51
  "types": "./esm/extensions/ext-llm-openai/src/index.d.ts",