@prismshadow/mmsp 0.5.0
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 +121 -0
- package/dist/ant_messages/client.d.ts +59 -0
- package/dist/ant_messages/client.d.ts.map +1 -0
- package/dist/ant_messages/client.js +419 -0
- package/dist/ant_messages/index.d.ts +2 -0
- package/dist/ant_messages/index.d.ts.map +1 -0
- package/dist/ant_messages/index.js +18 -0
- package/dist/anthropic_official/client.d.ts +63 -0
- package/dist/anthropic_official/client.d.ts.map +1 -0
- package/dist/anthropic_official/client.js +540 -0
- package/dist/anthropic_official/index.d.ts +2 -0
- package/dist/anthropic_official/index.d.ts.map +1 -0
- package/dist/anthropic_official/index.js +18 -0
- package/dist/autoClient.d.ts +96 -0
- package/dist/autoClient.d.ts.map +1 -0
- package/dist/autoClient.js +258 -0
- package/dist/baseClient.d.ts +111 -0
- package/dist/baseClient.d.ts.map +1 -0
- package/dist/baseClient.js +284 -0
- package/dist/deepseek_official/client.d.ts +60 -0
- package/dist/deepseek_official/client.d.ts.map +1 -0
- package/dist/deepseek_official/client.js +407 -0
- package/dist/deepseek_official/index.d.ts +2 -0
- package/dist/deepseek_official/index.d.ts.map +1 -0
- package/dist/deepseek_official/index.js +18 -0
- package/dist/errors.d.ts +84 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +140 -0
- package/dist/gemini_generate_content/client.d.ts +86 -0
- package/dist/gemini_generate_content/client.d.ts.map +1 -0
- package/dist/gemini_generate_content/client.js +809 -0
- package/dist/gemini_generate_content/index.d.ts +2 -0
- package/dist/gemini_generate_content/index.d.ts.map +1 -0
- package/dist/gemini_generate_content/index.js +18 -0
- package/dist/gemini_official/client.d.ts +87 -0
- package/dist/gemini_official/client.d.ts.map +1 -0
- package/dist/gemini_official/client.js +780 -0
- package/dist/gemini_official/index.d.ts +2 -0
- package/dist/gemini_official/index.d.ts.map +1 -0
- package/dist/gemini_official/index.js +18 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/integration/index.d.ts +1 -0
- package/dist/integration/index.d.ts.map +1 -0
- package/dist/integration/index.js +14 -0
- package/dist/integration/playground.d.ts +17 -0
- package/dist/integration/playground.d.ts.map +1 -0
- package/dist/integration/playground.js +3246 -0
- package/dist/integration/tracer.d.ts +188 -0
- package/dist/integration/tracer.d.ts.map +1 -0
- package/dist/integration/tracer.js +1928 -0
- package/dist/legacy.d.ts +13 -0
- package/dist/legacy.d.ts.map +1 -0
- package/dist/legacy.js +59 -0
- package/dist/minimax_official/client.d.ts +43 -0
- package/dist/minimax_official/client.d.ts.map +1 -0
- package/dist/minimax_official/client.js +346 -0
- package/dist/minimax_official/index.d.ts +2 -0
- package/dist/minimax_official/index.d.ts.map +1 -0
- package/dist/minimax_official/index.js +18 -0
- package/dist/moonshot_official/client.d.ts +73 -0
- package/dist/moonshot_official/client.d.ts.map +1 -0
- package/dist/moonshot_official/client.js +477 -0
- package/dist/moonshot_official/index.d.ts +2 -0
- package/dist/moonshot_official/index.d.ts.map +1 -0
- package/dist/moonshot_official/index.js +18 -0
- package/dist/openai_chat/client.d.ts +67 -0
- package/dist/openai_chat/client.d.ts.map +1 -0
- package/dist/openai_chat/client.js +419 -0
- package/dist/openai_chat/index.d.ts +2 -0
- package/dist/openai_chat/index.d.ts.map +1 -0
- package/dist/openai_chat/index.js +18 -0
- package/dist/openai_chat_vllm_adapter/client.d.ts +15 -0
- package/dist/openai_chat_vllm_adapter/client.d.ts.map +1 -0
- package/dist/openai_chat_vllm_adapter/client.js +118 -0
- package/dist/openai_chat_vllm_adapter/index.d.ts +2 -0
- package/dist/openai_chat_vllm_adapter/index.d.ts.map +1 -0
- package/dist/openai_chat_vllm_adapter/index.js +5 -0
- package/dist/openai_embedding/client.d.ts +46 -0
- package/dist/openai_embedding/client.d.ts.map +1 -0
- package/dist/openai_embedding/client.js +124 -0
- package/dist/openai_embedding/index.d.ts +2 -0
- package/dist/openai_embedding/index.d.ts.map +1 -0
- package/dist/openai_embedding/index.js +18 -0
- package/dist/openai_official/client.d.ts +61 -0
- package/dist/openai_official/client.d.ts.map +1 -0
- package/dist/openai_official/client.js +464 -0
- package/dist/openai_official/index.d.ts +2 -0
- package/dist/openai_official/index.d.ts.map +1 -0
- package/dist/openai_official/index.js +18 -0
- package/dist/openai_responses/client.d.ts +61 -0
- package/dist/openai_responses/client.d.ts.map +1 -0
- package/dist/openai_responses/client.js +449 -0
- package/dist/openai_responses/index.d.ts +2 -0
- package/dist/openai_responses/index.d.ts.map +1 -0
- package/dist/openai_responses/index.js +18 -0
- package/dist/registry.d.ts +49 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +798 -0
- package/dist/streamItems.d.ts +36 -0
- package/dist/streamItems.d.ts.map +1 -0
- package/dist/streamItems.js +183 -0
- package/dist/types.d.ts +190 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +37 -0
- package/dist/utils.d.ts +99 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +312 -0
- package/dist/zai_official/client.d.ts +78 -0
- package/dist/zai_official/client.d.ts.map +1 -0
- package/dist/zai_official/client.js +420 -0
- package/dist/zai_official/index.d.ts +2 -0
- package/dist/zai_official/index.d.ts.map +1 -0
- package/dist/zai_official/index.js +18 -0
- package/package.json +68 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2025 Prism Shadow. and/or its affiliates
|
|
3
|
+
//
|
|
4
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
// you may not use this file except in compliance with the License.
|
|
6
|
+
// You may obtain a copy of the License at
|
|
7
|
+
//
|
|
8
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
//
|
|
10
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
// See the License for the specific language governing permissions and
|
|
14
|
+
// limitations under the License.
|
|
15
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
16
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
17
|
+
};
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.OpenaiEmbeddingClient = void 0;
|
|
20
|
+
const openai_1 = __importDefault(require("openai"));
|
|
21
|
+
const baseClient_1 = require("../baseClient");
|
|
22
|
+
const errors_1 = require("../errors");
|
|
23
|
+
const utils_1 = require("../utils");
|
|
24
|
+
/**
|
|
25
|
+
* OpenAI Embeddings-compatible client implementation.
|
|
26
|
+
*/
|
|
27
|
+
class OpenaiEmbeddingClient extends baseClient_1.LLMClient {
|
|
28
|
+
/**
|
|
29
|
+
* Initialize OpenAI-compatible embedding client with model, API key, and base URL.
|
|
30
|
+
*/
|
|
31
|
+
constructor(options) {
|
|
32
|
+
super();
|
|
33
|
+
this._model = options.model;
|
|
34
|
+
const { apiKey: key, baseUrl: url } = (0, utils_1.resolveCredentials)(this.constructor.name, options, { key: "OPENAI_API_KEY", baseUrl: "OPENAI_BASE_URL" });
|
|
35
|
+
this._client = new openai_1.default({
|
|
36
|
+
apiKey: key,
|
|
37
|
+
baseURL: url,
|
|
38
|
+
defaultHeaders: options.defaultHeaders,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Transform universal configuration to OpenAI Embeddings configuration.
|
|
43
|
+
*/
|
|
44
|
+
transformUniConfigToModelConfig(config) {
|
|
45
|
+
if (config.fast_mode) {
|
|
46
|
+
throw new errors_1.UnsupportedParameterError({
|
|
47
|
+
client: this.constructor.name,
|
|
48
|
+
parameter: "fast_mode",
|
|
49
|
+
message: "OpenAI embeddings do not support fast mode.",
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
const params = {
|
|
53
|
+
model: this._model,
|
|
54
|
+
};
|
|
55
|
+
const dimensions = config.embedding_config?.dimensions;
|
|
56
|
+
if (dimensions !== undefined) {
|
|
57
|
+
params.dimensions = dimensions;
|
|
58
|
+
}
|
|
59
|
+
return params;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Transform universal messages to OpenAI Embeddings input strings.
|
|
63
|
+
*/
|
|
64
|
+
transformUniMessageToModelInput(messages) {
|
|
65
|
+
const texts = [];
|
|
66
|
+
for (const msg of messages) {
|
|
67
|
+
let msgText = "";
|
|
68
|
+
for (const item of msg.content_items) {
|
|
69
|
+
if (item.type !== "text.done") {
|
|
70
|
+
throw new Error("OpenAI embeddings only support text content items.");
|
|
71
|
+
}
|
|
72
|
+
msgText += item.text;
|
|
73
|
+
}
|
|
74
|
+
texts.push(msgText || " ");
|
|
75
|
+
}
|
|
76
|
+
return texts;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Transform an OpenAI Embeddings response into a universal event, one complete item per vector.
|
|
80
|
+
*/
|
|
81
|
+
transformModelOutputToUniEvent(modelOutput) {
|
|
82
|
+
return {
|
|
83
|
+
role: "assistant",
|
|
84
|
+
event_type: "stop",
|
|
85
|
+
content_items: modelOutput.data.map((item) => ({
|
|
86
|
+
type: "embedding.delta",
|
|
87
|
+
embedding: item.embedding,
|
|
88
|
+
})),
|
|
89
|
+
usage_metadata: {
|
|
90
|
+
cached_tokens: null,
|
|
91
|
+
prompt_tokens: modelOutput.usage?.prompt_tokens ?? null,
|
|
92
|
+
thoughts_tokens: null,
|
|
93
|
+
response_tokens: null,
|
|
94
|
+
},
|
|
95
|
+
finish_reason: "stop",
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Generate embeddings using OpenAI Embeddings-compatible API.
|
|
100
|
+
*/
|
|
101
|
+
async *_streamingResponseInternal(options) {
|
|
102
|
+
const params = {
|
|
103
|
+
...this.transformUniConfigToModelConfig(options.config),
|
|
104
|
+
input: this.transformUniMessageToModelInput(options.messages),
|
|
105
|
+
};
|
|
106
|
+
const result = await this._client.embeddings.create(params, {
|
|
107
|
+
signal: options.signal,
|
|
108
|
+
});
|
|
109
|
+
yield this.transformModelOutputToUniEvent(result);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* List the model ids the configured endpoint serves.
|
|
113
|
+
*
|
|
114
|
+
* @returns The model ids, in the order the endpoint returned them.
|
|
115
|
+
*/
|
|
116
|
+
async listModels() {
|
|
117
|
+
const models = [];
|
|
118
|
+
for await (const model of this._client.models.list()) {
|
|
119
|
+
models.push(model.id);
|
|
120
|
+
}
|
|
121
|
+
return models;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
exports.OpenaiEmbeddingClient = OpenaiEmbeddingClient;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/openai_embedding/index.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2025 Prism Shadow. and/or its affiliates
|
|
3
|
+
//
|
|
4
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
// you may not use this file except in compliance with the License.
|
|
6
|
+
// You may obtain a copy of the License at
|
|
7
|
+
//
|
|
8
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
//
|
|
10
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
// See the License for the specific language governing permissions and
|
|
14
|
+
// limitations under the License.
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.OpenaiEmbeddingClient = void 0;
|
|
17
|
+
var client_1 = require("./client");
|
|
18
|
+
Object.defineProperty(exports, "OpenaiEmbeddingClient", { enumerable: true, get: function () { return client_1.OpenaiEmbeddingClient; } });
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { ResponseInputItem, ResponseStreamEvent } from "openai/resources/responses/responses";
|
|
2
|
+
import { LLMClient } from "../baseClient";
|
|
3
|
+
import { UniConfig, UniEvent, UniMessage } from "../types";
|
|
4
|
+
/**
|
|
5
|
+
* GPT-6-specific LLM client implementation (also serves GPT-5.6, GPT-5.5 and GPT-5.4).
|
|
6
|
+
*/
|
|
7
|
+
export declare class OpenAIOfficialClient extends LLMClient {
|
|
8
|
+
protected _model: string;
|
|
9
|
+
private _client;
|
|
10
|
+
/**
|
|
11
|
+
* Initialize GPT-6 client with model and API key.
|
|
12
|
+
*/
|
|
13
|
+
constructor(options: {
|
|
14
|
+
model: string;
|
|
15
|
+
apiKey?: string;
|
|
16
|
+
baseUrl?: string | null;
|
|
17
|
+
defaultHeaders?: Record<string, string>;
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* Convert ThinkingLevel enum to OpenAI's reasoning effort.
|
|
21
|
+
*/
|
|
22
|
+
private _convertThinkingLevelToEffort;
|
|
23
|
+
/**
|
|
24
|
+
* Convert ToolChoice to OpenAI's tool_choice format with allowed tools support.
|
|
25
|
+
*/
|
|
26
|
+
private _convertToolChoice;
|
|
27
|
+
/**
|
|
28
|
+
* Convert an image URL to an input_image item, at the detail the API needs
|
|
29
|
+
* to read it.
|
|
30
|
+
*/
|
|
31
|
+
private _convertImageUrl;
|
|
32
|
+
/**
|
|
33
|
+
* Transform universal configuration to OpenAI Responses API configuration.
|
|
34
|
+
*/
|
|
35
|
+
transformUniConfigToModelConfig(config: UniConfig): any;
|
|
36
|
+
/**
|
|
37
|
+
* Transform universal message format to OpenAI Responses API input format.
|
|
38
|
+
*/
|
|
39
|
+
transformUniMessageToModelInput(messages: UniMessage[], _signal?: AbortSignal): ResponseInputItem[];
|
|
40
|
+
/**
|
|
41
|
+
* Transform one OpenAI Responses API stream event into a universal event, identifying items by
|
|
42
|
+
* output item id. An item needs no done: it is done when the next one begins or the stream
|
|
43
|
+
* ends.
|
|
44
|
+
*/
|
|
45
|
+
transformModelOutputToUniEvent(modelOutput: ResponseStreamEvent): UniEvent;
|
|
46
|
+
/**
|
|
47
|
+
* Stream generate using OpenAI Responses API with unified conversion methods.
|
|
48
|
+
*/
|
|
49
|
+
_streamingResponseInternal(options: {
|
|
50
|
+
messages: UniMessage[];
|
|
51
|
+
config: UniConfig;
|
|
52
|
+
signal?: AbortSignal;
|
|
53
|
+
}): AsyncGenerator<UniEvent>;
|
|
54
|
+
/**
|
|
55
|
+
* List the model ids the configured endpoint serves.
|
|
56
|
+
*
|
|
57
|
+
* @returns The model ids, in the order the endpoint returned them.
|
|
58
|
+
*/
|
|
59
|
+
listModels(): Promise<string[]>;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/openai_official/client.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACV,iBAAiB,EACjB,mBAAmB,EAEpB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAOL,SAAS,EACT,QAAQ,EACR,UAAU,EAGX,MAAM,UAAU,CAAC;AAOlB;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,SAAS;IACjD,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,OAAO,CAAS;IAExB;;OAEG;gBACS,OAAO,EAAE;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACzC;IAeD;;OAEG;IACH,OAAO,CAAC,6BAA6B;IAoBrC;;OAEG;IAEH,OAAO,CAAC,kBAAkB;IAW1B;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAWxB;;OAEG;IAEH,+BAA+B,CAAC,MAAM,EAAE,SAAS,GAAG,GAAG;IAmEvD;;OAEG;IACH,+BAA+B,CAC7B,QAAQ,EAAE,UAAU,EAAE,EACtB,OAAO,CAAC,EAAE,WAAW,GACpB,iBAAiB,EAAE;IAkJtB;;;;OAIG;IACH,8BAA8B,CAAC,WAAW,EAAE,mBAAmB,GAAG,QAAQ;IAmJ1E;;OAEG;IACI,0BAA0B,CAAC,OAAO,EAAE;QACzC,QAAQ,EAAE,UAAU,EAAE,CAAC;QACvB,MAAM,EAAE,SAAS,CAAC;QAClB,MAAM,CAAC,EAAE,WAAW,CAAC;KACtB,GAAG,cAAc,CAAC,QAAQ,CAAC;IAqB5B;;;;OAIG;IACG,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;CAQtC"}
|
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2025 Prism Shadow. and/or its affiliates
|
|
3
|
+
//
|
|
4
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
// you may not use this file except in compliance with the License.
|
|
6
|
+
// You may obtain a copy of the License at
|
|
7
|
+
//
|
|
8
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
//
|
|
10
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
// See the License for the specific language governing permissions and
|
|
14
|
+
// limitations under the License.
|
|
15
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
16
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
17
|
+
};
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.OpenAIOfficialClient = void 0;
|
|
20
|
+
const openai_1 = __importDefault(require("openai"));
|
|
21
|
+
const baseClient_1 = require("../baseClient");
|
|
22
|
+
const errors_1 = require("../errors");
|
|
23
|
+
const types_1 = require("../types");
|
|
24
|
+
const utils_1 = require("../utils");
|
|
25
|
+
/**
|
|
26
|
+
* GPT-6-specific LLM client implementation (also serves GPT-5.6, GPT-5.5 and GPT-5.4).
|
|
27
|
+
*/
|
|
28
|
+
class OpenAIOfficialClient extends baseClient_1.LLMClient {
|
|
29
|
+
/**
|
|
30
|
+
* Initialize GPT-6 client with model and API key.
|
|
31
|
+
*/
|
|
32
|
+
constructor(options) {
|
|
33
|
+
super();
|
|
34
|
+
this._model = options.model;
|
|
35
|
+
const { apiKey: key, baseUrl: url } = (0, utils_1.resolveCredentials)(this.constructor.name, options, { key: "OPENAI_API_KEY", baseUrl: "OPENAI_BASE_URL" });
|
|
36
|
+
this._client = new openai_1.default({
|
|
37
|
+
apiKey: key,
|
|
38
|
+
baseURL: url,
|
|
39
|
+
defaultHeaders: options.defaultHeaders,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Convert ThinkingLevel enum to OpenAI's reasoning effort.
|
|
44
|
+
*/
|
|
45
|
+
_convertThinkingLevelToEffort(thinkingLevel) {
|
|
46
|
+
if (thinkingLevel === types_1.ThinkingLevel.NONE && this._model.includes("gpt-6")) {
|
|
47
|
+
// GPT-6 rejects both "none" and "minimal" with a 400 (verified live 2026-09-09:
|
|
48
|
+
// "Unsupported value: 'none' is not supported with the 'gpt-6-astra' model.
|
|
49
|
+
// Supported values are: 'low', 'medium', 'high', 'xhigh', and 'max'."), so NONE
|
|
50
|
+
// degrades to the lowest effort the generation accepts.
|
|
51
|
+
return "low";
|
|
52
|
+
}
|
|
53
|
+
const mapping = {
|
|
54
|
+
[types_1.ThinkingLevel.NONE]: "none",
|
|
55
|
+
[types_1.ThinkingLevel.LOW]: "low",
|
|
56
|
+
[types_1.ThinkingLevel.MEDIUM]: "medium",
|
|
57
|
+
[types_1.ThinkingLevel.HIGH]: "high",
|
|
58
|
+
[types_1.ThinkingLevel.XHIGH]: "xhigh",
|
|
59
|
+
[types_1.ThinkingLevel.MAX]: "max",
|
|
60
|
+
};
|
|
61
|
+
return mapping[thinkingLevel];
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Convert ToolChoice to OpenAI's tool_choice format with allowed tools support.
|
|
65
|
+
*/
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
67
|
+
_convertToolChoice(toolChoice) {
|
|
68
|
+
if (Array.isArray(toolChoice)) {
|
|
69
|
+
return {
|
|
70
|
+
mode: "required",
|
|
71
|
+
tools: toolChoice.map((name) => ({ type: "function", name })),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return toolChoice;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Convert an image URL to an input_image item, at the detail the API needs
|
|
78
|
+
* to read it.
|
|
79
|
+
*/
|
|
80
|
+
_convertImageUrl(imageUrl) {
|
|
81
|
+
const detail = (0, utils_1.openaiImageDetail)(this._model, imageUrl);
|
|
82
|
+
return detail
|
|
83
|
+
? { type: "input_image", image_url: imageUrl, detail }
|
|
84
|
+
: { type: "input_image", image_url: imageUrl };
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Transform universal configuration to OpenAI Responses API configuration.
|
|
88
|
+
*/
|
|
89
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
90
|
+
transformUniConfigToModelConfig(config) {
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
92
|
+
const openaiConfig = {
|
|
93
|
+
model: this._model,
|
|
94
|
+
store: false,
|
|
95
|
+
include: ["reasoning.encrypted_content"],
|
|
96
|
+
};
|
|
97
|
+
if (config.system_prompt !== undefined) {
|
|
98
|
+
openaiConfig.instructions = config.system_prompt;
|
|
99
|
+
}
|
|
100
|
+
if (config.max_tokens !== undefined) {
|
|
101
|
+
openaiConfig.max_output_tokens = config.max_tokens;
|
|
102
|
+
}
|
|
103
|
+
if (config.temperature !== undefined && config.temperature !== 1.0) {
|
|
104
|
+
throw new errors_1.UnsupportedParameterError({
|
|
105
|
+
client: this.constructor.name,
|
|
106
|
+
parameter: "temperature",
|
|
107
|
+
message: "GPT-6 does not support setting temperature.",
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
if (config.thinking_level !== undefined) {
|
|
111
|
+
openaiConfig.reasoning = {
|
|
112
|
+
effort: this._convertThinkingLevelToEffort(config.thinking_level),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
if (config.thinking_summary) {
|
|
116
|
+
// reasoning.summary stands on its own, with or without an effort (verified live
|
|
117
|
+
// 2026-09-03 on the OpenAI and OpenRouter endpoints). False needs no key: the
|
|
118
|
+
// Responses API returns no summary unless one is asked for.
|
|
119
|
+
openaiConfig.reasoning = openaiConfig.reasoning ?? {};
|
|
120
|
+
openaiConfig.reasoning.summary = "concise";
|
|
121
|
+
}
|
|
122
|
+
if (config.tools !== undefined) {
|
|
123
|
+
openaiConfig.tools = config.tools.map((tool) => ({
|
|
124
|
+
type: "function",
|
|
125
|
+
...tool,
|
|
126
|
+
}));
|
|
127
|
+
}
|
|
128
|
+
if (config.tool_choice !== undefined) {
|
|
129
|
+
openaiConfig.tool_choice = this._convertToolChoice(config.tool_choice);
|
|
130
|
+
}
|
|
131
|
+
if (config.fast_mode) {
|
|
132
|
+
openaiConfig.service_tier = "priority";
|
|
133
|
+
}
|
|
134
|
+
if (config.prompt_caching !== undefined &&
|
|
135
|
+
config.prompt_caching !== types_1.PromptCaching.ENABLE) {
|
|
136
|
+
throw new errors_1.UnsupportedParameterError({
|
|
137
|
+
client: this.constructor.name,
|
|
138
|
+
parameter: "prompt_caching",
|
|
139
|
+
message: "prompt_caching must be ENABLE for GPT-6.",
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
return openaiConfig;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Transform universal message format to OpenAI Responses API input format.
|
|
146
|
+
*/
|
|
147
|
+
transformUniMessageToModelInput(messages, _signal) {
|
|
148
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
149
|
+
const inputList = [];
|
|
150
|
+
for (const msg of messages) {
|
|
151
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
152
|
+
let contentItems = [];
|
|
153
|
+
let lastPhase = null;
|
|
154
|
+
for (const item of msg.content_items) {
|
|
155
|
+
// anything that is not message content becomes an input item of its own, so the
|
|
156
|
+
// text collected so far is flushed first to keep the order the model produced
|
|
157
|
+
if (item.type !== "text.done" &&
|
|
158
|
+
item.type !== "image_url.done" &&
|
|
159
|
+
contentItems.length > 0) {
|
|
160
|
+
// Every turn goes back as a typed message item — the Responses API's EasyInputMessage
|
|
161
|
+
// shape, where type "message" is valid for any role. A vLLM-style Responses server
|
|
162
|
+
// answers a bare { role: "assistant", content: [...] } item with a 400 on the turn that
|
|
163
|
+
// replays it and takes the typed form for every role; OpenAI, DeepSeek and MiniMax accept
|
|
164
|
+
// either shape. Nothing beyond that minimal shape goes out: an id or a status the server
|
|
165
|
+
// never sent would be an invention.
|
|
166
|
+
const entry = {
|
|
167
|
+
type: "message",
|
|
168
|
+
role: msg.role,
|
|
169
|
+
content: contentItems,
|
|
170
|
+
};
|
|
171
|
+
if (lastPhase !== null) {
|
|
172
|
+
entry.phase = lastPhase;
|
|
173
|
+
}
|
|
174
|
+
inputList.push(entry);
|
|
175
|
+
contentItems = [];
|
|
176
|
+
}
|
|
177
|
+
if (item.type === "text.done") {
|
|
178
|
+
const phase = item.fidelity?.phase;
|
|
179
|
+
if (msg.role === "assistant" && phase) {
|
|
180
|
+
// split different phases
|
|
181
|
+
if (lastPhase !== null &&
|
|
182
|
+
lastPhase !== phase &&
|
|
183
|
+
contentItems.length > 0) {
|
|
184
|
+
inputList.push({
|
|
185
|
+
type: "message",
|
|
186
|
+
role: msg.role,
|
|
187
|
+
content: contentItems,
|
|
188
|
+
phase: lastPhase,
|
|
189
|
+
});
|
|
190
|
+
contentItems = [];
|
|
191
|
+
}
|
|
192
|
+
lastPhase = phase;
|
|
193
|
+
}
|
|
194
|
+
if (msg.role === "user") {
|
|
195
|
+
contentItems.push({ type: "input_text", text: item.text });
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
contentItems.push({ type: "output_text", text: item.text });
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
else if (item.type === "image_url.done") {
|
|
202
|
+
contentItems.push(this._convertImageUrl(item.image_url));
|
|
203
|
+
}
|
|
204
|
+
else if (item.type === "thinking.done") {
|
|
205
|
+
// rebuild the reasoning item from the recorded wire fields: the thinking
|
|
206
|
+
// text goes back through the channel that carried it (histories recorded
|
|
207
|
+
// by the pre-channel client carry encrypted_content and stream summaries)
|
|
208
|
+
const fidelity = item.fidelity ?? {};
|
|
209
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
210
|
+
const reasoning = { type: "reasoning", summary: [] };
|
|
211
|
+
const summaryChannel = fidelity.channel === "summary" ||
|
|
212
|
+
(!("channel" in fidelity) && fidelity.encrypted_content != null);
|
|
213
|
+
if (summaryChannel) {
|
|
214
|
+
if (item.thinking) {
|
|
215
|
+
reasoning.summary = [
|
|
216
|
+
{ type: "summary_text", text: item.thinking },
|
|
217
|
+
];
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
else if (item.thinking) {
|
|
221
|
+
reasoning.content = [
|
|
222
|
+
{ type: "reasoning_text", text: item.thinking },
|
|
223
|
+
];
|
|
224
|
+
}
|
|
225
|
+
for (const key of ["encrypted_content", "signature", "format"]) {
|
|
226
|
+
if (fidelity[key] != null) {
|
|
227
|
+
reasoning[key] = fidelity[key];
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
inputList.push(reasoning);
|
|
231
|
+
}
|
|
232
|
+
else if (item.type === "tool_call.done") {
|
|
233
|
+
inputList.push({
|
|
234
|
+
type: "function_call",
|
|
235
|
+
call_id: item.tool_call_id,
|
|
236
|
+
name: item.name,
|
|
237
|
+
arguments: JSON.stringify(item.arguments),
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
else if (item.type === "tool_result.done") {
|
|
241
|
+
if (!item.tool_call_id) {
|
|
242
|
+
throw new Error("tool_call_id is required for tool result.");
|
|
243
|
+
}
|
|
244
|
+
// Tool results are input items
|
|
245
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
246
|
+
const imageParts = [];
|
|
247
|
+
if (item.images) {
|
|
248
|
+
for (const imageUrl of item.images) {
|
|
249
|
+
imageParts.push(this._convertImageUrl(imageUrl));
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
// a plain string is the form the Responses API documents for a text
|
|
253
|
+
// result and the one every endpoint fronting this model accepts; the
|
|
254
|
+
// content-part list is reserved for results carrying images
|
|
255
|
+
const output = imageParts.length > 0
|
|
256
|
+
? [{ type: "input_text", text: item.text }, ...imageParts]
|
|
257
|
+
: item.text;
|
|
258
|
+
inputList.push({
|
|
259
|
+
type: "function_call_output",
|
|
260
|
+
call_id: item.tool_call_id,
|
|
261
|
+
output,
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
throw new Error(`Unknown item: ${JSON.stringify(item)}`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
if (contentItems.length > 0) {
|
|
269
|
+
const entry = {
|
|
270
|
+
type: "message",
|
|
271
|
+
role: msg.role,
|
|
272
|
+
content: contentItems,
|
|
273
|
+
};
|
|
274
|
+
if (lastPhase !== null) {
|
|
275
|
+
entry.phase = lastPhase;
|
|
276
|
+
}
|
|
277
|
+
inputList.push(entry);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return inputList;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Transform one OpenAI Responses API stream event into a universal event, identifying items by
|
|
284
|
+
* output item id. An item needs no done: it is done when the next one begins or the stream
|
|
285
|
+
* ends.
|
|
286
|
+
*/
|
|
287
|
+
transformModelOutputToUniEvent(modelOutput) {
|
|
288
|
+
let eventType = "delta";
|
|
289
|
+
const contentItems = [];
|
|
290
|
+
let usageMetadata = null;
|
|
291
|
+
let finishReason = null;
|
|
292
|
+
const openaiEventType = modelOutput.type;
|
|
293
|
+
if (openaiEventType === "response.output_text.delta") {
|
|
294
|
+
contentItems.push({
|
|
295
|
+
type: "text.delta",
|
|
296
|
+
text: modelOutput.delta,
|
|
297
|
+
fidelity: { item_id: modelOutput.item_id },
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
else if (openaiEventType === "response.reasoning_summary_text.delta" ||
|
|
301
|
+
openaiEventType === "response.reasoning_text.delta") {
|
|
302
|
+
contentItems.push({
|
|
303
|
+
type: "thinking.delta",
|
|
304
|
+
thinking: modelOutput.delta,
|
|
305
|
+
fidelity: { item_id: modelOutput.item_id },
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
else if (openaiEventType === "response.output_item.added") {
|
|
309
|
+
// an item begins: a delta under its id, empty unless it carries the call's name or the
|
|
310
|
+
// message's phase, ends the item before it
|
|
311
|
+
const item = modelOutput.item;
|
|
312
|
+
if (item.type === "function_call") {
|
|
313
|
+
contentItems.push({
|
|
314
|
+
type: "tool_call.delta",
|
|
315
|
+
name: item.name,
|
|
316
|
+
arguments: "",
|
|
317
|
+
tool_call_id: item.call_id,
|
|
318
|
+
// a server that sends no item id still sends the call id
|
|
319
|
+
fidelity: { item_id: item.id || item.call_id },
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
else if (item.type === "message") {
|
|
323
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
324
|
+
const phase = item.phase;
|
|
325
|
+
contentItems.push({
|
|
326
|
+
type: "text.delta",
|
|
327
|
+
text: "",
|
|
328
|
+
fidelity: { item_id: item.id, ...(phase != null ? { phase } : {}) },
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
else if (item.type === "reasoning") {
|
|
332
|
+
contentItems.push({
|
|
333
|
+
type: "thinking.delta",
|
|
334
|
+
thinking: "",
|
|
335
|
+
fidelity: { item_id: item.id },
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
else if (openaiEventType === "response.output_item.done") {
|
|
340
|
+
const item = modelOutput.item;
|
|
341
|
+
if (item.type === "reasoning") {
|
|
342
|
+
// the completed item carries the canonical wire fields to send back on the
|
|
343
|
+
// next turn (identical to the response.completed copy, but adjacent to the
|
|
344
|
+
// thinking deltas so the fidelity lands on the item that carried the text);
|
|
345
|
+
// record the channel plus the fields the server demands back. This event is the
|
|
346
|
+
// only source of encrypted_content, because the streaming-events reference says
|
|
347
|
+
// of response.output_item.added: "For reasoning items, encrypted_content may be
|
|
348
|
+
// incomplete while the item is in progress. Use the reasoning item from the
|
|
349
|
+
// corresponding response.output_item.done event when passing it as input to a
|
|
350
|
+
// subsequent request."
|
|
351
|
+
const fidelity = { item_id: item.id };
|
|
352
|
+
if (item.summary && item.summary.length > 0) {
|
|
353
|
+
fidelity.channel = "summary";
|
|
354
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
355
|
+
}
|
|
356
|
+
else if (item.content?.length > 0) {
|
|
357
|
+
fidelity.channel = "content";
|
|
358
|
+
}
|
|
359
|
+
for (const key of ["encrypted_content", "signature", "format"]) {
|
|
360
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
361
|
+
if (item[key] != null) {
|
|
362
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
363
|
+
fidelity[key] = item[key];
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
contentItems.push({ type: "thinking.delta", thinking: "", fidelity });
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
else if (openaiEventType === "response.function_call_arguments.delta") {
|
|
370
|
+
contentItems.push({
|
|
371
|
+
type: "tool_call.delta",
|
|
372
|
+
name: "",
|
|
373
|
+
arguments: modelOutput.delta,
|
|
374
|
+
tool_call_id: "",
|
|
375
|
+
fidelity: { item_id: modelOutput.item_id },
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
else if (openaiEventType === "response.completed" ||
|
|
379
|
+
openaiEventType === "response.incomplete") {
|
|
380
|
+
eventType = "stop";
|
|
381
|
+
const response = modelOutput.response;
|
|
382
|
+
const finishReasonMapping = {
|
|
383
|
+
completed: "stop",
|
|
384
|
+
incomplete: "length",
|
|
385
|
+
};
|
|
386
|
+
if (response.status) {
|
|
387
|
+
finishReason = finishReasonMapping[response.status] || "unknown";
|
|
388
|
+
}
|
|
389
|
+
if (response.usage) {
|
|
390
|
+
const inputTokens = response.usage.input_tokens;
|
|
391
|
+
const outputTokens = response.usage.output_tokens;
|
|
392
|
+
const cachedTokens = response.usage.input_tokens_details.cached_tokens;
|
|
393
|
+
const reasoningTokens = response.usage.output_tokens_details.reasoning_tokens;
|
|
394
|
+
usageMetadata = {
|
|
395
|
+
cached_tokens: cachedTokens,
|
|
396
|
+
prompt_tokens: inputTokens - cachedTokens,
|
|
397
|
+
thoughts_tokens: reasoningTokens,
|
|
398
|
+
response_tokens: outputTokens - reasoningTokens,
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
else if ([
|
|
403
|
+
"response.created",
|
|
404
|
+
"response.in_progress",
|
|
405
|
+
"response.output_text.done",
|
|
406
|
+
"response.function_call_arguments.done",
|
|
407
|
+
"response.reasoning_summary_part.added",
|
|
408
|
+
"response.reasoning_summary_part.done",
|
|
409
|
+
"response.reasoning_summary_text.done",
|
|
410
|
+
"response.reasoning_text.done",
|
|
411
|
+
"response.content_part.added",
|
|
412
|
+
"response.content_part.done",
|
|
413
|
+
// gateway heartbeat on long generations; carries no content
|
|
414
|
+
"keepalive",
|
|
415
|
+
].includes(openaiEventType)) {
|
|
416
|
+
// lifecycle events, and repeats of what the deltas carry
|
|
417
|
+
}
|
|
418
|
+
else if ((0, utils_1.isDebugEnabled)()) {
|
|
419
|
+
throw new Error(`Unknown output: ${JSON.stringify(modelOutput)}`);
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
// a gateway injects its own events (heartbeats, cost tickers) into the stream, and
|
|
423
|
+
// killing a long generation over one costs more than dropping it
|
|
424
|
+
}
|
|
425
|
+
return {
|
|
426
|
+
role: "assistant",
|
|
427
|
+
event_type: eventType,
|
|
428
|
+
content_items: contentItems,
|
|
429
|
+
usage_metadata: usageMetadata,
|
|
430
|
+
finish_reason: finishReason,
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Stream generate using OpenAI Responses API with unified conversion methods.
|
|
435
|
+
*/
|
|
436
|
+
async *_streamingResponseInternal(options) {
|
|
437
|
+
const openaiConfig = this.transformUniConfigToModelConfig(options.config);
|
|
438
|
+
const inputList = this.transformUniMessageToModelInput(options.messages, options.signal);
|
|
439
|
+
const params = {
|
|
440
|
+
...openaiConfig,
|
|
441
|
+
input: inputList,
|
|
442
|
+
stream: true,
|
|
443
|
+
};
|
|
444
|
+
const stream = await this._client.responses.create(params, {
|
|
445
|
+
signal: options.signal,
|
|
446
|
+
});
|
|
447
|
+
for await (const event of stream) {
|
|
448
|
+
yield this.transformModelOutputToUniEvent(event);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* List the model ids the configured endpoint serves.
|
|
453
|
+
*
|
|
454
|
+
* @returns The model ids, in the order the endpoint returned them.
|
|
455
|
+
*/
|
|
456
|
+
async listModels() {
|
|
457
|
+
const models = [];
|
|
458
|
+
for await (const model of this._client.models.list()) {
|
|
459
|
+
models.push(model.id);
|
|
460
|
+
}
|
|
461
|
+
return models;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
exports.OpenAIOfficialClient = OpenAIOfficialClient;
|