@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 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/openai_official/index.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,oBAAoB,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.OpenAIOfficialClient = void 0;
|
|
17
|
+
var client_1 = require("./client");
|
|
18
|
+
Object.defineProperty(exports, "OpenAIOfficialClient", { enumerable: true, get: function () { return client_1.OpenAIOfficialClient; } });
|
|
@@ -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
|
+
* OpenAI Responses-compatible client implementation.
|
|
6
|
+
*/
|
|
7
|
+
export declare class OpenaiResponsesClient extends LLMClient {
|
|
8
|
+
protected _model: string;
|
|
9
|
+
private _client;
|
|
10
|
+
/**
|
|
11
|
+
* Initialize OpenAI Responses-compatible client with model, API key, and base URL.
|
|
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 the Responses API reasoning effort.
|
|
21
|
+
*/
|
|
22
|
+
private _convertThinkingLevelToEffort;
|
|
23
|
+
/**
|
|
24
|
+
* Convert ToolChoice to the Responses API 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-compatible configuration.
|
|
34
|
+
*/
|
|
35
|
+
transformUniConfigToModelConfig(config: UniConfig): any;
|
|
36
|
+
/**
|
|
37
|
+
* Transform universal message format to OpenAI Responses-compatible input format.
|
|
38
|
+
*/
|
|
39
|
+
transformUniMessageToModelInput(messages: UniMessage[], _signal?: AbortSignal): ResponseInputItem[];
|
|
40
|
+
/**
|
|
41
|
+
* Transform one OpenAI Responses-compatible stream event into a universal event, identifying
|
|
42
|
+
* items by output item id. An item needs no done: it is done when the next one begins or the
|
|
43
|
+
* stream ends.
|
|
44
|
+
*/
|
|
45
|
+
transformModelOutputToUniEvent(modelOutput: ResponseStreamEvent): UniEvent;
|
|
46
|
+
/**
|
|
47
|
+
* Stream generate using an OpenAI Responses-compatible 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_responses/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,qBAAsB,SAAQ,SAAS;IAClD,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;IAmBrC;;OAEG;IAEH,OAAO,CAAC,kBAAkB;IAW1B;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAWxB;;OAEG;IAEH,+BAA+B,CAAC,MAAM,EAAE,SAAS,GAAG,GAAG;IA8DvD;;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;IA0I1E;;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,449 @@
|
|
|
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.OpenaiResponsesClient = 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
|
+
* OpenAI Responses-compatible client implementation.
|
|
27
|
+
*/
|
|
28
|
+
class OpenaiResponsesClient extends baseClient_1.LLMClient {
|
|
29
|
+
/**
|
|
30
|
+
* Initialize OpenAI Responses-compatible client with model, API key, and base URL.
|
|
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 the Responses API reasoning effort.
|
|
44
|
+
*/
|
|
45
|
+
_convertThinkingLevelToEffort(thinkingLevel) {
|
|
46
|
+
if (thinkingLevel === types_1.ThinkingLevel.NONE && this._model.includes("gpt-6")) {
|
|
47
|
+
// a gateway serving GPT-6 forwards the effort to OpenAI, which rejects "none" and
|
|
48
|
+
// "minimal" with a 400 (verified live 2026-09-09 against api.openai.com), so NONE
|
|
49
|
+
// degrades to the lowest effort the generation accepts.
|
|
50
|
+
return "low";
|
|
51
|
+
}
|
|
52
|
+
const mapping = {
|
|
53
|
+
[types_1.ThinkingLevel.NONE]: "none",
|
|
54
|
+
[types_1.ThinkingLevel.LOW]: "low",
|
|
55
|
+
[types_1.ThinkingLevel.MEDIUM]: "medium",
|
|
56
|
+
[types_1.ThinkingLevel.HIGH]: "high",
|
|
57
|
+
[types_1.ThinkingLevel.XHIGH]: "xhigh",
|
|
58
|
+
[types_1.ThinkingLevel.MAX]: "max",
|
|
59
|
+
};
|
|
60
|
+
return mapping[thinkingLevel];
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Convert ToolChoice to the Responses API tool_choice format with allowed tools support.
|
|
64
|
+
*/
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
66
|
+
_convertToolChoice(toolChoice) {
|
|
67
|
+
if (Array.isArray(toolChoice)) {
|
|
68
|
+
return {
|
|
69
|
+
mode: "required",
|
|
70
|
+
tools: toolChoice.map((name) => ({ type: "function", name })),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return toolChoice;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Convert an image URL to an input_image item, at the detail the API needs
|
|
77
|
+
* to read it.
|
|
78
|
+
*/
|
|
79
|
+
_convertImageUrl(imageUrl) {
|
|
80
|
+
const detail = (0, utils_1.openaiImageDetail)(this._model, imageUrl);
|
|
81
|
+
return detail
|
|
82
|
+
? { type: "input_image", image_url: imageUrl, detail }
|
|
83
|
+
: { type: "input_image", image_url: imageUrl };
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Transform universal configuration to OpenAI Responses-compatible configuration.
|
|
87
|
+
*/
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
89
|
+
transformUniConfigToModelConfig(config) {
|
|
90
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
91
|
+
const openaiConfig = {
|
|
92
|
+
model: this._model,
|
|
93
|
+
store: false,
|
|
94
|
+
};
|
|
95
|
+
if (config.system_prompt !== undefined) {
|
|
96
|
+
openaiConfig.instructions = config.system_prompt;
|
|
97
|
+
}
|
|
98
|
+
if (config.max_tokens !== undefined) {
|
|
99
|
+
openaiConfig.max_output_tokens = config.max_tokens;
|
|
100
|
+
}
|
|
101
|
+
if (config.temperature !== undefined) {
|
|
102
|
+
openaiConfig.temperature = config.temperature;
|
|
103
|
+
}
|
|
104
|
+
// Unlike the model-specific Responses clients, the summary stays inside this branch:
|
|
105
|
+
// OpenRouter reads a reasoning object carrying no effort as "reasoning disabled" and
|
|
106
|
+
// refuses it on a forced-thinking model -- "Reasoning is mandatory for this endpoint
|
|
107
|
+
// and cannot be disabled" (400, verified live 2026-09-03 with z-ai/glm-5.3) -- so a
|
|
108
|
+
// summary sent on its own would turn a dropped value into a failed request.
|
|
109
|
+
if (config.thinking_level !== undefined) {
|
|
110
|
+
openaiConfig.reasoning = {
|
|
111
|
+
effort: this._convertThinkingLevelToEffort(config.thinking_level),
|
|
112
|
+
};
|
|
113
|
+
if (config.thinking_summary) {
|
|
114
|
+
openaiConfig.reasoning.summary = "concise";
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (config.tools !== undefined) {
|
|
118
|
+
openaiConfig.tools = config.tools.map((tool) => ({
|
|
119
|
+
type: "function",
|
|
120
|
+
...tool,
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
if (config.tool_choice !== undefined) {
|
|
124
|
+
openaiConfig.tool_choice = this._convertToolChoice(config.tool_choice);
|
|
125
|
+
}
|
|
126
|
+
if (config.fast_mode) {
|
|
127
|
+
openaiConfig.service_tier = "priority";
|
|
128
|
+
}
|
|
129
|
+
if (config.prompt_caching !== undefined &&
|
|
130
|
+
config.prompt_caching !== types_1.PromptCaching.ENABLE) {
|
|
131
|
+
throw new errors_1.UnsupportedParameterError({
|
|
132
|
+
client: this.constructor.name,
|
|
133
|
+
parameter: "prompt_caching",
|
|
134
|
+
message: "prompt_caching must be ENABLE for the Responses API.",
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
return openaiConfig;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Transform universal message format to OpenAI Responses-compatible input format.
|
|
141
|
+
*/
|
|
142
|
+
transformUniMessageToModelInput(messages, _signal) {
|
|
143
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
144
|
+
const inputList = [];
|
|
145
|
+
for (const msg of messages) {
|
|
146
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
147
|
+
let contentItems = [];
|
|
148
|
+
let lastPhase = null;
|
|
149
|
+
for (const item of msg.content_items) {
|
|
150
|
+
// anything that is not message content becomes an input item of its own, so the
|
|
151
|
+
// text collected so far is flushed first to keep the original order: a server that
|
|
152
|
+
// merges a function call into the adjacent assistant message rejects a call whose
|
|
153
|
+
// output does not follow it (DeepSeek answers "No tool output found for tool call")
|
|
154
|
+
if (item.type !== "text.done" &&
|
|
155
|
+
item.type !== "image_url.done" &&
|
|
156
|
+
contentItems.length > 0) {
|
|
157
|
+
// Every turn goes back as a typed message item — the Responses API's EasyInputMessage
|
|
158
|
+
// shape, where type "message" is valid for any role. A vLLM-style Responses server
|
|
159
|
+
// answers a bare { role: "assistant", content: [...] } item with a 400 on the turn that
|
|
160
|
+
// replays it and takes the typed form for every role; OpenAI, DeepSeek and MiniMax accept
|
|
161
|
+
// either shape. Nothing beyond that minimal shape goes out: an id or a status the server
|
|
162
|
+
// never sent would be an invention.
|
|
163
|
+
const entry = {
|
|
164
|
+
type: "message",
|
|
165
|
+
role: msg.role,
|
|
166
|
+
content: contentItems,
|
|
167
|
+
};
|
|
168
|
+
if (lastPhase !== null) {
|
|
169
|
+
entry.phase = lastPhase;
|
|
170
|
+
}
|
|
171
|
+
inputList.push(entry);
|
|
172
|
+
contentItems = [];
|
|
173
|
+
}
|
|
174
|
+
if (item.type === "text.done") {
|
|
175
|
+
const phase = item.fidelity?.phase;
|
|
176
|
+
if (msg.role === "assistant" && phase) {
|
|
177
|
+
// split different phases
|
|
178
|
+
if (lastPhase !== null &&
|
|
179
|
+
lastPhase !== phase &&
|
|
180
|
+
contentItems.length > 0) {
|
|
181
|
+
inputList.push({
|
|
182
|
+
type: "message",
|
|
183
|
+
role: msg.role,
|
|
184
|
+
content: contentItems,
|
|
185
|
+
phase: lastPhase,
|
|
186
|
+
});
|
|
187
|
+
contentItems = [];
|
|
188
|
+
}
|
|
189
|
+
lastPhase = phase;
|
|
190
|
+
}
|
|
191
|
+
if (msg.role === "user") {
|
|
192
|
+
contentItems.push({ type: "input_text", text: item.text });
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
contentItems.push({ type: "output_text", text: item.text });
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
else if (item.type === "image_url.done") {
|
|
199
|
+
contentItems.push(this._convertImageUrl(item.image_url));
|
|
200
|
+
}
|
|
201
|
+
else if (item.type === "thinking.done") {
|
|
202
|
+
// the wire shape differs by server: OpenAI-style servers stream summaries and
|
|
203
|
+
// demand the summary key back (with encrypted_content preserved), while
|
|
204
|
+
// DeepSeek/Z.AI/MiniMax-style servers accept a reasoning item rebuilt from the
|
|
205
|
+
// thinking text alone as reasoning_text content
|
|
206
|
+
const fidelity = item.fidelity ?? {};
|
|
207
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
208
|
+
const reasoning = { type: "reasoning", summary: [] };
|
|
209
|
+
if (fidelity.channel === "summary") {
|
|
210
|
+
if (item.thinking) {
|
|
211
|
+
reasoning.summary = [
|
|
212
|
+
{ type: "summary_text", text: item.thinking },
|
|
213
|
+
];
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
else if (item.thinking) {
|
|
217
|
+
reasoning.content = [
|
|
218
|
+
{ type: "reasoning_text", text: item.thinking },
|
|
219
|
+
];
|
|
220
|
+
}
|
|
221
|
+
for (const key of ["encrypted_content", "signature", "format"]) {
|
|
222
|
+
if (fidelity[key] != null) {
|
|
223
|
+
reasoning[key] = fidelity[key];
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
inputList.push(reasoning);
|
|
227
|
+
}
|
|
228
|
+
else if (item.type === "tool_call.done") {
|
|
229
|
+
inputList.push({
|
|
230
|
+
type: "function_call",
|
|
231
|
+
call_id: item.tool_call_id,
|
|
232
|
+
name: item.name,
|
|
233
|
+
arguments: JSON.stringify(item.arguments),
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
else if (item.type === "tool_result.done") {
|
|
237
|
+
if (!item.tool_call_id) {
|
|
238
|
+
throw new Error("tool_call_id is required for tool result.");
|
|
239
|
+
}
|
|
240
|
+
// NOTE: tool results are input items
|
|
241
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
242
|
+
const imageParts = [];
|
|
243
|
+
if (item.images) {
|
|
244
|
+
for (const imageUrl of item.images) {
|
|
245
|
+
imageParts.push(this._convertImageUrl(imageUrl));
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// a plain string is the form every OpenAI-compatible server accepts for a text
|
|
249
|
+
// result; the content-part list is reserved for results carrying images, which
|
|
250
|
+
// only servers with multimodal tool messages take
|
|
251
|
+
const output = imageParts.length > 0
|
|
252
|
+
? [{ type: "input_text", text: item.text }, ...imageParts]
|
|
253
|
+
: item.text;
|
|
254
|
+
inputList.push({
|
|
255
|
+
type: "function_call_output",
|
|
256
|
+
call_id: item.tool_call_id,
|
|
257
|
+
output,
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
throw new Error(`Unknown item: ${JSON.stringify(item)}`);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
if (contentItems.length > 0) {
|
|
265
|
+
const entry = {
|
|
266
|
+
type: "message",
|
|
267
|
+
role: msg.role,
|
|
268
|
+
content: contentItems,
|
|
269
|
+
};
|
|
270
|
+
if (lastPhase !== null) {
|
|
271
|
+
entry.phase = lastPhase;
|
|
272
|
+
}
|
|
273
|
+
inputList.push(entry);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return inputList;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Transform one OpenAI Responses-compatible stream event into a universal event, identifying
|
|
280
|
+
* items by output item id. An item needs no done: it is done when the next one begins or the
|
|
281
|
+
* stream ends.
|
|
282
|
+
*/
|
|
283
|
+
transformModelOutputToUniEvent(modelOutput) {
|
|
284
|
+
let eventType = "delta";
|
|
285
|
+
const contentItems = [];
|
|
286
|
+
let usageMetadata = null;
|
|
287
|
+
let finishReason = null;
|
|
288
|
+
const openaiEventType = modelOutput.type;
|
|
289
|
+
if (openaiEventType === "response.output_text.delta") {
|
|
290
|
+
contentItems.push({
|
|
291
|
+
type: "text.delta",
|
|
292
|
+
text: modelOutput.delta,
|
|
293
|
+
fidelity: { item_id: modelOutput.item_id },
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
else if (openaiEventType === "response.reasoning_text.delta" ||
|
|
297
|
+
openaiEventType === "response.reasoning_summary_text.delta") {
|
|
298
|
+
contentItems.push({
|
|
299
|
+
type: "thinking.delta",
|
|
300
|
+
thinking: modelOutput.delta,
|
|
301
|
+
fidelity: { item_id: modelOutput.item_id },
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
else if (openaiEventType === "response.output_item.added") {
|
|
305
|
+
// an item begins: a delta under its id, empty unless it carries the call's name or the
|
|
306
|
+
// message's phase, ends the item before it
|
|
307
|
+
const item = modelOutput.item;
|
|
308
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
309
|
+
const phase = item.phase;
|
|
310
|
+
if (item.type === "function_call") {
|
|
311
|
+
contentItems.push({
|
|
312
|
+
type: "tool_call.delta",
|
|
313
|
+
name: item.name,
|
|
314
|
+
arguments: "",
|
|
315
|
+
tool_call_id: item.call_id,
|
|
316
|
+
// a server that sends no item id still sends the call id
|
|
317
|
+
fidelity: { item_id: item.id || item.call_id },
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
else if (item.type === "message") {
|
|
321
|
+
contentItems.push({
|
|
322
|
+
type: "text.delta",
|
|
323
|
+
text: "",
|
|
324
|
+
fidelity: { item_id: item.id, ...(phase ? { phase } : {}) },
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
else if (item.type === "reasoning") {
|
|
328
|
+
contentItems.push({
|
|
329
|
+
type: "thinking.delta",
|
|
330
|
+
thinking: "",
|
|
331
|
+
fidelity: { item_id: item.id },
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
else if (openaiEventType === "response.output_item.done") {
|
|
336
|
+
const item = modelOutput.item;
|
|
337
|
+
if (item.type === "reasoning") {
|
|
338
|
+
// the last delta of a reasoning item: the wire shape of the completed item, so a
|
|
339
|
+
// replay reproduces the channel that carried the thinking plus the fields the server
|
|
340
|
+
// demands back
|
|
341
|
+
const fidelity = { item_id: item.id };
|
|
342
|
+
if (item.summary && item.summary.length > 0) {
|
|
343
|
+
fidelity.channel = "summary";
|
|
344
|
+
}
|
|
345
|
+
for (const key of ["encrypted_content", "signature", "format"]) {
|
|
346
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
347
|
+
if (item[key] != null) {
|
|
348
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
349
|
+
fidelity[key] = item[key];
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
contentItems.push({ type: "thinking.delta", thinking: "", fidelity });
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
else if (openaiEventType === "response.function_call_arguments.delta") {
|
|
356
|
+
contentItems.push({
|
|
357
|
+
type: "tool_call.delta",
|
|
358
|
+
name: "",
|
|
359
|
+
arguments: modelOutput.delta,
|
|
360
|
+
tool_call_id: "",
|
|
361
|
+
fidelity: { item_id: modelOutput.item_id },
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
else if (openaiEventType === "response.completed" ||
|
|
365
|
+
openaiEventType === "response.incomplete") {
|
|
366
|
+
eventType = "stop";
|
|
367
|
+
const response = modelOutput.response;
|
|
368
|
+
const finishReasonMapping = {
|
|
369
|
+
completed: "stop",
|
|
370
|
+
incomplete: "length",
|
|
371
|
+
};
|
|
372
|
+
if (response.status) {
|
|
373
|
+
finishReason = finishReasonMapping[response.status] || "unknown";
|
|
374
|
+
}
|
|
375
|
+
if (response.usage) {
|
|
376
|
+
// some servers drop the detail blocks (e.g. MiniMax on truncation), so default to zero
|
|
377
|
+
const cachedTokens = response.usage.input_tokens_details?.cached_tokens || 0;
|
|
378
|
+
const reasoningTokens = response.usage.output_tokens_details?.reasoning_tokens || 0;
|
|
379
|
+
usageMetadata = {
|
|
380
|
+
cached_tokens: cachedTokens,
|
|
381
|
+
prompt_tokens: response.usage.input_tokens - cachedTokens,
|
|
382
|
+
thoughts_tokens: reasoningTokens,
|
|
383
|
+
response_tokens: response.usage.output_tokens - reasoningTokens,
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
else if ([
|
|
388
|
+
"response.created",
|
|
389
|
+
"response.in_progress",
|
|
390
|
+
"response.output_text.done",
|
|
391
|
+
"response.function_call_arguments.done",
|
|
392
|
+
"response.reasoning_text.done",
|
|
393
|
+
"response.reasoning_summary_part.added",
|
|
394
|
+
"response.reasoning_summary_part.done",
|
|
395
|
+
"response.reasoning_summary_text.done",
|
|
396
|
+
"response.content_part.added",
|
|
397
|
+
"response.content_part.done",
|
|
398
|
+
// gateway heartbeat on long generations; carries no content
|
|
399
|
+
"keepalive",
|
|
400
|
+
].includes(openaiEventType)) {
|
|
401
|
+
// lifecycle events, and repeats of what the deltas carry
|
|
402
|
+
}
|
|
403
|
+
else if ((0, utils_1.isDebugEnabled)()) {
|
|
404
|
+
throw new Error(`Unknown output: ${JSON.stringify(modelOutput)}`);
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
// a gateway injects its own events (heartbeats, cost tickers) into the stream, and
|
|
408
|
+
// killing a long generation over one costs more than dropping it
|
|
409
|
+
}
|
|
410
|
+
return {
|
|
411
|
+
role: "assistant",
|
|
412
|
+
event_type: eventType,
|
|
413
|
+
content_items: contentItems,
|
|
414
|
+
usage_metadata: usageMetadata,
|
|
415
|
+
finish_reason: finishReason,
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Stream generate using an OpenAI Responses-compatible API with unified conversion methods.
|
|
420
|
+
*/
|
|
421
|
+
async *_streamingResponseInternal(options) {
|
|
422
|
+
const openaiConfig = this.transformUniConfigToModelConfig(options.config);
|
|
423
|
+
const inputList = this.transformUniMessageToModelInput(options.messages, options.signal);
|
|
424
|
+
const params = {
|
|
425
|
+
...openaiConfig,
|
|
426
|
+
input: inputList,
|
|
427
|
+
stream: true,
|
|
428
|
+
};
|
|
429
|
+
const stream = await this._client.responses.create(params, {
|
|
430
|
+
signal: options.signal,
|
|
431
|
+
});
|
|
432
|
+
for await (const event of stream) {
|
|
433
|
+
yield this.transformModelOutputToUniEvent(event);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* List the model ids the configured endpoint serves.
|
|
438
|
+
*
|
|
439
|
+
* @returns The model ids, in the order the endpoint returned them.
|
|
440
|
+
*/
|
|
441
|
+
async listModels() {
|
|
442
|
+
const models = [];
|
|
443
|
+
for await (const model of this._client.models.list()) {
|
|
444
|
+
models.push(model.id);
|
|
445
|
+
}
|
|
446
|
+
return models;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
exports.OpenaiResponsesClient = OpenaiResponsesClient;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/openai_responses/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.OpenaiResponsesClient = void 0;
|
|
17
|
+
var client_1 = require("./client");
|
|
18
|
+
Object.defineProperty(exports, "OpenaiResponsesClient", { enumerable: true, get: function () { return client_1.OpenaiResponsesClient; } });
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export type Modality = "Text" | "Image" | "Video" | "Audio" | "Embed";
|
|
2
|
+
export type Currency = "USD" | "CNY";
|
|
3
|
+
/**
|
|
4
|
+
* List prices per million tokens for MMSP's usage buckets.
|
|
5
|
+
*
|
|
6
|
+
* Keys mirror `usage_metadata`: `cached_tokens` (cache-hit price, absent when
|
|
7
|
+
* the platform publishes none), `prompt_tokens` (non-cached input), and
|
|
8
|
+
* `thoughts_tokens`/`response_tokens`, which both carry the vendor's output
|
|
9
|
+
* price. Values are in the currency requested from listSupportedModels.
|
|
10
|
+
*/
|
|
11
|
+
export interface ModelPricing {
|
|
12
|
+
currency: Currency;
|
|
13
|
+
prompt_tokens: number;
|
|
14
|
+
thoughts_tokens: number;
|
|
15
|
+
response_tokens: number;
|
|
16
|
+
cached_tokens?: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* One supported model entry.
|
|
20
|
+
*
|
|
21
|
+
* (model, base_url, client) maps directly onto the AutoLLMClient constructor:
|
|
22
|
+
* `new AutoLLMClient({ model, baseUrl: base_url, clientType: client })`.
|
|
23
|
+
* Modalities describe what is usable through that client; `context_window` and
|
|
24
|
+
* `pricing` are omitted where the platform publishes no authoritative value.
|
|
25
|
+
*
|
|
26
|
+
* `pricing` is always the LIST price. A running promotion is deliberately not recorded: the
|
|
27
|
+
* registry's job is the catalog price, and applying a promotion is the consumer's.
|
|
28
|
+
*/
|
|
29
|
+
export interface SupportedModel {
|
|
30
|
+
model: string;
|
|
31
|
+
base_url: string;
|
|
32
|
+
client: string;
|
|
33
|
+
input_modalities: Modality[];
|
|
34
|
+
output_modalities: Modality[];
|
|
35
|
+
context_window?: number;
|
|
36
|
+
pricing?: ModelPricing;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* List supported models with base URL, client, modalities, context window, and
|
|
40
|
+
* pricing.
|
|
41
|
+
*
|
|
42
|
+
* Covers the official vendor endpoints plus the OpenRouter and SiliconFlow
|
|
43
|
+
* platforms; `client` is the `clientType` token that routes the model to its
|
|
44
|
+
* protocol client. Prices are per million tokens for MMSP's usage buckets
|
|
45
|
+
* (cached_tokens, prompt_tokens, thoughts_tokens, response_tokens), stored in
|
|
46
|
+
* USD and converted to `currency` at 7 CNY/USD on request.
|
|
47
|
+
*/
|
|
48
|
+
export declare function listSupportedModels(currency?: Currency): SupportedModel[];
|
|
49
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AACtE,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,KAAK,CAAC;AAErC;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,QAAQ,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,QAAQ,EAAE,CAAC;IAC7B,iBAAiB,EAAE,QAAQ,EAAE,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB;AA0wBD;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,GAAE,QAAgB,GACzB,cAAc,EAAE,CASlB"}
|