@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.
Files changed (116) hide show
  1. package/README.md +121 -0
  2. package/dist/ant_messages/client.d.ts +59 -0
  3. package/dist/ant_messages/client.d.ts.map +1 -0
  4. package/dist/ant_messages/client.js +419 -0
  5. package/dist/ant_messages/index.d.ts +2 -0
  6. package/dist/ant_messages/index.d.ts.map +1 -0
  7. package/dist/ant_messages/index.js +18 -0
  8. package/dist/anthropic_official/client.d.ts +63 -0
  9. package/dist/anthropic_official/client.d.ts.map +1 -0
  10. package/dist/anthropic_official/client.js +540 -0
  11. package/dist/anthropic_official/index.d.ts +2 -0
  12. package/dist/anthropic_official/index.d.ts.map +1 -0
  13. package/dist/anthropic_official/index.js +18 -0
  14. package/dist/autoClient.d.ts +96 -0
  15. package/dist/autoClient.d.ts.map +1 -0
  16. package/dist/autoClient.js +258 -0
  17. package/dist/baseClient.d.ts +111 -0
  18. package/dist/baseClient.d.ts.map +1 -0
  19. package/dist/baseClient.js +284 -0
  20. package/dist/deepseek_official/client.d.ts +60 -0
  21. package/dist/deepseek_official/client.d.ts.map +1 -0
  22. package/dist/deepseek_official/client.js +407 -0
  23. package/dist/deepseek_official/index.d.ts +2 -0
  24. package/dist/deepseek_official/index.d.ts.map +1 -0
  25. package/dist/deepseek_official/index.js +18 -0
  26. package/dist/errors.d.ts +84 -0
  27. package/dist/errors.d.ts.map +1 -0
  28. package/dist/errors.js +140 -0
  29. package/dist/gemini_generate_content/client.d.ts +86 -0
  30. package/dist/gemini_generate_content/client.d.ts.map +1 -0
  31. package/dist/gemini_generate_content/client.js +809 -0
  32. package/dist/gemini_generate_content/index.d.ts +2 -0
  33. package/dist/gemini_generate_content/index.d.ts.map +1 -0
  34. package/dist/gemini_generate_content/index.js +18 -0
  35. package/dist/gemini_official/client.d.ts +87 -0
  36. package/dist/gemini_official/client.d.ts.map +1 -0
  37. package/dist/gemini_official/client.js +780 -0
  38. package/dist/gemini_official/index.d.ts +2 -0
  39. package/dist/gemini_official/index.d.ts.map +1 -0
  40. package/dist/gemini_official/index.js +18 -0
  41. package/dist/index.d.ts +6 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +44 -0
  44. package/dist/integration/index.d.ts +1 -0
  45. package/dist/integration/index.d.ts.map +1 -0
  46. package/dist/integration/index.js +14 -0
  47. package/dist/integration/playground.d.ts +17 -0
  48. package/dist/integration/playground.d.ts.map +1 -0
  49. package/dist/integration/playground.js +3246 -0
  50. package/dist/integration/tracer.d.ts +188 -0
  51. package/dist/integration/tracer.d.ts.map +1 -0
  52. package/dist/integration/tracer.js +1928 -0
  53. package/dist/legacy.d.ts +13 -0
  54. package/dist/legacy.d.ts.map +1 -0
  55. package/dist/legacy.js +59 -0
  56. package/dist/minimax_official/client.d.ts +43 -0
  57. package/dist/minimax_official/client.d.ts.map +1 -0
  58. package/dist/minimax_official/client.js +346 -0
  59. package/dist/minimax_official/index.d.ts +2 -0
  60. package/dist/minimax_official/index.d.ts.map +1 -0
  61. package/dist/minimax_official/index.js +18 -0
  62. package/dist/moonshot_official/client.d.ts +73 -0
  63. package/dist/moonshot_official/client.d.ts.map +1 -0
  64. package/dist/moonshot_official/client.js +477 -0
  65. package/dist/moonshot_official/index.d.ts +2 -0
  66. package/dist/moonshot_official/index.d.ts.map +1 -0
  67. package/dist/moonshot_official/index.js +18 -0
  68. package/dist/openai_chat/client.d.ts +67 -0
  69. package/dist/openai_chat/client.d.ts.map +1 -0
  70. package/dist/openai_chat/client.js +419 -0
  71. package/dist/openai_chat/index.d.ts +2 -0
  72. package/dist/openai_chat/index.d.ts.map +1 -0
  73. package/dist/openai_chat/index.js +18 -0
  74. package/dist/openai_chat_vllm_adapter/client.d.ts +15 -0
  75. package/dist/openai_chat_vllm_adapter/client.d.ts.map +1 -0
  76. package/dist/openai_chat_vllm_adapter/client.js +118 -0
  77. package/dist/openai_chat_vllm_adapter/index.d.ts +2 -0
  78. package/dist/openai_chat_vllm_adapter/index.d.ts.map +1 -0
  79. package/dist/openai_chat_vllm_adapter/index.js +5 -0
  80. package/dist/openai_embedding/client.d.ts +46 -0
  81. package/dist/openai_embedding/client.d.ts.map +1 -0
  82. package/dist/openai_embedding/client.js +124 -0
  83. package/dist/openai_embedding/index.d.ts +2 -0
  84. package/dist/openai_embedding/index.d.ts.map +1 -0
  85. package/dist/openai_embedding/index.js +18 -0
  86. package/dist/openai_official/client.d.ts +61 -0
  87. package/dist/openai_official/client.d.ts.map +1 -0
  88. package/dist/openai_official/client.js +464 -0
  89. package/dist/openai_official/index.d.ts +2 -0
  90. package/dist/openai_official/index.d.ts.map +1 -0
  91. package/dist/openai_official/index.js +18 -0
  92. package/dist/openai_responses/client.d.ts +61 -0
  93. package/dist/openai_responses/client.d.ts.map +1 -0
  94. package/dist/openai_responses/client.js +449 -0
  95. package/dist/openai_responses/index.d.ts +2 -0
  96. package/dist/openai_responses/index.d.ts.map +1 -0
  97. package/dist/openai_responses/index.js +18 -0
  98. package/dist/registry.d.ts +49 -0
  99. package/dist/registry.d.ts.map +1 -0
  100. package/dist/registry.js +798 -0
  101. package/dist/streamItems.d.ts +36 -0
  102. package/dist/streamItems.d.ts.map +1 -0
  103. package/dist/streamItems.js +183 -0
  104. package/dist/types.d.ts +190 -0
  105. package/dist/types.d.ts.map +1 -0
  106. package/dist/types.js +37 -0
  107. package/dist/utils.d.ts +99 -0
  108. package/dist/utils.d.ts.map +1 -0
  109. package/dist/utils.js +312 -0
  110. package/dist/zai_official/client.d.ts +78 -0
  111. package/dist/zai_official/client.d.ts.map +1 -0
  112. package/dist/zai_official/client.js +420 -0
  113. package/dist/zai_official/index.d.ts +2 -0
  114. package/dist/zai_official/index.d.ts.map +1 -0
  115. package/dist/zai_official/index.js +18 -0
  116. package/package.json +68 -0
@@ -0,0 +1,2 @@
1
+ export { OpenAIOfficialClient } from "./client";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -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,2 @@
1
+ export { OpenaiResponsesClient } from "./client";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -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"}