@adminforth/completion-adapter-openai-responses 1.0.0 → 1.0.1
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 +20 -0
- package/dist/index.d.ts +8 -34
- package/dist/index.js +15 -531
- package/dist/langchain.d.ts +14 -0
- package/dist/langchain.js +114 -0
- package/dist/openai.d.ts +50 -0
- package/dist/openai.js +349 -0
- package/dist/types.d.ts +3 -1
- package/index.ts +28 -712
- package/langchain.ts +169 -0
- package/openai.ts +467 -0
- package/package.json +2 -2
- package/types.ts +7 -1
package/README.md
CHANGED
|
@@ -45,3 +45,23 @@ The adapter supports:
|
|
|
45
45
|
- tool calls
|
|
46
46
|
- streaming output chunks
|
|
47
47
|
- streaming reasoning chunks
|
|
48
|
+
- Responses API continuation with `previousResponseId`
|
|
49
|
+
|
|
50
|
+
## Responses continuation
|
|
51
|
+
|
|
52
|
+
For regular completion flows you can pass the previous Responses API id to reuse
|
|
53
|
+
server-side context. The adapter returns the current `responseId`, which can be
|
|
54
|
+
used as `previousResponseId` on the next call:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
const first = await adapter.complete({
|
|
58
|
+
content: "Summarize the project requirements",
|
|
59
|
+
maxTokens: 300,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const second = await adapter.complete({
|
|
63
|
+
content: "Now turn that into three implementation milestones",
|
|
64
|
+
maxTokens: 300,
|
|
65
|
+
previousResponseId: first.responseId,
|
|
66
|
+
});
|
|
67
|
+
```
|
package/dist/index.d.ts
CHANGED
|
@@ -1,34 +1,13 @@
|
|
|
1
1
|
import type { AdapterOptions } from "./types.js";
|
|
2
|
-
import type { CompletionAdapter,
|
|
3
|
-
import {
|
|
2
|
+
import type { CompletionAdapter, CompletionTool } from "adminforth";
|
|
3
|
+
import { type CompletionRequestInput, type CompletionResult, type ReasoningEffort, type StreamChunkCallback } from "./openai.js";
|
|
4
|
+
import { type AgentModelPurpose } from "./langchain.js";
|
|
4
5
|
export type { AdapterOptions } from "./types.js";
|
|
5
|
-
|
|
6
|
-
type ReasoningEffort = "none" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
7
|
-
type AgentModelPurpose = "primary" | "summary";
|
|
8
|
-
type CompletionRequestInput = {
|
|
9
|
-
content: string;
|
|
10
|
-
maxTokens?: number;
|
|
11
|
-
outputSchema?: any;
|
|
12
|
-
reasoningEffort?: ReasoningEffort;
|
|
13
|
-
tools?: CompletionTool[];
|
|
14
|
-
onChunk?: StreamChunkCallback;
|
|
15
|
-
signal?: AbortSignal;
|
|
16
|
-
};
|
|
17
|
-
type UsedTokens = {
|
|
18
|
-
input_uncached: number;
|
|
19
|
-
input_cached: number;
|
|
20
|
-
output: number;
|
|
21
|
-
};
|
|
22
|
-
type CompletionResult = {
|
|
23
|
-
content?: string;
|
|
24
|
-
finishReason?: string;
|
|
25
|
-
error?: string;
|
|
26
|
-
used_tokens?: UsedTokens;
|
|
27
|
-
};
|
|
28
|
-
export default class CompletionAdapterOpenAIResponses implements CompletionAdapter {
|
|
6
|
+
declare class CompletionAdapterOpenAIResponses implements CompletionAdapter {
|
|
29
7
|
options: AdapterOptions;
|
|
30
8
|
private encoding;
|
|
31
9
|
private activeAbortController;
|
|
10
|
+
private openAi;
|
|
32
11
|
constructor(options: AdapterOptions);
|
|
33
12
|
validate(): void;
|
|
34
13
|
measureTokensCount(content: string): number;
|
|
@@ -36,19 +15,14 @@ export default class CompletionAdapterOpenAIResponses implements CompletionAdapt
|
|
|
36
15
|
isGenerationInProgress(): boolean;
|
|
37
16
|
private getConfiguredBaseUrl;
|
|
38
17
|
private shouldUseComplitionApi;
|
|
39
|
-
private shouldDumpRawRequest;
|
|
40
|
-
private getClientConfiguration;
|
|
41
|
-
private createResponsesDebugFetch;
|
|
42
|
-
private getFetchUrl;
|
|
43
|
-
private isResponsesUrl;
|
|
44
|
-
private dumpRawRequest;
|
|
45
|
-
private getResponsesUrl;
|
|
46
18
|
getLangChainAgentSpec(params: {
|
|
47
19
|
maxTokens: number;
|
|
48
20
|
purpose: AgentModelPurpose;
|
|
49
21
|
}): {
|
|
50
|
-
model: ChatOpenAI<import("@langchain/openai").ChatOpenAICallOptions>;
|
|
22
|
+
model: import("@langchain/openai").ChatOpenAI<import("@langchain/openai").ChatOpenAICallOptions>;
|
|
51
23
|
middleware: import("langchain").AgentMiddleware<undefined, undefined, unknown, readonly (import("@langchain/core/tools").ClientTool | import("@langchain/core/tools").ServerTool)[]>[];
|
|
52
24
|
};
|
|
53
25
|
complete: (requestOrContent: CompletionRequestInput | string, maxTokens?: number, outputSchema?: any, reasoningEffort?: ReasoningEffort, toolsOrOnChunk?: CompletionTool[] | StreamChunkCallback, onChunk?: StreamChunkCallback) => Promise<CompletionResult>;
|
|
54
26
|
}
|
|
27
|
+
export { CompletionAdapterOpenAIResponses };
|
|
28
|
+
export default CompletionAdapterOpenAIResponses;
|
package/dist/index.js
CHANGED
|
@@ -7,175 +7,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
11
|
-
var t = {};
|
|
12
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
13
|
-
t[p] = s[p];
|
|
14
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
15
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
16
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
17
|
-
t[p[i]] = s[p[i]];
|
|
18
|
-
}
|
|
19
|
-
return t;
|
|
20
|
-
};
|
|
21
|
-
import { AIMessage } from "@langchain/core/messages";
|
|
22
|
-
import { ChatOpenAI } from "@langchain/openai";
|
|
23
|
-
import { createMiddleware } from "langchain";
|
|
24
10
|
import { encoding_for_model } from "tiktoken";
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
var _a;
|
|
29
|
-
let text = "";
|
|
30
|
-
for (const item of (_a = data.output) !== null && _a !== void 0 ? _a : []) {
|
|
31
|
-
if (item.type !== "message" || !Array.isArray(item.content))
|
|
32
|
-
continue;
|
|
33
|
-
for (const part of item.content) {
|
|
34
|
-
if (part.type === "output_text" && typeof part.text === "string") {
|
|
35
|
-
text += part.text;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return text;
|
|
40
|
-
}
|
|
41
|
-
function extractReasoning(data) {
|
|
42
|
-
var _a, _b, _c;
|
|
43
|
-
let reasoning = "";
|
|
44
|
-
for (const item of (_a = data.output) !== null && _a !== void 0 ? _a : []) {
|
|
45
|
-
if (item.type !== "reasoning")
|
|
46
|
-
continue;
|
|
47
|
-
for (const part of (_b = item.summary) !== null && _b !== void 0 ? _b : []) {
|
|
48
|
-
if ((part === null || part === void 0 ? void 0 : part.type) === "summary_text" && typeof part.text === "string") {
|
|
49
|
-
reasoning += part.text;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
if (!reasoning) {
|
|
53
|
-
for (const part of (_c = item.content) !== null && _c !== void 0 ? _c : []) {
|
|
54
|
-
if ((part === null || part === void 0 ? void 0 : part.type) === "reasoning_text" && typeof part.text === "string") {
|
|
55
|
-
reasoning += part.text;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return reasoning || undefined;
|
|
61
|
-
}
|
|
62
|
-
function extractFunctionCall(data) {
|
|
63
|
-
var _a;
|
|
64
|
-
for (const item of (_a = data.output) !== null && _a !== void 0 ? _a : []) {
|
|
65
|
-
if (item.type === "function_call") {
|
|
66
|
-
return item;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
return undefined;
|
|
70
|
-
}
|
|
71
|
-
function extractUsedTokens(data) {
|
|
72
|
-
var _a, _b;
|
|
73
|
-
const usage = data.usage;
|
|
74
|
-
if (!usage) {
|
|
75
|
-
return undefined;
|
|
76
|
-
}
|
|
77
|
-
const inputCached = (_b = (_a = usage.input_tokens_details) === null || _a === void 0 ? void 0 : _a.cached_tokens) !== null && _b !== void 0 ? _b : 0;
|
|
78
|
-
return {
|
|
79
|
-
input_uncached: Math.max(usage.input_tokens - inputCached, 0),
|
|
80
|
-
input_cached: inputCached,
|
|
81
|
-
output: usage.output_tokens,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
function executeToolCall(toolCall, tools) {
|
|
85
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
86
|
-
const tool = tools === null || tools === void 0 ? void 0 : tools.find((candidate) => candidate.name === toolCall.name);
|
|
87
|
-
if (!tool) {
|
|
88
|
-
throw new Error(`Tool "${toolCall.name}" not found`);
|
|
89
|
-
}
|
|
90
|
-
const toolResult = yield tool.handler(JSON.parse(toolCall.arguments));
|
|
91
|
-
if (typeof toolResult === "string")
|
|
92
|
-
return toolResult;
|
|
93
|
-
if (typeof toolResult === "undefined")
|
|
94
|
-
return "";
|
|
95
|
-
return JSON.stringify(toolResult);
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
function parseSseBlock(block) {
|
|
99
|
-
let event;
|
|
100
|
-
let data = "";
|
|
101
|
-
for (const rawLine of block.split("\n")) {
|
|
102
|
-
const line = rawLine.trimEnd();
|
|
103
|
-
if (!line)
|
|
104
|
-
continue;
|
|
105
|
-
if (line.startsWith("event:"))
|
|
106
|
-
event = line.slice(6).trim();
|
|
107
|
-
if (line.startsWith("data:"))
|
|
108
|
-
data += line.slice(5).trim();
|
|
109
|
-
}
|
|
110
|
-
return data ? { event, data } : null;
|
|
111
|
-
}
|
|
112
|
-
function getAgentReasoningEffort(purpose) {
|
|
113
|
-
return purpose === "summary" ? "minimal" : "low";
|
|
114
|
-
}
|
|
115
|
-
function buildReasoningConfig(params) {
|
|
116
|
-
var _a;
|
|
117
|
-
return Object.assign({ summary: "auto", effort: params.effort }, ((_a = params.reasoning) !== null && _a !== void 0 ? _a : {}));
|
|
118
|
-
}
|
|
119
|
-
function getTurnKey(context) {
|
|
120
|
-
return `${context.sessionId}:${context.turnId}`;
|
|
121
|
-
}
|
|
122
|
-
function getResponseId(message) {
|
|
123
|
-
var _a;
|
|
124
|
-
const metadata = message.response_metadata;
|
|
125
|
-
return (_a = metadata === null || metadata === void 0 ? void 0 : metadata.id) !== null && _a !== void 0 ? _a : null;
|
|
126
|
-
}
|
|
127
|
-
function getPreviousResponseId(modelSettings) {
|
|
128
|
-
return modelSettings === null || modelSettings === void 0 ? void 0 : modelSettings.previous_response_id;
|
|
129
|
-
}
|
|
130
|
-
function getContinuationMessages(messages, previousResponseId) {
|
|
131
|
-
var _a;
|
|
132
|
-
let continuationStartIndex = null;
|
|
133
|
-
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
134
|
-
const message = messages[index];
|
|
135
|
-
if (AIMessage.isInstance(message) &&
|
|
136
|
-
((_a = message.response_metadata) === null || _a === void 0 ? void 0 : _a.id) ===
|
|
137
|
-
previousResponseId) {
|
|
138
|
-
continuationStartIndex = index + 1;
|
|
139
|
-
break;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
if (continuationStartIndex === null) {
|
|
143
|
-
return null;
|
|
144
|
-
}
|
|
145
|
-
return messages.slice(continuationStartIndex);
|
|
146
|
-
}
|
|
147
|
-
function createOpenAiResponsesContinuationMiddleware() {
|
|
148
|
-
const responseIdsByTurn = new Map();
|
|
149
|
-
return createMiddleware({
|
|
150
|
-
name: "OpenAiResponsesContinuationMiddleware",
|
|
151
|
-
wrapModelCall(request, handler) {
|
|
152
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
153
|
-
var _a;
|
|
154
|
-
const context = request.runtime.context;
|
|
155
|
-
const turnKey = getTurnKey(context);
|
|
156
|
-
const previousResponseId = (_a = getPreviousResponseId(request.modelSettings)) !== null && _a !== void 0 ? _a : responseIdsByTurn.get(turnKey);
|
|
157
|
-
const continuationMessages = previousResponseId
|
|
158
|
-
? getContinuationMessages(request.messages, previousResponseId)
|
|
159
|
-
: null;
|
|
160
|
-
const response = (yield handler(previousResponseId && continuationMessages
|
|
161
|
-
? Object.assign(Object.assign({}, request), { messages: continuationMessages, modelSettings: Object.assign(Object.assign({}, request.modelSettings), { previous_response_id: previousResponseId }) }) : request));
|
|
162
|
-
const responseId = getResponseId(response);
|
|
163
|
-
if (responseId) {
|
|
164
|
-
responseIdsByTurn.set(turnKey, responseId);
|
|
165
|
-
}
|
|
166
|
-
else {
|
|
167
|
-
responseIdsByTurn.delete(turnKey);
|
|
168
|
-
}
|
|
169
|
-
return response;
|
|
170
|
-
});
|
|
171
|
-
},
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
export default class CompletionAdapterOpenAIResponses {
|
|
11
|
+
import { OpenAIResponsesService, } from "./openai.js";
|
|
12
|
+
import { createLangChainAgentSpec, } from "./langchain.js";
|
|
13
|
+
class CompletionAdapterOpenAIResponses {
|
|
175
14
|
constructor(options) {
|
|
176
15
|
this.activeAbortController = null;
|
|
177
16
|
this.complete = (requestOrContent_1, ...args_1) => __awaiter(this, [requestOrContent_1, ...args_1], void 0, function* (requestOrContent, maxTokens = 50, outputSchema, reasoningEffort = "low", toolsOrOnChunk, onChunk) {
|
|
178
|
-
var _a, _b, _c;
|
|
179
17
|
const request = typeof requestOrContent === "string"
|
|
180
18
|
? {
|
|
181
19
|
content: requestOrContent,
|
|
@@ -188,37 +26,7 @@ export default class CompletionAdapterOpenAIResponses {
|
|
|
188
26
|
: onChunk,
|
|
189
27
|
}
|
|
190
28
|
: requestOrContent;
|
|
191
|
-
const {
|
|
192
|
-
const model = this.options.model || "gpt-5-nano";
|
|
193
|
-
const isStreaming = typeof streamChunkCallback === "function";
|
|
194
|
-
const extra = this.options.extraRequestBodyParameters;
|
|
195
|
-
const _d = extra !== null && extra !== void 0 ? extra : {}, { reasoning: extraReasoning } = _d, extraWithoutReasoning = __rest(_d, ["reasoning"]);
|
|
196
|
-
let openAiTools = undefined;
|
|
197
|
-
if (tools && tools.length > 0) {
|
|
198
|
-
openAiTools = tools.map((tool) => ({
|
|
199
|
-
type: "function",
|
|
200
|
-
name: tool.name,
|
|
201
|
-
description: tool.description,
|
|
202
|
-
parameters: tool.input_schema,
|
|
203
|
-
strict: false,
|
|
204
|
-
}));
|
|
205
|
-
}
|
|
206
|
-
const body = Object.assign({ model, input: content, max_output_tokens: requestMaxTokens, stream: isStreaming, text: requestOutputSchema
|
|
207
|
-
? {
|
|
208
|
-
format: Object.assign({ type: "json_schema" }, requestOutputSchema),
|
|
209
|
-
}
|
|
210
|
-
: {
|
|
211
|
-
format: {
|
|
212
|
-
type: "text",
|
|
213
|
-
},
|
|
214
|
-
}, reasoning: Object.assign({}, buildReasoningConfig({
|
|
215
|
-
reasoning: extraReasoning,
|
|
216
|
-
effort: requestReasoningEffort,
|
|
217
|
-
})), tools: openAiTools }, extraWithoutReasoning);
|
|
218
|
-
const serializedBody = JSON.stringify(body);
|
|
219
|
-
if (this.shouldDumpRawRequest()) {
|
|
220
|
-
this.dumpRawRequest(this.getResponsesUrl(), serializedBody);
|
|
221
|
-
}
|
|
29
|
+
const { signal: requestSignal } = request;
|
|
222
30
|
const abortController = new AbortController();
|
|
223
31
|
this.activeAbortController = abortController;
|
|
224
32
|
const abortFromRequestSignal = () => abortController.abort(requestSignal === null || requestSignal === void 0 ? void 0 : requestSignal.reason);
|
|
@@ -228,269 +36,18 @@ export default class CompletionAdapterOpenAIResponses {
|
|
|
228
36
|
else {
|
|
229
37
|
requestSignal === null || requestSignal === void 0 ? void 0 : requestSignal.addEventListener("abort", abortFromRequestSignal, { once: true });
|
|
230
38
|
}
|
|
231
|
-
let resp = null;
|
|
232
39
|
try {
|
|
233
|
-
|
|
234
|
-
method: "POST",
|
|
235
|
-
headers: {
|
|
236
|
-
"Content-Type": "application/json",
|
|
237
|
-
Authorization: `Bearer ${this.options.openAiApiKey}`,
|
|
238
|
-
},
|
|
239
|
-
body: serializedBody,
|
|
240
|
-
signal: abortController.signal,
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
catch (error) {
|
|
244
|
-
if (this.activeAbortController === abortController) {
|
|
245
|
-
this.activeAbortController = null;
|
|
246
|
-
}
|
|
247
|
-
if (abortController.signal.aborted) {
|
|
248
|
-
return {
|
|
249
|
-
error: (error === null || error === void 0 ? void 0 : error.message) || "Generation aborted",
|
|
250
|
-
finishReason: "aborted",
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
return {
|
|
254
|
-
error: (error === null || error === void 0 ? void 0 : error.message) || "OpenAI request failed",
|
|
255
|
-
};
|
|
40
|
+
return yield this.openAi.complete(request, abortController.signal);
|
|
256
41
|
}
|
|
257
42
|
finally {
|
|
258
43
|
requestSignal === null || requestSignal === void 0 ? void 0 : requestSignal.removeEventListener("abort", abortFromRequestSignal);
|
|
259
|
-
}
|
|
260
|
-
if (!resp) {
|
|
261
|
-
if (this.activeAbortController === abortController) {
|
|
262
|
-
this.activeAbortController = null;
|
|
263
|
-
}
|
|
264
|
-
return {
|
|
265
|
-
error: "OpenAI request failed",
|
|
266
|
-
};
|
|
267
|
-
}
|
|
268
|
-
try {
|
|
269
|
-
if (!resp.ok) {
|
|
270
|
-
let errorMessage = `OpenAI request failed with status ${resp.status}`;
|
|
271
|
-
try {
|
|
272
|
-
const errorData = (yield resp.json());
|
|
273
|
-
if ((_a = errorData.error) === null || _a === void 0 ? void 0 : _a.message)
|
|
274
|
-
errorMessage = errorData.error.message;
|
|
275
|
-
}
|
|
276
|
-
catch (_e) { }
|
|
277
|
-
return { error: errorMessage };
|
|
278
|
-
}
|
|
279
|
-
if (!isStreaming) {
|
|
280
|
-
const json = yield resp.json();
|
|
281
|
-
const data = json;
|
|
282
|
-
if (data.error) {
|
|
283
|
-
return { error: data.error.message };
|
|
284
|
-
}
|
|
285
|
-
const usedTokens = extractUsedTokens(data);
|
|
286
|
-
const toolCall = extractFunctionCall(data);
|
|
287
|
-
if (toolCall) {
|
|
288
|
-
try {
|
|
289
|
-
const toolResult = yield executeToolCall(toolCall, tools);
|
|
290
|
-
return {
|
|
291
|
-
content: toolResult,
|
|
292
|
-
finishReason: "tool_call",
|
|
293
|
-
used_tokens: usedTokens,
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
|
-
catch (error) {
|
|
297
|
-
return {
|
|
298
|
-
error: (error === null || error === void 0 ? void 0 : error.message) || "Tool execution failed",
|
|
299
|
-
finishReason: "tool_call",
|
|
300
|
-
used_tokens: usedTokens,
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
const parsedContent = extractOutputText(data);
|
|
305
|
-
return {
|
|
306
|
-
content: parsedContent,
|
|
307
|
-
finishReason: ((_b = data.incomplete_details) === null || _b === void 0 ? void 0 : _b.reason)
|
|
308
|
-
? data.incomplete_details.reason
|
|
309
|
-
: undefined,
|
|
310
|
-
used_tokens: usedTokens,
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
if (!resp.body) {
|
|
314
|
-
return { error: "Response body is empty" };
|
|
315
|
-
}
|
|
316
|
-
const reader = resp.body.getReader();
|
|
317
|
-
const decoder = new TextDecoder("utf-8");
|
|
318
|
-
let buffer = "";
|
|
319
|
-
let fullContent = "";
|
|
320
|
-
let fullReasoning = "";
|
|
321
|
-
let finishReason;
|
|
322
|
-
let completedResponse;
|
|
323
|
-
let usedTokens;
|
|
324
|
-
const handleEvent = (event, eventType) => __awaiter(this, void 0, void 0, function* () {
|
|
325
|
-
var _a, _b, _c, _d;
|
|
326
|
-
const type = (event === null || event === void 0 ? void 0 : event.type) || eventType;
|
|
327
|
-
if (type === "response.output_text.delta") {
|
|
328
|
-
const delta = (event === null || event === void 0 ? void 0 : event.delta) || "";
|
|
329
|
-
if (!delta)
|
|
330
|
-
return;
|
|
331
|
-
fullContent += delta;
|
|
332
|
-
yield (streamChunkCallback === null || streamChunkCallback === void 0 ? void 0 : streamChunkCallback(delta, { type: "output", delta, text: fullContent }));
|
|
333
|
-
return;
|
|
334
|
-
}
|
|
335
|
-
if (type === "response.reasoning_summary_text.delta" ||
|
|
336
|
-
type === "response.reasoning_text.delta") {
|
|
337
|
-
const delta = (event === null || event === void 0 ? void 0 : event.delta) || "";
|
|
338
|
-
if (!delta)
|
|
339
|
-
return;
|
|
340
|
-
fullReasoning += delta;
|
|
341
|
-
yield (streamChunkCallback === null || streamChunkCallback === void 0 ? void 0 : streamChunkCallback(delta, {
|
|
342
|
-
type: "reasoning",
|
|
343
|
-
delta,
|
|
344
|
-
text: fullReasoning,
|
|
345
|
-
}));
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
|
-
if (type === "response.completed" || type === "response.incomplete") {
|
|
349
|
-
const response = event === null || event === void 0 ? void 0 : event.response;
|
|
350
|
-
if (!response)
|
|
351
|
-
return;
|
|
352
|
-
const finalContent = extractOutputText(response);
|
|
353
|
-
if (finalContent.startsWith(fullContent)) {
|
|
354
|
-
const delta = finalContent.slice(fullContent.length);
|
|
355
|
-
if (delta) {
|
|
356
|
-
fullContent = finalContent;
|
|
357
|
-
yield (streamChunkCallback === null || streamChunkCallback === void 0 ? void 0 : streamChunkCallback(delta, {
|
|
358
|
-
type: "output",
|
|
359
|
-
delta,
|
|
360
|
-
text: fullContent,
|
|
361
|
-
}));
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
const finalReasoning = extractReasoning(response) || "";
|
|
365
|
-
if (finalReasoning.startsWith(fullReasoning)) {
|
|
366
|
-
const delta = finalReasoning.slice(fullReasoning.length);
|
|
367
|
-
if (delta) {
|
|
368
|
-
fullReasoning = finalReasoning;
|
|
369
|
-
yield (streamChunkCallback === null || streamChunkCallback === void 0 ? void 0 : streamChunkCallback(delta, {
|
|
370
|
-
type: "reasoning",
|
|
371
|
-
delta,
|
|
372
|
-
text: fullReasoning,
|
|
373
|
-
}));
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
finishReason =
|
|
377
|
-
((_a = response.incomplete_details) === null || _a === void 0 ? void 0 : _a.reason) || response.status || finishReason;
|
|
378
|
-
completedResponse = response;
|
|
379
|
-
usedTokens = extractUsedTokens(response);
|
|
380
|
-
return;
|
|
381
|
-
}
|
|
382
|
-
if (type === "response.failed") {
|
|
383
|
-
throw new Error(((_c = (_b = event === null || event === void 0 ? void 0 : event.response) === null || _b === void 0 ? void 0 : _b.error) === null || _c === void 0 ? void 0 : _c.message) ||
|
|
384
|
-
((_d = event === null || event === void 0 ? void 0 : event.error) === null || _d === void 0 ? void 0 : _d.message) ||
|
|
385
|
-
"Response failed");
|
|
386
|
-
}
|
|
387
|
-
});
|
|
388
|
-
try {
|
|
389
|
-
while (true) {
|
|
390
|
-
const { value, done } = yield reader.read();
|
|
391
|
-
if (done)
|
|
392
|
-
break;
|
|
393
|
-
buffer += decoder.decode(value, { stream: true });
|
|
394
|
-
const blocks = buffer.split("\n\n");
|
|
395
|
-
buffer = blocks.pop() || "";
|
|
396
|
-
for (const block of blocks) {
|
|
397
|
-
const parsedBlock = parseSseBlock(block);
|
|
398
|
-
if (!(parsedBlock === null || parsedBlock === void 0 ? void 0 : parsedBlock.data) || parsedBlock.data === "[DONE]")
|
|
399
|
-
continue;
|
|
400
|
-
let event;
|
|
401
|
-
try {
|
|
402
|
-
event = JSON.parse(parsedBlock.data);
|
|
403
|
-
}
|
|
404
|
-
catch (_f) {
|
|
405
|
-
continue;
|
|
406
|
-
}
|
|
407
|
-
if ((_c = event === null || event === void 0 ? void 0 : event.error) === null || _c === void 0 ? void 0 : _c.message) {
|
|
408
|
-
return { error: event.error.message };
|
|
409
|
-
}
|
|
410
|
-
yield handleEvent(event, parsedBlock.event);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
if (buffer.trim()) {
|
|
414
|
-
const parsedBlock = parseSseBlock(buffer.trim());
|
|
415
|
-
if ((parsedBlock === null || parsedBlock === void 0 ? void 0 : parsedBlock.data) && parsedBlock.data !== "[DONE]") {
|
|
416
|
-
try {
|
|
417
|
-
yield handleEvent(JSON.parse(parsedBlock.data), parsedBlock.event);
|
|
418
|
-
}
|
|
419
|
-
catch (error) {
|
|
420
|
-
return {
|
|
421
|
-
error: (error === null || error === void 0 ? void 0 : error.message) || "Streaming failed",
|
|
422
|
-
content: fullContent || undefined,
|
|
423
|
-
finishReason,
|
|
424
|
-
};
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
if (completedResponse) {
|
|
429
|
-
const toolCall = extractFunctionCall(completedResponse);
|
|
430
|
-
if (toolCall) {
|
|
431
|
-
try {
|
|
432
|
-
const toolResult = yield executeToolCall(toolCall, tools);
|
|
433
|
-
if (toolResult) {
|
|
434
|
-
const delta = toolResult.startsWith(fullContent)
|
|
435
|
-
? toolResult.slice(fullContent.length)
|
|
436
|
-
: toolResult;
|
|
437
|
-
if (delta) {
|
|
438
|
-
yield (streamChunkCallback === null || streamChunkCallback === void 0 ? void 0 : streamChunkCallback(delta, {
|
|
439
|
-
type: "output",
|
|
440
|
-
delta,
|
|
441
|
-
text: toolResult,
|
|
442
|
-
}));
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
return {
|
|
446
|
-
content: toolResult,
|
|
447
|
-
finishReason: "tool_call",
|
|
448
|
-
used_tokens: usedTokens,
|
|
449
|
-
};
|
|
450
|
-
}
|
|
451
|
-
catch (error) {
|
|
452
|
-
return {
|
|
453
|
-
error: (error === null || error === void 0 ? void 0 : error.message) || "Tool execution failed",
|
|
454
|
-
content: fullContent || undefined,
|
|
455
|
-
finishReason: "tool_call",
|
|
456
|
-
used_tokens: usedTokens,
|
|
457
|
-
};
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
return {
|
|
462
|
-
content: fullContent || undefined,
|
|
463
|
-
finishReason,
|
|
464
|
-
used_tokens: usedTokens,
|
|
465
|
-
};
|
|
466
|
-
}
|
|
467
|
-
catch (error) {
|
|
468
|
-
if (abortController.signal.aborted) {
|
|
469
|
-
return {
|
|
470
|
-
error: (error === null || error === void 0 ? void 0 : error.message) || "Generation aborted",
|
|
471
|
-
content: fullContent || undefined,
|
|
472
|
-
finishReason: "aborted",
|
|
473
|
-
used_tokens: usedTokens,
|
|
474
|
-
};
|
|
475
|
-
}
|
|
476
|
-
return {
|
|
477
|
-
error: (error === null || error === void 0 ? void 0 : error.message) || "Streaming failed",
|
|
478
|
-
content: fullContent || undefined,
|
|
479
|
-
finishReason,
|
|
480
|
-
used_tokens: usedTokens,
|
|
481
|
-
};
|
|
482
|
-
}
|
|
483
|
-
finally {
|
|
484
|
-
reader.releaseLock();
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
finally {
|
|
488
44
|
if (this.activeAbortController === abortController) {
|
|
489
45
|
this.activeAbortController = null;
|
|
490
46
|
}
|
|
491
47
|
}
|
|
492
48
|
});
|
|
493
49
|
this.options = options;
|
|
50
|
+
this.openAi = new OpenAIResponsesService(options);
|
|
494
51
|
try {
|
|
495
52
|
this.encoding = encoding_for_model((this.options.model || "gpt-5-nano"));
|
|
496
53
|
}
|
|
@@ -525,89 +82,16 @@ export default class CompletionAdapterOpenAIResponses {
|
|
|
525
82
|
}
|
|
526
83
|
return Boolean(this.getConfiguredBaseUrl());
|
|
527
84
|
}
|
|
528
|
-
shouldDumpRawRequest() {
|
|
529
|
-
return this.options.dumpRawRequest === true;
|
|
530
|
-
}
|
|
531
|
-
getClientConfiguration() {
|
|
532
|
-
const configuredBaseUrl = this.getConfiguredBaseUrl();
|
|
533
|
-
const debugFetch = this.shouldDumpRawRequest()
|
|
534
|
-
? this.createResponsesDebugFetch()
|
|
535
|
-
: undefined;
|
|
536
|
-
if (!configuredBaseUrl && !debugFetch) {
|
|
537
|
-
return undefined;
|
|
538
|
-
}
|
|
539
|
-
return Object.assign(Object.assign({}, (configuredBaseUrl ? { baseURL: configuredBaseUrl } : {})), (debugFetch ? { fetch: debugFetch } : {}));
|
|
540
|
-
}
|
|
541
|
-
createResponsesDebugFetch() {
|
|
542
|
-
return (input, init) => __awaiter(this, void 0, void 0, function* () {
|
|
543
|
-
const url = this.getFetchUrl(input);
|
|
544
|
-
if (this.isResponsesUrl(url) && typeof (init === null || init === void 0 ? void 0 : init.body) === "string") {
|
|
545
|
-
this.dumpRawRequest(url, init.body);
|
|
546
|
-
}
|
|
547
|
-
return fetch(input, init);
|
|
548
|
-
});
|
|
549
|
-
}
|
|
550
|
-
getFetchUrl(input) {
|
|
551
|
-
if (typeof input === "string") {
|
|
552
|
-
return input;
|
|
553
|
-
}
|
|
554
|
-
if (input instanceof URL) {
|
|
555
|
-
return input.toString();
|
|
556
|
-
}
|
|
557
|
-
return input.url;
|
|
558
|
-
}
|
|
559
|
-
isResponsesUrl(url) {
|
|
560
|
-
try {
|
|
561
|
-
return new URL(url).pathname.endsWith("/responses");
|
|
562
|
-
}
|
|
563
|
-
catch (_a) {
|
|
564
|
-
return url.endsWith("/responses") || url.includes("/responses?");
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
dumpRawRequest(url, body) {
|
|
568
|
-
console.info(`${RAW_REQUEST_LOG_PREFIX} ${url}`);
|
|
569
|
-
try {
|
|
570
|
-
console.info(JSON.stringify(JSON.parse(body), null, 2));
|
|
571
|
-
}
|
|
572
|
-
catch (_a) {
|
|
573
|
-
console.info(body);
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
getResponsesUrl() {
|
|
577
|
-
const baseUrl = this.getConfiguredBaseUrl() || DEFAULT_OPENAI_BASE_URL;
|
|
578
|
-
const normalizedBaseUrl = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
|
|
579
|
-
return new URL("responses", normalizedBaseUrl).toString();
|
|
580
|
-
}
|
|
581
85
|
getLangChainAgentSpec(params) {
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
const configuredBaseUrl = this.getConfiguredBaseUrl();
|
|
585
|
-
const normalizedModelKwargs = Object.assign({}, modelKwargs);
|
|
586
|
-
const clientConfiguration = this.getClientConfiguration();
|
|
587
|
-
const useComplitionApi = this.shouldUseComplitionApi();
|
|
588
|
-
const chatOpenAiOptions = {
|
|
589
|
-
model: this.options.model || "gpt-5-nano",
|
|
590
|
-
apiKey: this.options.openAiApiKey,
|
|
86
|
+
return createLangChainAgentSpec({
|
|
87
|
+
options: this.options,
|
|
591
88
|
maxTokens: params.maxTokens,
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
};
|
|
598
|
-
chatOpenAiOptions.useResponsesApi = !useComplitionApi;
|
|
599
|
-
let supportsResponseContinuation = true;
|
|
600
|
-
if (configuredBaseUrl || useComplitionApi) {
|
|
601
|
-
supportsResponseContinuation = false;
|
|
602
|
-
}
|
|
603
|
-
if (clientConfiguration) {
|
|
604
|
-
chatOpenAiOptions.configuration = clientConfiguration;
|
|
605
|
-
}
|
|
606
|
-
return {
|
|
607
|
-
model: new ChatOpenAI(chatOpenAiOptions),
|
|
608
|
-
middleware: params.purpose === "primary" && supportsResponseContinuation
|
|
609
|
-
? [createOpenAiResponsesContinuationMiddleware()]
|
|
610
|
-
: [],
|
|
611
|
-
};
|
|
89
|
+
purpose: params.purpose,
|
|
90
|
+
configuredBaseUrl: this.getConfiguredBaseUrl(),
|
|
91
|
+
clientConfiguration: this.openAi.getClientConfiguration(),
|
|
92
|
+
useComplitionApi: this.shouldUseComplitionApi(),
|
|
93
|
+
});
|
|
612
94
|
}
|
|
613
95
|
}
|
|
96
|
+
export { CompletionAdapterOpenAIResponses };
|
|
97
|
+
export default CompletionAdapterOpenAIResponses;
|