@aigne/openai 0.16.4-beta.4 → 0.16.4-beta.6
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 +32 -0
- package/lib/cjs/openai-chat-model.d.ts +3 -2
- package/lib/cjs/openai-chat-model.js +42 -19
- package/lib/cjs/openai-video-model.d.ts +24 -4
- package/lib/cjs/openai-video-model.js +8 -5
- package/lib/dts/openai-chat-model.d.ts +3 -2
- package/lib/dts/openai-video-model.d.ts +24 -4
- package/lib/esm/openai-chat-model.d.ts +3 -2
- package/lib/esm/openai-chat-model.js +42 -19
- package/lib/esm/openai-video-model.d.ts +24 -4
- package/lib/esm/openai-video-model.js +8 -5
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.16.4-beta.6](https://github.com/AIGNE-io/aigne-framework/compare/openai-v0.16.4-beta.5...openai-v0.16.4-beta.6) (2025-10-31)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **models:** add image parameters support for video generation ([#684](https://github.com/AIGNE-io/aigne-framework/issues/684)) ([b048b7f](https://github.com/AIGNE-io/aigne-framework/commit/b048b7f92bd7a532dbdbeb6fb5fa5499bae6b953))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* dependencies
|
|
15
|
+
* @aigne/core bumped to 1.65.0-beta.5
|
|
16
|
+
* devDependencies
|
|
17
|
+
* @aigne/test-utils bumped to 0.5.57-beta.6
|
|
18
|
+
|
|
19
|
+
## [0.16.4-beta.5](https://github.com/AIGNE-io/aigne-framework/compare/openai-v0.16.4-beta.4...openai-v0.16.4-beta.5) (2025-10-29)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Features
|
|
23
|
+
|
|
24
|
+
* add reasoningEffort option for chat model ([#680](https://github.com/AIGNE-io/aigne-framework/issues/680)) ([f69d232](https://github.com/AIGNE-io/aigne-framework/commit/f69d232d714d4a3e4946bdc8c6598747c9bcbd57))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Dependencies
|
|
28
|
+
|
|
29
|
+
* The following workspace dependencies were updated
|
|
30
|
+
* dependencies
|
|
31
|
+
* @aigne/core bumped to 1.65.0-beta.4
|
|
32
|
+
* devDependencies
|
|
33
|
+
* @aigne/test-utils bumped to 0.5.57-beta.5
|
|
34
|
+
|
|
3
35
|
## [0.16.4-beta.4](https://github.com/AIGNE-io/aigne-framework/compare/openai-v0.16.4-beta.3...openai-v0.16.4-beta.4) (2025-10-28)
|
|
4
36
|
|
|
5
37
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AgentInvokeOptions, type AgentProcessResult, ChatModel, type ChatModelInput, type ChatModelInputMessage, type ChatModelInputTool, type ChatModelOptions, type ChatModelOutput } from "@aigne/core";
|
|
1
|
+
import { type AgentInvokeOptions, type AgentProcessResult, ChatModel, type ChatModelInput, type ChatModelInputMessage, type ChatModelInputOptions, type ChatModelInputTool, type ChatModelOptions, type ChatModelOutput } from "@aigne/core";
|
|
2
2
|
import { type PromiseOrValue } from "@aigne/core/utils/type-utils.js";
|
|
3
3
|
import type { ClientOptions, OpenAI } from "openai";
|
|
4
4
|
import type { ChatCompletionMessageParam, ChatCompletionTool } from "openai/resources";
|
|
@@ -127,13 +127,14 @@ export declare class OpenAIChatModel extends ChatModel {
|
|
|
127
127
|
apiKey: string | undefined;
|
|
128
128
|
model: string;
|
|
129
129
|
};
|
|
130
|
-
get modelOptions(): Omit<
|
|
130
|
+
get modelOptions(): Omit<ChatModelInputOptions, "model"> | undefined;
|
|
131
131
|
/**
|
|
132
132
|
* Process the input and generate a response
|
|
133
133
|
* @param input The input to process
|
|
134
134
|
* @returns The generated response
|
|
135
135
|
*/
|
|
136
136
|
process(input: ChatModelInput, _options: AgentInvokeOptions): PromiseOrValue<AgentProcessResult<ChatModelOutput>>;
|
|
137
|
+
private getReasoningEffort;
|
|
137
138
|
private _process;
|
|
138
139
|
private getParallelToolCalls;
|
|
139
140
|
protected getRunMessages(input: ChatModelInput): Promise<ChatCompletionMessageParam[]>;
|
|
@@ -105,6 +105,20 @@ class OpenAIChatModel extends core_1.ChatModel {
|
|
|
105
105
|
process(input, _options) {
|
|
106
106
|
return this._process(input);
|
|
107
107
|
}
|
|
108
|
+
getReasoningEffort(effort) {
|
|
109
|
+
if (typeof effort === "number") {
|
|
110
|
+
if (effort > 5000)
|
|
111
|
+
return "high";
|
|
112
|
+
if (effort > 1000)
|
|
113
|
+
return "medium";
|
|
114
|
+
if (effort > 500)
|
|
115
|
+
return "low";
|
|
116
|
+
if (effort > 0)
|
|
117
|
+
return "minimal";
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
return effort;
|
|
121
|
+
}
|
|
108
122
|
async _process(input) {
|
|
109
123
|
const messages = await this.getRunMessages(input);
|
|
110
124
|
const model = input.modelOptions?.model || this.credential.model;
|
|
@@ -121,6 +135,7 @@ class OpenAIChatModel extends core_1.ChatModel {
|
|
|
121
135
|
include_usage: true,
|
|
122
136
|
},
|
|
123
137
|
stream: true,
|
|
138
|
+
reasoning_effort: this.getReasoningEffort(input.modelOptions?.reasoningEffort ?? this.modelOptions?.reasoningEffort),
|
|
124
139
|
};
|
|
125
140
|
// For models that do not support tools use with JSON schema in same request,
|
|
126
141
|
// so we need to handle the case where tools are not used and responseFormat is json
|
|
@@ -138,9 +153,9 @@ class OpenAIChatModel extends core_1.ChatModel {
|
|
|
138
153
|
response_format: responseFormat,
|
|
139
154
|
}));
|
|
140
155
|
if (input.responseFormat?.type !== "json_schema") {
|
|
141
|
-
return await this.extractResultFromStream(stream, false, true);
|
|
156
|
+
return await this.extractResultFromStream(body, stream, false, true);
|
|
142
157
|
}
|
|
143
|
-
const result = await this.extractResultFromStream(stream, jsonMode);
|
|
158
|
+
const result = await this.extractResultFromStream(body, stream, jsonMode);
|
|
144
159
|
// Just return the result if it has tool calls
|
|
145
160
|
if (result.toolCalls?.length || result.json)
|
|
146
161
|
return result;
|
|
@@ -214,18 +229,28 @@ class OpenAIChatModel extends core_1.ChatModel {
|
|
|
214
229
|
...body,
|
|
215
230
|
response_format: resolvedResponseFormat,
|
|
216
231
|
}));
|
|
217
|
-
return this.extractResultFromStream(res, jsonMode);
|
|
232
|
+
return this.extractResultFromStream(body, res, jsonMode);
|
|
218
233
|
}
|
|
219
|
-
async extractResultFromStream(stream, jsonMode, streaming) {
|
|
234
|
+
async extractResultFromStream(body, stream, jsonMode, streaming) {
|
|
220
235
|
const result = new ReadableStream({
|
|
221
236
|
start: async (controller) => {
|
|
222
237
|
try {
|
|
238
|
+
controller.enqueue({
|
|
239
|
+
delta: {
|
|
240
|
+
json: {
|
|
241
|
+
modelOptions: {
|
|
242
|
+
reasoningEffort: body.reasoning_effort,
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
});
|
|
223
247
|
let text = "";
|
|
224
248
|
let refusal = "";
|
|
225
249
|
const toolCalls = [];
|
|
226
250
|
let model;
|
|
227
251
|
for await (const chunk of stream) {
|
|
228
252
|
const choice = chunk.choices?.[0];
|
|
253
|
+
const delta = choice?.delta;
|
|
229
254
|
if (!model) {
|
|
230
255
|
model = chunk.model;
|
|
231
256
|
controller.enqueue({
|
|
@@ -236,8 +261,8 @@ class OpenAIChatModel extends core_1.ChatModel {
|
|
|
236
261
|
},
|
|
237
262
|
});
|
|
238
263
|
}
|
|
239
|
-
if (
|
|
240
|
-
for (const call of
|
|
264
|
+
if (delta?.tool_calls?.length) {
|
|
265
|
+
for (const call of delta.tool_calls) {
|
|
241
266
|
if (this.supportsToolStreaming && call.index !== undefined) {
|
|
242
267
|
handleToolCallDelta(toolCalls, call);
|
|
243
268
|
}
|
|
@@ -246,27 +271,23 @@ class OpenAIChatModel extends core_1.ChatModel {
|
|
|
246
271
|
}
|
|
247
272
|
}
|
|
248
273
|
}
|
|
249
|
-
if (
|
|
250
|
-
text
|
|
274
|
+
if (delta && "reasoning" in delta && typeof delta.reasoning === "string") {
|
|
275
|
+
controller.enqueue({ delta: { text: { thoughts: delta.reasoning } } });
|
|
276
|
+
}
|
|
277
|
+
if (delta?.content) {
|
|
278
|
+
text += delta.content;
|
|
251
279
|
if (!jsonMode) {
|
|
252
280
|
controller.enqueue({
|
|
253
281
|
delta: {
|
|
254
282
|
text: {
|
|
255
|
-
text:
|
|
283
|
+
text: delta.content,
|
|
256
284
|
},
|
|
257
285
|
},
|
|
258
286
|
});
|
|
259
287
|
}
|
|
260
288
|
}
|
|
261
|
-
if (
|
|
262
|
-
refusal +=
|
|
263
|
-
if (!jsonMode) {
|
|
264
|
-
controller.enqueue({
|
|
265
|
-
delta: {
|
|
266
|
-
text: { text: choice.delta.refusal },
|
|
267
|
-
},
|
|
268
|
-
});
|
|
269
|
-
}
|
|
289
|
+
if (delta?.refusal) {
|
|
290
|
+
refusal += delta.refusal;
|
|
270
291
|
}
|
|
271
292
|
if (chunk.usage) {
|
|
272
293
|
controller.enqueue({
|
|
@@ -281,7 +302,6 @@ class OpenAIChatModel extends core_1.ChatModel {
|
|
|
281
302
|
});
|
|
282
303
|
}
|
|
283
304
|
}
|
|
284
|
-
text = text || refusal;
|
|
285
305
|
if (jsonMode && text) {
|
|
286
306
|
controller.enqueue({
|
|
287
307
|
delta: {
|
|
@@ -303,6 +323,9 @@ class OpenAIChatModel extends core_1.ChatModel {
|
|
|
303
323
|
},
|
|
304
324
|
});
|
|
305
325
|
}
|
|
326
|
+
if (refusal) {
|
|
327
|
+
controller.error(new Error(`Got refusal from LLM: ${refusal}`));
|
|
328
|
+
}
|
|
306
329
|
controller.close();
|
|
307
330
|
}
|
|
308
331
|
catch (error) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { VideoModel, type VideoModelInput, type VideoModelOptions, type VideoModelOutput } from "@aigne/core";
|
|
1
|
+
import { type AgentInvokeOptions, VideoModel, type VideoModelInput, type VideoModelOptions, type VideoModelOutput } from "@aigne/core";
|
|
2
2
|
import type OpenAI from "openai";
|
|
3
3
|
import type { ClientOptions } from "openai";
|
|
4
4
|
/**
|
|
@@ -6,9 +6,29 @@ import type { ClientOptions } from "openai";
|
|
|
6
6
|
*/
|
|
7
7
|
export interface OpenAIVideoModelInput extends VideoModelInput {
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
9
|
+
* Sora model to use for video generation
|
|
10
|
+
*
|
|
11
|
+
* - `sora-2`: Standard version, lower cost
|
|
12
|
+
* - `sora-2-pro`: Pro version, higher quality
|
|
13
|
+
*
|
|
14
|
+
* @default "sora-2"
|
|
15
|
+
*/
|
|
16
|
+
model?: "sora-2" | "sora-2-pro";
|
|
17
|
+
/**
|
|
18
|
+
* Video resolution (width x height)
|
|
19
|
+
*
|
|
20
|
+
* - `720x1280`: Vertical video (9:16)
|
|
21
|
+
* - `1280x720`: Horizontal video (16:9)
|
|
22
|
+
* - `1024x1792`: Vertical video (9:16, higher resolution)
|
|
23
|
+
* - `1792x1024`: Horizontal video (16:9, higher resolution)
|
|
24
|
+
*/
|
|
25
|
+
size?: "720x1280" | "1280x720" | "1024x1792" | "1792x1024";
|
|
26
|
+
/**
|
|
27
|
+
* Video duration in seconds
|
|
28
|
+
*
|
|
29
|
+
* @default "4"
|
|
10
30
|
*/
|
|
11
|
-
|
|
31
|
+
seconds?: "4" | "8" | "12";
|
|
12
32
|
}
|
|
13
33
|
/**
|
|
14
34
|
* Output from OpenAI Video Model
|
|
@@ -68,5 +88,5 @@ export declare class OpenAIVideoModel extends VideoModel<OpenAIVideoModelInput,
|
|
|
68
88
|
};
|
|
69
89
|
get modelOptions(): Omit<Partial<OpenAIVideoModelInput>, "model"> | undefined;
|
|
70
90
|
downloadToFile(videoId: string): Promise<string>;
|
|
71
|
-
process(input: OpenAIVideoModelInput): Promise<OpenAIVideoModelOutput>;
|
|
91
|
+
process(input: OpenAIVideoModelInput, options: AgentInvokeOptions): Promise<OpenAIVideoModelOutput>;
|
|
72
92
|
}
|
|
@@ -9,7 +9,9 @@ const openai_js_1 = require("./openai.js");
|
|
|
9
9
|
const DEFAULT_MODEL = "sora-2";
|
|
10
10
|
const DEFAULT_SECONDS = 4;
|
|
11
11
|
const openAIVideoModelInputSchema = core_1.videoModelInputSchema.extend({
|
|
12
|
-
|
|
12
|
+
model: zod_1.z.enum(["sora-2", "sora-2-pro"]).optional(),
|
|
13
|
+
seconds: zod_1.z.enum(["4", "8", "12"]).optional(),
|
|
14
|
+
size: zod_1.z.enum(["720x1280", "1280x720", "1024x1792", "1792x1024"]).optional(),
|
|
13
15
|
});
|
|
14
16
|
const openAIVideoModelOptionsSchema = zod_1.z.object({
|
|
15
17
|
apiKey: zod_1.z.string().optional(),
|
|
@@ -64,7 +66,7 @@ class OpenAIVideoModel extends core_1.VideoModel {
|
|
|
64
66
|
const buffer = Buffer.from(arrayBuffer);
|
|
65
67
|
return buffer.toString("base64");
|
|
66
68
|
}
|
|
67
|
-
async process(input) {
|
|
69
|
+
async process(input, options) {
|
|
68
70
|
const model = input.model ?? input.modelOptions?.model ?? this.credential.model;
|
|
69
71
|
const createParams = {
|
|
70
72
|
model: model,
|
|
@@ -74,9 +76,10 @@ class OpenAIVideoModel extends core_1.VideoModel {
|
|
|
74
76
|
createParams.seconds = input.seconds;
|
|
75
77
|
if (input.size)
|
|
76
78
|
createParams.size = input.size;
|
|
77
|
-
if (input.
|
|
78
|
-
createParams.input_reference =
|
|
79
|
-
|
|
79
|
+
if (input.image) {
|
|
80
|
+
createParams.input_reference = await this.transformFileType("file", input.image, options).then((file) => new File([Buffer.from(file.data, "base64")], file.filename || "image.png", {
|
|
81
|
+
type: file.mimeType,
|
|
82
|
+
}));
|
|
80
83
|
}
|
|
81
84
|
let video = await this.client.videos.create(createParams);
|
|
82
85
|
logger_js_1.logger.debug(`Video generation started: ${video.id}`);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AgentInvokeOptions, type AgentProcessResult, ChatModel, type ChatModelInput, type ChatModelInputMessage, type ChatModelInputTool, type ChatModelOptions, type ChatModelOutput } from "@aigne/core";
|
|
1
|
+
import { type AgentInvokeOptions, type AgentProcessResult, ChatModel, type ChatModelInput, type ChatModelInputMessage, type ChatModelInputOptions, type ChatModelInputTool, type ChatModelOptions, type ChatModelOutput } from "@aigne/core";
|
|
2
2
|
import { type PromiseOrValue } from "@aigne/core/utils/type-utils.js";
|
|
3
3
|
import type { ClientOptions, OpenAI } from "openai";
|
|
4
4
|
import type { ChatCompletionMessageParam, ChatCompletionTool } from "openai/resources";
|
|
@@ -127,13 +127,14 @@ export declare class OpenAIChatModel extends ChatModel {
|
|
|
127
127
|
apiKey: string | undefined;
|
|
128
128
|
model: string;
|
|
129
129
|
};
|
|
130
|
-
get modelOptions(): Omit<
|
|
130
|
+
get modelOptions(): Omit<ChatModelInputOptions, "model"> | undefined;
|
|
131
131
|
/**
|
|
132
132
|
* Process the input and generate a response
|
|
133
133
|
* @param input The input to process
|
|
134
134
|
* @returns The generated response
|
|
135
135
|
*/
|
|
136
136
|
process(input: ChatModelInput, _options: AgentInvokeOptions): PromiseOrValue<AgentProcessResult<ChatModelOutput>>;
|
|
137
|
+
private getReasoningEffort;
|
|
137
138
|
private _process;
|
|
138
139
|
private getParallelToolCalls;
|
|
139
140
|
protected getRunMessages(input: ChatModelInput): Promise<ChatCompletionMessageParam[]>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { VideoModel, type VideoModelInput, type VideoModelOptions, type VideoModelOutput } from "@aigne/core";
|
|
1
|
+
import { type AgentInvokeOptions, VideoModel, type VideoModelInput, type VideoModelOptions, type VideoModelOutput } from "@aigne/core";
|
|
2
2
|
import type OpenAI from "openai";
|
|
3
3
|
import type { ClientOptions } from "openai";
|
|
4
4
|
/**
|
|
@@ -6,9 +6,29 @@ import type { ClientOptions } from "openai";
|
|
|
6
6
|
*/
|
|
7
7
|
export interface OpenAIVideoModelInput extends VideoModelInput {
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
9
|
+
* Sora model to use for video generation
|
|
10
|
+
*
|
|
11
|
+
* - `sora-2`: Standard version, lower cost
|
|
12
|
+
* - `sora-2-pro`: Pro version, higher quality
|
|
13
|
+
*
|
|
14
|
+
* @default "sora-2"
|
|
15
|
+
*/
|
|
16
|
+
model?: "sora-2" | "sora-2-pro";
|
|
17
|
+
/**
|
|
18
|
+
* Video resolution (width x height)
|
|
19
|
+
*
|
|
20
|
+
* - `720x1280`: Vertical video (9:16)
|
|
21
|
+
* - `1280x720`: Horizontal video (16:9)
|
|
22
|
+
* - `1024x1792`: Vertical video (9:16, higher resolution)
|
|
23
|
+
* - `1792x1024`: Horizontal video (16:9, higher resolution)
|
|
24
|
+
*/
|
|
25
|
+
size?: "720x1280" | "1280x720" | "1024x1792" | "1792x1024";
|
|
26
|
+
/**
|
|
27
|
+
* Video duration in seconds
|
|
28
|
+
*
|
|
29
|
+
* @default "4"
|
|
10
30
|
*/
|
|
11
|
-
|
|
31
|
+
seconds?: "4" | "8" | "12";
|
|
12
32
|
}
|
|
13
33
|
/**
|
|
14
34
|
* Output from OpenAI Video Model
|
|
@@ -68,5 +88,5 @@ export declare class OpenAIVideoModel extends VideoModel<OpenAIVideoModelInput,
|
|
|
68
88
|
};
|
|
69
89
|
get modelOptions(): Omit<Partial<OpenAIVideoModelInput>, "model"> | undefined;
|
|
70
90
|
downloadToFile(videoId: string): Promise<string>;
|
|
71
|
-
process(input: OpenAIVideoModelInput): Promise<OpenAIVideoModelOutput>;
|
|
91
|
+
process(input: OpenAIVideoModelInput, options: AgentInvokeOptions): Promise<OpenAIVideoModelOutput>;
|
|
72
92
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AgentInvokeOptions, type AgentProcessResult, ChatModel, type ChatModelInput, type ChatModelInputMessage, type ChatModelInputTool, type ChatModelOptions, type ChatModelOutput } from "@aigne/core";
|
|
1
|
+
import { type AgentInvokeOptions, type AgentProcessResult, ChatModel, type ChatModelInput, type ChatModelInputMessage, type ChatModelInputOptions, type ChatModelInputTool, type ChatModelOptions, type ChatModelOutput } from "@aigne/core";
|
|
2
2
|
import { type PromiseOrValue } from "@aigne/core/utils/type-utils.js";
|
|
3
3
|
import type { ClientOptions, OpenAI } from "openai";
|
|
4
4
|
import type { ChatCompletionMessageParam, ChatCompletionTool } from "openai/resources";
|
|
@@ -127,13 +127,14 @@ export declare class OpenAIChatModel extends ChatModel {
|
|
|
127
127
|
apiKey: string | undefined;
|
|
128
128
|
model: string;
|
|
129
129
|
};
|
|
130
|
-
get modelOptions(): Omit<
|
|
130
|
+
get modelOptions(): Omit<ChatModelInputOptions, "model"> | undefined;
|
|
131
131
|
/**
|
|
132
132
|
* Process the input and generate a response
|
|
133
133
|
* @param input The input to process
|
|
134
134
|
* @returns The generated response
|
|
135
135
|
*/
|
|
136
136
|
process(input: ChatModelInput, _options: AgentInvokeOptions): PromiseOrValue<AgentProcessResult<ChatModelOutput>>;
|
|
137
|
+
private getReasoningEffort;
|
|
137
138
|
private _process;
|
|
138
139
|
private getParallelToolCalls;
|
|
139
140
|
protected getRunMessages(input: ChatModelInput): Promise<ChatCompletionMessageParam[]>;
|
|
@@ -100,6 +100,20 @@ export class OpenAIChatModel extends ChatModel {
|
|
|
100
100
|
process(input, _options) {
|
|
101
101
|
return this._process(input);
|
|
102
102
|
}
|
|
103
|
+
getReasoningEffort(effort) {
|
|
104
|
+
if (typeof effort === "number") {
|
|
105
|
+
if (effort > 5000)
|
|
106
|
+
return "high";
|
|
107
|
+
if (effort > 1000)
|
|
108
|
+
return "medium";
|
|
109
|
+
if (effort > 500)
|
|
110
|
+
return "low";
|
|
111
|
+
if (effort > 0)
|
|
112
|
+
return "minimal";
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
return effort;
|
|
116
|
+
}
|
|
103
117
|
async _process(input) {
|
|
104
118
|
const messages = await this.getRunMessages(input);
|
|
105
119
|
const model = input.modelOptions?.model || this.credential.model;
|
|
@@ -116,6 +130,7 @@ export class OpenAIChatModel extends ChatModel {
|
|
|
116
130
|
include_usage: true,
|
|
117
131
|
},
|
|
118
132
|
stream: true,
|
|
133
|
+
reasoning_effort: this.getReasoningEffort(input.modelOptions?.reasoningEffort ?? this.modelOptions?.reasoningEffort),
|
|
119
134
|
};
|
|
120
135
|
// For models that do not support tools use with JSON schema in same request,
|
|
121
136
|
// so we need to handle the case where tools are not used and responseFormat is json
|
|
@@ -133,9 +148,9 @@ export class OpenAIChatModel extends ChatModel {
|
|
|
133
148
|
response_format: responseFormat,
|
|
134
149
|
}));
|
|
135
150
|
if (input.responseFormat?.type !== "json_schema") {
|
|
136
|
-
return await this.extractResultFromStream(stream, false, true);
|
|
151
|
+
return await this.extractResultFromStream(body, stream, false, true);
|
|
137
152
|
}
|
|
138
|
-
const result = await this.extractResultFromStream(stream, jsonMode);
|
|
153
|
+
const result = await this.extractResultFromStream(body, stream, jsonMode);
|
|
139
154
|
// Just return the result if it has tool calls
|
|
140
155
|
if (result.toolCalls?.length || result.json)
|
|
141
156
|
return result;
|
|
@@ -209,18 +224,28 @@ export class OpenAIChatModel extends ChatModel {
|
|
|
209
224
|
...body,
|
|
210
225
|
response_format: resolvedResponseFormat,
|
|
211
226
|
}));
|
|
212
|
-
return this.extractResultFromStream(res, jsonMode);
|
|
227
|
+
return this.extractResultFromStream(body, res, jsonMode);
|
|
213
228
|
}
|
|
214
|
-
async extractResultFromStream(stream, jsonMode, streaming) {
|
|
229
|
+
async extractResultFromStream(body, stream, jsonMode, streaming) {
|
|
215
230
|
const result = new ReadableStream({
|
|
216
231
|
start: async (controller) => {
|
|
217
232
|
try {
|
|
233
|
+
controller.enqueue({
|
|
234
|
+
delta: {
|
|
235
|
+
json: {
|
|
236
|
+
modelOptions: {
|
|
237
|
+
reasoningEffort: body.reasoning_effort,
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
});
|
|
218
242
|
let text = "";
|
|
219
243
|
let refusal = "";
|
|
220
244
|
const toolCalls = [];
|
|
221
245
|
let model;
|
|
222
246
|
for await (const chunk of stream) {
|
|
223
247
|
const choice = chunk.choices?.[0];
|
|
248
|
+
const delta = choice?.delta;
|
|
224
249
|
if (!model) {
|
|
225
250
|
model = chunk.model;
|
|
226
251
|
controller.enqueue({
|
|
@@ -231,8 +256,8 @@ export class OpenAIChatModel extends ChatModel {
|
|
|
231
256
|
},
|
|
232
257
|
});
|
|
233
258
|
}
|
|
234
|
-
if (
|
|
235
|
-
for (const call of
|
|
259
|
+
if (delta?.tool_calls?.length) {
|
|
260
|
+
for (const call of delta.tool_calls) {
|
|
236
261
|
if (this.supportsToolStreaming && call.index !== undefined) {
|
|
237
262
|
handleToolCallDelta(toolCalls, call);
|
|
238
263
|
}
|
|
@@ -241,27 +266,23 @@ export class OpenAIChatModel extends ChatModel {
|
|
|
241
266
|
}
|
|
242
267
|
}
|
|
243
268
|
}
|
|
244
|
-
if (
|
|
245
|
-
text
|
|
269
|
+
if (delta && "reasoning" in delta && typeof delta.reasoning === "string") {
|
|
270
|
+
controller.enqueue({ delta: { text: { thoughts: delta.reasoning } } });
|
|
271
|
+
}
|
|
272
|
+
if (delta?.content) {
|
|
273
|
+
text += delta.content;
|
|
246
274
|
if (!jsonMode) {
|
|
247
275
|
controller.enqueue({
|
|
248
276
|
delta: {
|
|
249
277
|
text: {
|
|
250
|
-
text:
|
|
278
|
+
text: delta.content,
|
|
251
279
|
},
|
|
252
280
|
},
|
|
253
281
|
});
|
|
254
282
|
}
|
|
255
283
|
}
|
|
256
|
-
if (
|
|
257
|
-
refusal +=
|
|
258
|
-
if (!jsonMode) {
|
|
259
|
-
controller.enqueue({
|
|
260
|
-
delta: {
|
|
261
|
-
text: { text: choice.delta.refusal },
|
|
262
|
-
},
|
|
263
|
-
});
|
|
264
|
-
}
|
|
284
|
+
if (delta?.refusal) {
|
|
285
|
+
refusal += delta.refusal;
|
|
265
286
|
}
|
|
266
287
|
if (chunk.usage) {
|
|
267
288
|
controller.enqueue({
|
|
@@ -276,7 +297,6 @@ export class OpenAIChatModel extends ChatModel {
|
|
|
276
297
|
});
|
|
277
298
|
}
|
|
278
299
|
}
|
|
279
|
-
text = text || refusal;
|
|
280
300
|
if (jsonMode && text) {
|
|
281
301
|
controller.enqueue({
|
|
282
302
|
delta: {
|
|
@@ -298,6 +318,9 @@ export class OpenAIChatModel extends ChatModel {
|
|
|
298
318
|
},
|
|
299
319
|
});
|
|
300
320
|
}
|
|
321
|
+
if (refusal) {
|
|
322
|
+
controller.error(new Error(`Got refusal from LLM: ${refusal}`));
|
|
323
|
+
}
|
|
301
324
|
controller.close();
|
|
302
325
|
}
|
|
303
326
|
catch (error) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { VideoModel, type VideoModelInput, type VideoModelOptions, type VideoModelOutput } from "@aigne/core";
|
|
1
|
+
import { type AgentInvokeOptions, VideoModel, type VideoModelInput, type VideoModelOptions, type VideoModelOutput } from "@aigne/core";
|
|
2
2
|
import type OpenAI from "openai";
|
|
3
3
|
import type { ClientOptions } from "openai";
|
|
4
4
|
/**
|
|
@@ -6,9 +6,29 @@ import type { ClientOptions } from "openai";
|
|
|
6
6
|
*/
|
|
7
7
|
export interface OpenAIVideoModelInput extends VideoModelInput {
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
9
|
+
* Sora model to use for video generation
|
|
10
|
+
*
|
|
11
|
+
* - `sora-2`: Standard version, lower cost
|
|
12
|
+
* - `sora-2-pro`: Pro version, higher quality
|
|
13
|
+
*
|
|
14
|
+
* @default "sora-2"
|
|
15
|
+
*/
|
|
16
|
+
model?: "sora-2" | "sora-2-pro";
|
|
17
|
+
/**
|
|
18
|
+
* Video resolution (width x height)
|
|
19
|
+
*
|
|
20
|
+
* - `720x1280`: Vertical video (9:16)
|
|
21
|
+
* - `1280x720`: Horizontal video (16:9)
|
|
22
|
+
* - `1024x1792`: Vertical video (9:16, higher resolution)
|
|
23
|
+
* - `1792x1024`: Horizontal video (16:9, higher resolution)
|
|
24
|
+
*/
|
|
25
|
+
size?: "720x1280" | "1280x720" | "1024x1792" | "1792x1024";
|
|
26
|
+
/**
|
|
27
|
+
* Video duration in seconds
|
|
28
|
+
*
|
|
29
|
+
* @default "4"
|
|
10
30
|
*/
|
|
11
|
-
|
|
31
|
+
seconds?: "4" | "8" | "12";
|
|
12
32
|
}
|
|
13
33
|
/**
|
|
14
34
|
* Output from OpenAI Video Model
|
|
@@ -68,5 +88,5 @@ export declare class OpenAIVideoModel extends VideoModel<OpenAIVideoModelInput,
|
|
|
68
88
|
};
|
|
69
89
|
get modelOptions(): Omit<Partial<OpenAIVideoModelInput>, "model"> | undefined;
|
|
70
90
|
downloadToFile(videoId: string): Promise<string>;
|
|
71
|
-
process(input: OpenAIVideoModelInput): Promise<OpenAIVideoModelOutput>;
|
|
91
|
+
process(input: OpenAIVideoModelInput, options: AgentInvokeOptions): Promise<OpenAIVideoModelOutput>;
|
|
72
92
|
}
|
|
@@ -6,7 +6,9 @@ import { CustomOpenAI } from "./openai.js";
|
|
|
6
6
|
const DEFAULT_MODEL = "sora-2";
|
|
7
7
|
const DEFAULT_SECONDS = 4;
|
|
8
8
|
const openAIVideoModelInputSchema = videoModelInputSchema.extend({
|
|
9
|
-
|
|
9
|
+
model: z.enum(["sora-2", "sora-2-pro"]).optional(),
|
|
10
|
+
seconds: z.enum(["4", "8", "12"]).optional(),
|
|
11
|
+
size: z.enum(["720x1280", "1280x720", "1024x1792", "1792x1024"]).optional(),
|
|
10
12
|
});
|
|
11
13
|
const openAIVideoModelOptionsSchema = z.object({
|
|
12
14
|
apiKey: z.string().optional(),
|
|
@@ -61,7 +63,7 @@ export class OpenAIVideoModel extends VideoModel {
|
|
|
61
63
|
const buffer = Buffer.from(arrayBuffer);
|
|
62
64
|
return buffer.toString("base64");
|
|
63
65
|
}
|
|
64
|
-
async process(input) {
|
|
66
|
+
async process(input, options) {
|
|
65
67
|
const model = input.model ?? input.modelOptions?.model ?? this.credential.model;
|
|
66
68
|
const createParams = {
|
|
67
69
|
model: model,
|
|
@@ -71,9 +73,10 @@ export class OpenAIVideoModel extends VideoModel {
|
|
|
71
73
|
createParams.seconds = input.seconds;
|
|
72
74
|
if (input.size)
|
|
73
75
|
createParams.size = input.size;
|
|
74
|
-
if (input.
|
|
75
|
-
createParams.input_reference =
|
|
76
|
-
|
|
76
|
+
if (input.image) {
|
|
77
|
+
createParams.input_reference = await this.transformFileType("file", input.image, options).then((file) => new File([Buffer.from(file.data, "base64")], file.filename || "image.png", {
|
|
78
|
+
type: file.mimeType,
|
|
79
|
+
}));
|
|
77
80
|
}
|
|
78
81
|
let video = await this.client.videos.create(createParams);
|
|
79
82
|
logger.debug(`Video generation started: ${video.id}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/openai",
|
|
3
|
-
"version": "0.16.4-beta.
|
|
3
|
+
"version": "0.16.4-beta.6",
|
|
4
4
|
"description": "AIGNE OpenAI SDK for integrating with OpenAI's GPT models and API services",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
"@aigne/uuid": "^13.0.1",
|
|
39
39
|
"openai": "^6.5.0",
|
|
40
40
|
"zod": "^3.25.67",
|
|
41
|
-
"@aigne/
|
|
42
|
-
"@aigne/
|
|
41
|
+
"@aigne/platform-helpers": "^0.6.3",
|
|
42
|
+
"@aigne/core": "^1.65.0-beta.5"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@types/bun": "^1.2.22",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"npm-run-all": "^4.1.5",
|
|
48
48
|
"rimraf": "^6.0.1",
|
|
49
49
|
"typescript": "^5.9.2",
|
|
50
|
-
"@aigne/test-utils": "^0.5.57-beta.
|
|
50
|
+
"@aigne/test-utils": "^0.5.57-beta.6"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
53
|
"lint": "tsc --noEmit",
|