@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
package/README.md ADDED
@@ -0,0 +1,121 @@
1
+ # MMSP TypeScript Implementation
2
+
3
+ This directory contains the TypeScript implementation of MMSP, mirroring the Python implementation in `src_py/`.
4
+
5
+ ## Building
6
+
7
+ ```bash
8
+ make install # Install dependencies
9
+ make build # Build TypeScript to JavaScript
10
+ make lint # Run ESLint
11
+ make test # Run tests
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ ### Basic Client Usage
17
+
18
+ ```typescript
19
+ import { AutoLLMClient } from "@prismshadow/mmsp";
20
+
21
+ process.env.OPENAI_API_KEY = "your-openai-api-key";
22
+
23
+ async function main() {
24
+ // The official OpenAI client, named by the model id's family
25
+ const client = new AutoLLMClient({ model: "gpt-5.5" });
26
+ // The same, spelled out, with the key given in code:
27
+ // const client = new AutoLLMClient({ model: "gpt-5.5", clientType: "openai-official", apiKey: "your-openai-api-key" });
28
+ // A compatible client, for any endpoint that serves OpenAI Chat Completions:
29
+ // const client = new AutoLLMClient({ model: "custom-model", clientType: "openai-chat", baseUrl: "http://127.0.0.1:8000/v1/", apiKey: "none" });
30
+ // For Gemini on Google Vertex AI, the service-account JSON key is the API key:
31
+ // const client = new AutoLLMClient({ model: "gemini-3.8-flash", apiKey: fs.readFileSync("service-account.json", "utf8") });
32
+
33
+ for await (const event of client.streamingResponseStateful({
34
+ message: {
35
+ role: "user",
36
+ content_items: [{ type: "text.done", text: "Hello!" }],
37
+ },
38
+ config: {},
39
+ })) {
40
+ console.log(event);
41
+ }
42
+ }
43
+
44
+ main().catch(console.error);
45
+ ```
46
+
47
+ `clientType` names one of the official clients (`openai-official`, `anthropic-official`, `gemini-official`, `zai-official`, `moonshot-official`, `deepseek-official`, `minimax-official`) or one of the compatible clients (`openai-responses`, `openai-chat`, `openai-chat-vllm-adapter`, `openai-embedding`, `ant-messages`, `gemini-generate-content`). It may be omitted for a model id that begins with a known family (`gpt-`, `text-embedding-`, `claude-`, `gemini-`, `glm-`, `kimi-`, `deepseek-`, `minimax-`), which names its official client; any other id throws and asks for one.
48
+
49
+ A Vertex AI service-account key is served through generateContent, because Vertex AI's Interactions endpoint serves none of the Gemini models; any other Gemini key uses the Interactions API. `clientType: "gemini-generate-content"` names generateContent explicitly, for gateways that proxy it.
50
+
51
+ Both streaming methods yield `delta` events, each carrying exactly one content item, then exactly one `stop` event, always last, carrying `usage_metadata` and `finish_reason`. Each item streams as one or more `.delta` fragments (`text.delta`, `tool_call.delta`, …) followed by its complete `.done` item (`text.done`, `tool_call.done`, …); items never interleave.
52
+
53
+ ### History Management
54
+
55
+ ```typescript
56
+ // Get current history
57
+ const history = client.getHistory();
58
+
59
+ // Clear all history
60
+ client.clearHistory();
61
+
62
+ // Replace history with a saved copy
63
+ client.setHistory(history);
64
+ ```
65
+
66
+ Messages hold complete items only, typed with a `.done` suffix. Item types without the suffix, saved before 0.5.0, are still accepted with a deprecation warning until 0.6.0; `normalizeLegacyMessages(messages)` converts stored messages.
67
+
68
+ ### Tracer Usage
69
+
70
+ Save and browse conversation history with a web interface:
71
+
72
+ ```typescript
73
+ import { Tracer } from "@prismshadow/mmsp/integration/tracer";
74
+
75
+ // Create a tracer instance
76
+ const tracer = new Tracer("./cache");
77
+
78
+ // Save conversation history
79
+ const model = "gpt-5.5";
80
+ const history = [
81
+ { role: "user", content_items: [{ type: "text.done", text: "Hello!" }] },
82
+ {
83
+ role: "assistant",
84
+ content_items: [{ type: "text.done", text: "Hi there!" }],
85
+ },
86
+ ];
87
+ const config = {};
88
+ tracer.saveHistory(model, history, "session/conv_001", config);
89
+
90
+ // Start web server to view saved conversations
91
+ tracer.startWebServer("127.0.0.1", 25750);
92
+ // Open http://127.0.0.1:25750 in your browser
93
+ ```
94
+
95
+ ### Playground Usage
96
+
97
+ Interactive web interface for chatting with LLMs:
98
+
99
+ ```typescript
100
+ import { startPlaygroundServer } from "@prismshadow/mmsp/integration/playground";
101
+
102
+ // Start the playground server
103
+ startPlaygroundServer("127.0.0.1", 25751);
104
+ // Open http://127.0.0.1:25751 in your browser
105
+ // Open http://127.0.0.1:25751/tracer/ to browse traces
106
+ ```
107
+
108
+ ## Examples
109
+
110
+ Run the examples:
111
+
112
+ ```bash
113
+ # Build the project
114
+ npm run build
115
+
116
+ # Run tracer example
117
+ npm run tracer
118
+
119
+ # Run playground example
120
+ npm run playground
121
+ ```
@@ -0,0 +1,59 @@
1
+ import { BetaMessageParam, BetaRawMessageStreamEvent } from "@anthropic-ai/sdk/resources/beta/messages";
2
+ import { LLMClient } from "../baseClient";
3
+ import { UniConfig, UniEvent, UniMessage } from "../types";
4
+ /**
5
+ * Anthropic Messages-compatible client implementation.
6
+ */
7
+ export declare class AntMessagesClient extends LLMClient {
8
+ protected _model: string;
9
+ private _client;
10
+ /**
11
+ * Initialize Anthropic Messages-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 image URL to an Anthropic image source block.
21
+ */
22
+ private _convertImageUrlToSource;
23
+ /**
24
+ * Convert ThinkingLevel enum to the Messages API thinking config.
25
+ */
26
+ private _convertThinkingLevelToThinkingConfig;
27
+ /**
28
+ * Convert ToolChoice to the Messages API tool_choice format.
29
+ */
30
+ private _convertToolChoice;
31
+ /**
32
+ * Transform universal configuration to Anthropic Messages-compatible configuration.
33
+ */
34
+ transformUniConfigToModelConfig(config: UniConfig): any;
35
+ /**
36
+ * Transform universal message format to the Messages API BetaMessageParam format.
37
+ */
38
+ transformUniMessageToModelInput(messages: UniMessage[], _signal?: AbortSignal): BetaMessageParam[];
39
+ /**
40
+ * Transform one Messages API stream event into a universal event, identifying items by
41
+ * content block index.
42
+ */
43
+ transformModelOutputToUniEvent(modelOutput: BetaRawMessageStreamEvent): UniEvent;
44
+ /**
45
+ * Stream generate using an Anthropic Messages-compatible API with unified conversion methods.
46
+ */
47
+ _streamingResponseInternal(options: {
48
+ messages: UniMessage[];
49
+ config: UniConfig;
50
+ signal?: AbortSignal;
51
+ }): AsyncGenerator<UniEvent>;
52
+ /**
53
+ * List the model ids the configured endpoint serves.
54
+ *
55
+ * @returns The model ids, in the order the endpoint returned them.
56
+ */
57
+ listModels(): Promise<string[]>;
58
+ }
59
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/ant_messages/client.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,gBAAgB,EAChB,yBAAyB,EAC1B,MAAM,2CAA2C,CAAC;AAEnD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAOL,SAAS,EACT,QAAQ,EACR,UAAU,EAEX,MAAM,UAAU,CAAC;AASlB;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,SAAS;IAC9C,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,OAAO,CAAY;IAE3B;;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;IAoBD;;OAEG;IAEH,OAAO,CAAC,wBAAwB;IAgBhC;;OAEG;IACH,OAAO,CAAC,qCAAqC;IAgC7C;;OAEG;IAEH,OAAO,CAAC,kBAAkB;IAoB1B;;OAEG;IAEH,+BAA+B,CAAC,MAAM,EAAE,SAAS,GAAG,GAAG;IA2EvD;;OAEG;IACH,+BAA+B,CAC7B,QAAQ,EAAE,UAAU,EAAE,EACtB,OAAO,CAAC,EAAE,WAAW,GACpB,gBAAgB,EAAE;IAmErB;;;OAGG;IACH,8BAA8B,CAC5B,WAAW,EAAE,yBAAyB,GACrC,QAAQ;IAoIX;;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;IAsB5B;;;;OAIG;IACG,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;CAQtC"}
@@ -0,0 +1,419 @@
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.AntMessagesClient = void 0;
20
+ const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
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
+ const REDACTED_THINKING = "_REDACTED_THINKING";
26
+ /**
27
+ * Anthropic Messages-compatible client implementation.
28
+ */
29
+ class AntMessagesClient extends baseClient_1.LLMClient {
30
+ /**
31
+ * Initialize Anthropic Messages-compatible client with model, API key, and base URL.
32
+ */
33
+ constructor(options) {
34
+ super();
35
+ this._model = options.model;
36
+ const { apiKey: key, baseUrl: url } = (0, utils_1.resolveCredentials)(this.constructor.name, options, { key: "ANTHROPIC_API_KEY", baseUrl: "ANTHROPIC_BASE_URL" });
37
+ // send the credential through both header conventions: Anthropic and DeepSeek read
38
+ // x-api-key while gateways such as OpenRouter and Z.AI read Authorization: Bearer. With no
39
+ // credential the token has to be null, not undefined, or the SDK fills it from
40
+ // ANTHROPIC_AUTH_TOKEN.
41
+ this._client = new sdk_1.default({
42
+ apiKey: key,
43
+ authToken: key ?? null,
44
+ baseURL: url,
45
+ defaultHeaders: options.defaultHeaders,
46
+ });
47
+ }
48
+ /**
49
+ * Convert image URL to an Anthropic image source block.
50
+ */
51
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
52
+ _convertImageUrlToSource(url) {
53
+ if (url.startsWith("data:")) {
54
+ const match = url.match(/^data:([^;]+);base64,(.+)$/);
55
+ if (!match) {
56
+ throw new Error(`Invalid base64 image: ${url}`);
57
+ }
58
+ return {
59
+ type: "image",
60
+ source: { type: "base64", media_type: match[1], data: match[2] },
61
+ };
62
+ }
63
+ return { type: "image", source: { type: "url", url } };
64
+ }
65
+ /**
66
+ * Convert ThinkingLevel enum to the Messages API thinking config.
67
+ */
68
+ _convertThinkingLevelToThinkingConfig(thinkingLevel) {
69
+ // NONE is explicit rather than omitted because some servers (e.g. Z.AI) think by default
70
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
71
+ const mapping = {
72
+ [types_1.ThinkingLevel.NONE]: { thinking: { type: "disabled" } },
73
+ [types_1.ThinkingLevel.LOW]: {
74
+ thinking: { type: "adaptive" },
75
+ output_config: { effort: "low" },
76
+ },
77
+ [types_1.ThinkingLevel.MEDIUM]: {
78
+ thinking: { type: "adaptive" },
79
+ output_config: { effort: "medium" },
80
+ },
81
+ [types_1.ThinkingLevel.HIGH]: {
82
+ thinking: { type: "adaptive" },
83
+ output_config: { effort: "high" },
84
+ },
85
+ [types_1.ThinkingLevel.XHIGH]: {
86
+ thinking: { type: "adaptive" },
87
+ output_config: { effort: "xhigh" },
88
+ },
89
+ [types_1.ThinkingLevel.MAX]: {
90
+ thinking: { type: "adaptive" },
91
+ output_config: { effort: "max" },
92
+ },
93
+ };
94
+ return mapping[thinkingLevel];
95
+ }
96
+ /**
97
+ * Convert ToolChoice to the Messages API tool_choice format.
98
+ */
99
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
100
+ _convertToolChoice(toolChoice) {
101
+ if (Array.isArray(toolChoice)) {
102
+ if (toolChoice.length > 1) {
103
+ throw new errors_1.UnsupportedParameterError({
104
+ client: this.constructor.name,
105
+ parameter: "tool_choice",
106
+ message: "The Messages API does not support multiple tool choices.",
107
+ });
108
+ }
109
+ return { type: "tool", name: toolChoice[0] };
110
+ }
111
+ else if (toolChoice === "none") {
112
+ return { type: "none" };
113
+ }
114
+ else if (toolChoice === "auto") {
115
+ return { type: "auto" };
116
+ }
117
+ else if (toolChoice === "required") {
118
+ return { type: "any" };
119
+ }
120
+ }
121
+ /**
122
+ * Transform universal configuration to Anthropic Messages-compatible configuration.
123
+ */
124
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
125
+ transformUniConfigToModelConfig(config) {
126
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
127
+ const antConfig = { model: this._model, stream: true };
128
+ if (config.system_prompt !== undefined) {
129
+ antConfig.system = config.system_prompt;
130
+ }
131
+ if (config.max_tokens !== undefined) {
132
+ antConfig.max_tokens = config.max_tokens;
133
+ }
134
+ else {
135
+ // the Messages API requires max_tokens to be specified
136
+ antConfig.max_tokens = 64000;
137
+ }
138
+ if (config.temperature !== undefined) {
139
+ antConfig.temperature = config.temperature;
140
+ }
141
+ if (config.thinking_level !== undefined) {
142
+ Object.assign(antConfig, this._convertThinkingLevelToThinkingConfig(config.thinking_level));
143
+ }
144
+ if (config.thinking_summary !== undefined) {
145
+ // display lives on the thinking block, so a summary asked for on its own selects
146
+ // adaptive thinking. A disabled block is the one place it cannot ride along --
147
+ // "thinking.disabled.display: Extra inputs are not permitted" (400, verified live
148
+ // 2026-09-03) -- and thinking_level NONE disables thinking, leaving nothing to show.
149
+ antConfig.thinking = antConfig.thinking ?? { type: "adaptive" };
150
+ if (antConfig.thinking.type !== "disabled") {
151
+ antConfig.thinking.display = config.thinking_summary
152
+ ? "summarized"
153
+ : "omitted";
154
+ }
155
+ }
156
+ // Convert tools to the Messages API tool schema
157
+ if (config.tools !== undefined) {
158
+ antConfig.tools = config.tools.map((tool) => {
159
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
160
+ const antTool = {};
161
+ for (const [key, value] of Object.entries(tool)) {
162
+ antTool[key.replace("parameters", "input_schema")] = value;
163
+ }
164
+ return antTool;
165
+ });
166
+ }
167
+ // Convert tool_choice
168
+ if (config.tool_choice !== undefined) {
169
+ antConfig.tool_choice = this._convertToolChoice(config.tool_choice);
170
+ }
171
+ if (config.fast_mode) {
172
+ antConfig.speed = "fast";
173
+ antConfig.betas = ["fast-mode-2026-02-01"];
174
+ }
175
+ if (config.prompt_caching !== undefined &&
176
+ config.prompt_caching !== types_1.PromptCaching.ENABLE) {
177
+ throw new errors_1.UnsupportedParameterError({
178
+ client: this.constructor.name,
179
+ parameter: "prompt_caching",
180
+ message: "prompt_caching must be ENABLE for the Messages API.",
181
+ });
182
+ }
183
+ return antConfig;
184
+ }
185
+ /**
186
+ * Transform universal message format to the Messages API BetaMessageParam format.
187
+ */
188
+ transformUniMessageToModelInput(messages, _signal) {
189
+ const antMessages = [];
190
+ for (const msg of messages) {
191
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
192
+ const contentBlocks = [];
193
+ for (const item of msg.content_items) {
194
+ if (item.type === "text.done") {
195
+ contentBlocks.push({ type: "text", text: item.text });
196
+ }
197
+ else if (item.type === "image_url.done") {
198
+ contentBlocks.push(this._convertImageUrlToSource(item.image_url));
199
+ }
200
+ else if (item.type === "thinking.done") {
201
+ if (item.thinking === REDACTED_THINKING) {
202
+ contentBlocks.push({
203
+ type: "redacted_thinking",
204
+ data: item.fidelity?.signature,
205
+ });
206
+ }
207
+ else {
208
+ // third-party servers accept thinking without a signature, but the
209
+ // official API requires the one it emitted
210
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
211
+ const thinkingBlock = {
212
+ type: "thinking",
213
+ thinking: item.thinking,
214
+ };
215
+ if (item.fidelity?.signature != null) {
216
+ thinkingBlock.signature = item.fidelity.signature;
217
+ }
218
+ contentBlocks.push(thinkingBlock);
219
+ }
220
+ }
221
+ else if (item.type === "tool_call.done") {
222
+ contentBlocks.push({
223
+ type: "tool_use",
224
+ id: item.tool_call_id,
225
+ name: item.name,
226
+ input: item.arguments,
227
+ });
228
+ }
229
+ else if (item.type === "tool_result.done") {
230
+ if (!item.tool_call_id) {
231
+ throw new Error("tool_call_id is required for tool result.");
232
+ }
233
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
234
+ const toolResult = [{ type: "text", text: item.text }];
235
+ if (item.images) {
236
+ for (const imageUrl of item.images) {
237
+ toolResult.push(this._convertImageUrlToSource(imageUrl));
238
+ }
239
+ }
240
+ contentBlocks.push({
241
+ type: "tool_result",
242
+ content: toolResult,
243
+ tool_use_id: item.tool_call_id,
244
+ });
245
+ }
246
+ else {
247
+ throw new Error(`Unknown item: ${JSON.stringify(item)}`);
248
+ }
249
+ }
250
+ antMessages.push({ role: msg.role, content: contentBlocks });
251
+ }
252
+ return antMessages;
253
+ }
254
+ /**
255
+ * Transform one Messages API stream event into a universal event, identifying items by
256
+ * content block index.
257
+ */
258
+ transformModelOutputToUniEvent(modelOutput) {
259
+ let eventType = "delta";
260
+ const contentItems = [];
261
+ let usageMetadata = null;
262
+ let finishReason = null;
263
+ const antEventType = modelOutput.type;
264
+ if (antEventType === "content_block_start") {
265
+ const itemId = String(modelOutput.index);
266
+ const block = modelOutput.content_block;
267
+ if (block.type === "tool_use") {
268
+ contentItems.push({
269
+ type: "tool_call.delta",
270
+ name: block.name,
271
+ arguments: "",
272
+ tool_call_id: block.id,
273
+ fidelity: { item_id: itemId },
274
+ });
275
+ }
276
+ else if (block.type === "redacted_thinking") {
277
+ contentItems.push({
278
+ type: "thinking.delta",
279
+ thinking: REDACTED_THINKING,
280
+ fidelity: { item_id: itemId, signature: block.data },
281
+ });
282
+ }
283
+ }
284
+ else if (antEventType === "content_block_delta") {
285
+ const itemId = String(modelOutput.index);
286
+ const delta = modelOutput.delta;
287
+ if (delta.type === "thinking_delta") {
288
+ contentItems.push({
289
+ type: "thinking.delta",
290
+ thinking: delta.thinking,
291
+ fidelity: { item_id: itemId },
292
+ });
293
+ }
294
+ else if (delta.type === "text_delta") {
295
+ contentItems.push({
296
+ type: "text.delta",
297
+ text: delta.text,
298
+ fidelity: { item_id: itemId },
299
+ });
300
+ }
301
+ else if (delta.type === "input_json_delta") {
302
+ contentItems.push({
303
+ type: "tool_call.delta",
304
+ name: "",
305
+ arguments: delta.partial_json,
306
+ tool_call_id: "",
307
+ fidelity: { item_id: itemId },
308
+ });
309
+ }
310
+ else if (delta.type === "signature_delta") {
311
+ // the last delta of a thinking block: its signature
312
+ contentItems.push({
313
+ type: "thinking.delta",
314
+ thinking: "",
315
+ fidelity: { item_id: itemId, signature: delta.signature },
316
+ });
317
+ }
318
+ }
319
+ else if (antEventType === "message_start") {
320
+ eventType = "stop";
321
+ const usage = modelOutput.message.usage;
322
+ if (usage) {
323
+ const cacheCreationTokens = usage.cache_creation_input_tokens || 0;
324
+ usageMetadata = {
325
+ cached_tokens: usage.cache_read_input_tokens,
326
+ prompt_tokens: usage.input_tokens + cacheCreationTokens,
327
+ thoughts_tokens: null,
328
+ response_tokens: null,
329
+ };
330
+ }
331
+ }
332
+ else if (antEventType === "message_delta") {
333
+ eventType = "stop";
334
+ const stopReasonMapping = {
335
+ end_turn: "stop",
336
+ max_tokens: "length",
337
+ stop_sequence: "stop",
338
+ tool_use: "tool_call",
339
+ };
340
+ const stopReason = modelOutput.delta.stop_reason;
341
+ if (stopReason) {
342
+ finishReason = stopReasonMapping[stopReason] || "unknown";
343
+ }
344
+ const usage = modelOutput.usage;
345
+ if (usage) {
346
+ // gateways report zero usage in message_start and the full counts here, so the
347
+ // delta also carries the input-side fields (null on servers that omit them)
348
+ const promptTokens = usage.input_tokens != null
349
+ ? usage.input_tokens + (usage.cache_creation_input_tokens || 0)
350
+ : null;
351
+ const thinkingTokens =
352
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
353
+ usage.output_tokens_details?.thinking_tokens ?? null;
354
+ usageMetadata = (0, utils_1.fixOpenrouterUsageMetadata)({
355
+ cached_tokens: usage.cache_read_input_tokens ?? null,
356
+ prompt_tokens: promptTokens,
357
+ thoughts_tokens: thinkingTokens,
358
+ response_tokens: usage.output_tokens - (thinkingTokens || 0),
359
+ }, this._client.baseURL);
360
+ }
361
+ }
362
+ else if ([
363
+ "content_block_stop",
364
+ "message_stop",
365
+ "text",
366
+ "thinking",
367
+ "signature",
368
+ "input_json",
369
+ "ping",
370
+ ].includes(antEventType)) {
371
+ // a block needs no stop: it is done when the next one begins or the stream ends. The SDK
372
+ // drops the "ping" heartbeat at the SSE layer; it reaches here only from gateways that
373
+ // relabel it onto another event
374
+ }
375
+ else if ((0, utils_1.isDebugEnabled)()) {
376
+ throw new Error(`Unknown output: ${JSON.stringify(modelOutput)}`);
377
+ }
378
+ else {
379
+ // a gateway injects its own events (heartbeats, cost tickers) into the stream, and
380
+ // killing a long generation over one costs more than dropping it
381
+ }
382
+ return {
383
+ role: "assistant",
384
+ event_type: eventType,
385
+ content_items: contentItems,
386
+ usage_metadata: usageMetadata,
387
+ finish_reason: finishReason,
388
+ };
389
+ }
390
+ /**
391
+ * Stream generate using an Anthropic Messages-compatible API with unified conversion methods.
392
+ */
393
+ async *_streamingResponseInternal(options) {
394
+ const antConfig = this.transformUniConfigToModelConfig(options.config);
395
+ const antMessages = this.transformUniMessageToModelInput(options.messages, options.signal);
396
+ const stream = (await this._client.beta.messages.create({
397
+ ...antConfig,
398
+ messages: antMessages,
399
+ }, {
400
+ signal: options.signal,
401
+ }));
402
+ for await (const event of stream) {
403
+ yield this.transformModelOutputToUniEvent(event);
404
+ }
405
+ }
406
+ /**
407
+ * List the model ids the configured endpoint serves.
408
+ *
409
+ * @returns The model ids, in the order the endpoint returned them.
410
+ */
411
+ async listModels() {
412
+ const models = [];
413
+ for await (const model of this._client.models.list()) {
414
+ models.push(model.id);
415
+ }
416
+ return models;
417
+ }
418
+ }
419
+ exports.AntMessagesClient = AntMessagesClient;
@@ -0,0 +1,2 @@
1
+ export { AntMessagesClient } from "./client";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ant_messages/index.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,iBAAiB,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.AntMessagesClient = void 0;
17
+ var client_1 = require("./client");
18
+ Object.defineProperty(exports, "AntMessagesClient", { enumerable: true, get: function () { return client_1.AntMessagesClient; } });