@deepstrike/sdk 0.2.30 → 0.2.32

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 (48) hide show
  1. package/dist/harness/harness.d.ts +3 -2
  2. package/dist/harness/harness.js +15 -35
  3. package/dist/harness/judge.d.ts +42 -0
  4. package/dist/harness/judge.js +58 -0
  5. package/dist/index.d.ts +8 -0
  6. package/dist/index.js +4 -0
  7. package/dist/kernel.d.ts +7 -1
  8. package/dist/providers/anthropic-compatible.d.ts +23 -0
  9. package/dist/providers/anthropic-compatible.js +29 -0
  10. package/dist/providers/catalog.js +5 -53
  11. package/dist/providers/deepseek.d.ts +28 -8
  12. package/dist/providers/deepseek.js +38 -157
  13. package/dist/providers/factories.js +10 -22
  14. package/dist/providers/gemini.d.ts +12 -0
  15. package/dist/providers/gemini.js +38 -3
  16. package/dist/providers/glm.d.ts +7 -4
  17. package/dist/providers/glm.js +27 -24
  18. package/dist/providers/kimi.d.ts +5 -4
  19. package/dist/providers/kimi.js +8 -22
  20. package/dist/providers/minimax.d.ts +26 -12
  21. package/dist/providers/minimax.js +33 -159
  22. package/dist/providers/openai-responses.d.ts +6 -0
  23. package/dist/providers/openai-responses.js +22 -2
  24. package/dist/providers/openai.d.ts +52 -0
  25. package/dist/providers/openai.js +145 -66
  26. package/dist/providers/profiles.d.ts +60 -0
  27. package/dist/providers/profiles.js +22 -0
  28. package/dist/providers/qwen.d.ts +20 -19
  29. package/dist/providers/qwen.js +49 -176
  30. package/dist/providers/registry.d.ts +18 -0
  31. package/dist/providers/registry.js +35 -0
  32. package/dist/providers/vendor-profiles.d.ts +54 -0
  33. package/dist/providers/vendor-profiles.js +66 -0
  34. package/dist/runtime/event-stream.d.ts +44 -0
  35. package/dist/runtime/event-stream.js +39 -0
  36. package/dist/runtime/reactive-session.d.ts +125 -0
  37. package/dist/runtime/reactive-session.js +127 -0
  38. package/dist/runtime/run-group.d.ts +74 -0
  39. package/dist/runtime/run-group.js +72 -0
  40. package/dist/runtime/runner.d.ts +9 -0
  41. package/dist/runtime/runner.js +56 -7
  42. package/dist/runtime/session-log.d.ts +8 -0
  43. package/dist/runtime/turn-policy.d.ts +33 -0
  44. package/dist/runtime/turn-policy.js +58 -0
  45. package/dist/signals/gateway.d.ts +7 -2
  46. package/dist/signals/gateway.js +13 -3
  47. package/dist/signals/types.d.ts +10 -1
  48. package/package.json +2 -2
@@ -15,6 +15,20 @@ export interface OpenAIProviderOptions {
15
15
  /** Custom OpenAI-compatible endpoint (MiMo, DeepSeek, Kimi, …). Defaults to the OpenAI API. */
16
16
  baseURL?: string;
17
17
  }
18
+ /** Reasoning captured from a single model turn, handed to the replay-remember hooks so an
19
+ * OpenAI-compatible subclass can persist whatever replay envelope its wire requires. */
20
+ export interface OpenAIChatTurnReasoning {
21
+ reasoningContent: string;
22
+ reasoningDetails?: unknown;
23
+ nativeToolCalls: unknown[];
24
+ }
25
+ /** Rebuild OpenAI-native `tool_calls` blocks from the streamed buffers — needed by reasoning
26
+ * vendors (DeepSeek/MiniMax) that persist the native blocks in their replay envelope. */
27
+ export declare function nativeToolCallsFromBuffers(toolCallBufs: Record<number, {
28
+ id: string;
29
+ name: string;
30
+ argsBuf: string;
31
+ }>): Array<Record<string, unknown>>;
18
32
  export declare class OpenAIChatProvider implements LLMProvider {
19
33
  protected client: OpenAI;
20
34
  protected circuit: CircuitBreaker;
@@ -31,6 +45,44 @@ export declare class OpenAIChatProvider implements LLMProvider {
31
45
  protected requireNonEmptyReasoningReplayForToolTurns(_extensions?: Record<string, unknown>): boolean;
32
46
  protected degradeMissingReasoningReplay(extensions?: Record<string, unknown>): boolean;
33
47
  protected buildChatMessages(context: RenderedContext, extensions?: Record<string, unknown>): OpenAI.Chat.Completions.ChatCompletionMessageParam[];
48
+ /** Pre-process caller extensions before they reach buildChatMessages + the wire request
49
+ * (e.g. set `__deepstrikeThinkingEnabled`). Default: pass through unchanged. */
50
+ protected prepareExtensions(extensions?: Record<string, unknown>): Record<string, unknown> | undefined;
51
+ /** Extra top-level request-body fields merged into the chat.completions call (vendor thinking
52
+ * knobs like `reasoning_effort`, `extra_body`, `reasoning_split`). Default: none. */
53
+ protected requestBodyExtras(_extensions?: Record<string, unknown>): Record<string, unknown>;
54
+ /** Vendor server tools (e.g. web search) injected into the `tools[]` array alongside the function
55
+ * tools, driven by caller `extensions`. These run server-side — the model invokes them and the
56
+ * results come back inline, with no client tool-loop round-trip. Default: none. Vendors that ship
57
+ * built-in tools (GLM web_search, …) override this and strip the consumed key in `prepareExtensions`
58
+ * so it does not also leak into the request body. */
59
+ protected serverTools(_extensions?: Record<string, unknown>): unknown[];
60
+ /** Merge function tools + vendor server tools into the wire `tools[]` (undefined when empty). Server
61
+ * tools (e.g. web_search) are non-standard wire entries, so the array is cast to the SDK tool type. */
62
+ protected assembleTools(tools: ToolSchema[], extensions?: Record<string, unknown>): OpenAI.Chat.Completions.ChatCompletionTool[] | undefined;
63
+ /** Request-body params controlling prompt caching. Default sends OpenAI's `prompt_cache_key`;
64
+ * vendors whose endpoints reject unknown params (e.g. DeepSeek 400s) override to `{}`. */
65
+ protected cacheKeyParams(context: RenderedContext, tools: ToolSchema[]): Record<string, unknown>;
66
+ /** Whether streamed `content` may carry inline `<thinking>…</thinking>` tags to split out.
67
+ * Default true (OpenAI). Reasoning vendors emit reasoning out-of-band, so they return false. */
68
+ protected usesInlineThinkingTags(): boolean;
69
+ /** Whether to surface streamed `reasoning_content` as thinking_delta events. Default true;
70
+ * vendors gate this behind an `exposeReasoning` extension. */
71
+ protected exposeReasoningDelta(_extensions?: Record<string, unknown>): boolean;
72
+ /** Persist replay after a non-streaming turn. Default: nothing (plain OpenAI has no reasoning
73
+ * to replay). Reasoning vendors override to store their envelope. */
74
+ protected rememberCompleteReplay(_content: string, _toolCalls: Array<{
75
+ id: string;
76
+ name: string;
77
+ arguments: string;
78
+ }>, _reasoning: OpenAIChatTurnReasoning): void;
79
+ /** Persist replay after a streamed turn. Default: store `{ reasoning_content }` when there is a
80
+ * tool-call turn or captured reasoning (the prior base behavior). Vendors override. */
81
+ protected rememberStreamReplay(content: string, toolCalls: Array<{
82
+ id: string;
83
+ name: string;
84
+ arguments: string;
85
+ }>, reasoning: OpenAIChatTurnReasoning): void;
34
86
  /**
35
87
  * Pre-flight query: would this history validate against this provider with the
36
88
  * given extensions, without sending the request? Lets an embedder route around
@@ -25,6 +25,15 @@ const OPENAI_POLICIES = {
25
25
  "o3-mini": { maxTurns: 25 },
26
26
  "o4-mini": { maxTurns: 25 },
27
27
  };
28
+ /** Rebuild OpenAI-native `tool_calls` blocks from the streamed buffers — needed by reasoning
29
+ * vendors (DeepSeek/MiniMax) that persist the native blocks in their replay envelope. */
30
+ export function nativeToolCallsFromBuffers(toolCallBufs) {
31
+ return Object.values(toolCallBufs).map(tb => ({
32
+ id: tb.id,
33
+ type: "function",
34
+ function: { name: tb.name, arguments: tb.argsBuf || "{}" },
35
+ }));
36
+ }
28
37
  export class OpenAIChatProvider {
29
38
  client;
30
39
  circuit;
@@ -75,6 +84,61 @@ export class OpenAIChatProvider {
75
84
  degradeMissingReasoning: this.degradeMissingReasoningReplay(extensions),
76
85
  });
77
86
  }
87
+ // ── Template-Method hooks ───────────────────────────────────────────────────
88
+ // Defaults reproduce the plain OpenAI-chat behavior; reasoning vendors
89
+ // (DeepSeek/MiniMax) override these instead of duplicating complete()/stream().
90
+ /** Pre-process caller extensions before they reach buildChatMessages + the wire request
91
+ * (e.g. set `__deepstrikeThinkingEnabled`). Default: pass through unchanged. */
92
+ prepareExtensions(extensions) {
93
+ return extensions;
94
+ }
95
+ /** Extra top-level request-body fields merged into the chat.completions call (vendor thinking
96
+ * knobs like `reasoning_effort`, `extra_body`, `reasoning_split`). Default: none. */
97
+ requestBodyExtras(_extensions) {
98
+ return {};
99
+ }
100
+ /** Vendor server tools (e.g. web search) injected into the `tools[]` array alongside the function
101
+ * tools, driven by caller `extensions`. These run server-side — the model invokes them and the
102
+ * results come back inline, with no client tool-loop round-trip. Default: none. Vendors that ship
103
+ * built-in tools (GLM web_search, …) override this and strip the consumed key in `prepareExtensions`
104
+ * so it does not also leak into the request body. */
105
+ serverTools(_extensions) {
106
+ return [];
107
+ }
108
+ /** Merge function tools + vendor server tools into the wire `tools[]` (undefined when empty). Server
109
+ * tools (e.g. web_search) are non-standard wire entries, so the array is cast to the SDK tool type. */
110
+ assembleTools(tools, extensions) {
111
+ const fnTools = tools.length ? this.chat.buildTools(tools) : [];
112
+ const all = [...fnTools, ...this.serverTools(extensions)];
113
+ return all.length ? all : undefined;
114
+ }
115
+ /** Request-body params controlling prompt caching. Default sends OpenAI's `prompt_cache_key`;
116
+ * vendors whose endpoints reject unknown params (e.g. DeepSeek 400s) override to `{}`. */
117
+ cacheKeyParams(context, tools) {
118
+ return { prompt_cache_key: this.promptCacheKey(context, tools) };
119
+ }
120
+ /** Whether streamed `content` may carry inline `<thinking>…</thinking>` tags to split out.
121
+ * Default true (OpenAI). Reasoning vendors emit reasoning out-of-band, so they return false. */
122
+ usesInlineThinkingTags() {
123
+ return true;
124
+ }
125
+ /** Whether to surface streamed `reasoning_content` as thinking_delta events. Default true;
126
+ * vendors gate this behind an `exposeReasoning` extension. */
127
+ exposeReasoningDelta(_extensions) {
128
+ return true;
129
+ }
130
+ /** Persist replay after a non-streaming turn. Default: nothing (plain OpenAI has no reasoning
131
+ * to replay). Reasoning vendors override to store their envelope. */
132
+ rememberCompleteReplay(_content, _toolCalls, _reasoning) {
133
+ /* no-op */
134
+ }
135
+ /** Persist replay after a streamed turn. Default: store `{ reasoning_content }` when there is a
136
+ * tool-call turn or captured reasoning (the prior base behavior). Vendors override. */
137
+ rememberStreamReplay(content, toolCalls, reasoning) {
138
+ if (toolCalls.length || reasoning.reasoningContent) {
139
+ this.chat.rememberReplayFields({ content, toolCalls }, { reasoning_content: reasoning.reasoningContent });
140
+ }
141
+ }
78
142
  /**
79
143
  * Pre-flight query: would this history validate against this provider with the
80
144
  * given extensions, without sending the request? Lets an embedder route around
@@ -100,23 +164,32 @@ export class OpenAIChatProvider {
100
164
  }
101
165
  }
102
166
  async complete(context, tools, extensions) {
167
+ const prepared = this.prepareExtensions(extensions);
103
168
  if (this.circuit.isOpen())
104
169
  throw new Error("Circuit breaker open");
105
- const msgs = this.buildChatMessages(context, extensions);
170
+ const msgs = this.buildChatMessages(context, prepared);
106
171
  let lastErr;
107
172
  for (let i = 0; i < this.maxRetries; i++) {
108
173
  try {
109
174
  const resp = await this.client.chat.completions.create({
110
- prompt_cache_key: this.promptCacheKey(context, tools),
111
- ...this.requestExtensions(extensions),
175
+ ...this.cacheKeyParams(context, tools),
176
+ ...this.requestExtensions(prepared),
177
+ ...this.requestBodyExtras(extensions),
112
178
  model: this.model,
113
179
  messages: msgs,
114
- ...(tools.length ? { tools: this.chat.buildTools(tools) } : {}),
180
+ ...((t => t ? { tools: t } : {})(this.assembleTools(tools, extensions))),
115
181
  });
116
182
  this.circuit.recordSuccess();
117
183
  const choice = resp.choices[0].message;
118
- const toolCalls = this.chat.normalizeToolCalls(choice.tool_calls ?? []);
119
- return { role: "assistant", content: choice.content ?? "", tokenCount: resp.usage?.completion_tokens ?? resp.usage?.total_tokens, toolCalls };
184
+ const nativeToolCalls = choice.tool_calls ?? [];
185
+ const toolCalls = this.chat.normalizeToolCalls(nativeToolCalls);
186
+ const content = choice.content ?? "";
187
+ this.rememberCompleteReplay(content, toolCalls, {
188
+ reasoningContent: typeof choice.reasoning_content === "string" ? choice.reasoning_content : "",
189
+ reasoningDetails: choice.reasoning_details,
190
+ nativeToolCalls: nativeToolCalls,
191
+ });
192
+ return { role: "assistant", content, tokenCount: resp.usage?.completion_tokens ?? resp.usage?.total_tokens, toolCalls };
120
193
  }
121
194
  catch (err) {
122
195
  lastErr = err;
@@ -128,22 +201,51 @@ export class OpenAIChatProvider {
128
201
  throw lastErr;
129
202
  }
130
203
  async *stream(context, tools, extensions, _state, signal) {
131
- const msgs = this.buildChatMessages(context, extensions);
204
+ const prepared = this.prepareExtensions(extensions);
205
+ const msgs = this.buildChatMessages(context, prepared);
132
206
  const toolCallBufs = {};
133
207
  const emittedToolCallIndexes = new Set();
208
+ const useTags = this.usesInlineThinkingTags();
209
+ const exposeReasoning = this.exposeReasoningDelta(extensions);
134
210
  const extractor = new ThinkingTagStreamExtractor();
135
211
  let accumulatedReasoning = "";
212
+ let accumulatedReasoningDetails;
136
213
  let accumulatedContent = "";
137
214
  const stream = await this.client.chat.completions.create({
138
- prompt_cache_key: this.promptCacheKey(context, tools),
139
- ...this.requestExtensions(extensions),
215
+ ...this.cacheKeyParams(context, tools),
216
+ ...this.requestExtensions(prepared),
217
+ ...this.requestBodyExtras(extensions),
140
218
  model: this.model,
141
219
  messages: msgs,
142
- ...(tools.length ? { tools: this.chat.buildTools(tools) } : {}),
220
+ ...((t => t ? { tools: t } : {})(this.assembleTools(tools, extensions))),
143
221
  stream: true,
144
222
  stream_options: { include_usage: true },
145
223
  // #2-B-ii: forward the abort signal so a preempt cancels the in-flight HTTP request.
146
224
  }, signal ? { signal } : undefined);
225
+ const rememberStream = () => {
226
+ const toolCalls = Object.values(toolCallBufs).map(tb => ({ id: tb.id, name: tb.name, arguments: tb.argsBuf || "{}" }));
227
+ this.rememberStreamReplay(accumulatedContent, toolCalls, {
228
+ reasoningContent: accumulatedReasoning,
229
+ reasoningDetails: accumulatedReasoningDetails,
230
+ nativeToolCalls: nativeToolCallsFromBuffers(toolCallBufs),
231
+ });
232
+ };
233
+ const emitPendingToolCalls = function* () {
234
+ for (const [index, tb] of Object.entries(toolCallBufs)) {
235
+ const idx = Number(index);
236
+ if (emittedToolCallIndexes.has(idx))
237
+ continue;
238
+ let args = {};
239
+ try {
240
+ args = JSON.parse(tb.argsBuf || "{}");
241
+ }
242
+ catch {
243
+ args = {};
244
+ }
245
+ emittedToolCallIndexes.add(idx);
246
+ yield { type: "tool_call", id: tb.id, name: tb.name, arguments: args };
247
+ }
248
+ };
147
249
  let totalTokens = 0;
148
250
  let inputTokens = 0;
149
251
  let outputTokens = 0;
@@ -163,20 +265,29 @@ export class OpenAIChatProvider {
163
265
  if (!delta)
164
266
  continue;
165
267
  if (delta.reasoning_content) {
166
- accumulatedReasoning += delta.reasoning_content;
167
- yield { type: "thinking_delta", delta: delta.reasoning_content };
268
+ accumulatedReasoning += String(delta.reasoning_content);
269
+ if (exposeReasoning)
270
+ yield { type: "thinking_delta", delta: String(delta.reasoning_content) };
168
271
  }
272
+ if (delta.reasoning_details !== undefined && delta.reasoning_details !== null)
273
+ accumulatedReasoningDetails = delta.reasoning_details;
169
274
  if (delta.content) {
170
- for (const part of extractor.feed(delta.content)) {
171
- if (part.type === "thinking") {
172
- accumulatedReasoning += part.content;
173
- yield { type: "thinking_delta", delta: part.content };
174
- }
175
- else {
176
- accumulatedContent += part.content;
177
- yield { type: "text_delta", delta: part.content };
275
+ if (useTags) {
276
+ for (const part of extractor.feed(String(delta.content))) {
277
+ if (part.type === "thinking") {
278
+ accumulatedReasoning += part.content;
279
+ yield { type: "thinking_delta", delta: part.content };
280
+ }
281
+ else {
282
+ accumulatedContent += part.content;
283
+ yield { type: "text_delta", delta: part.content };
284
+ }
178
285
  }
179
286
  }
287
+ else {
288
+ accumulatedContent += String(delta.content);
289
+ yield { type: "text_delta", delta: delta.content };
290
+ }
180
291
  }
181
292
  for (const tc of delta.tool_calls ?? []) {
182
293
  const idx = tc.index;
@@ -187,56 +298,24 @@ export class OpenAIChatProvider {
187
298
  toolCallBufs[idx].argsBuf += tc.function?.arguments ?? "";
188
299
  }
189
300
  if (choice.finish_reason === "tool_calls") {
190
- const toolCalls = Object.values(toolCallBufs).map(tb => ({
191
- id: tb.id, name: tb.name, arguments: tb.argsBuf || "{}",
192
- }));
193
- this.chat.rememberReplayFields({ content: accumulatedContent, toolCalls }, { reasoning_content: accumulatedReasoning });
194
- for (const [index, tb] of Object.entries(toolCallBufs)) {
195
- const idx = Number(index);
196
- if (emittedToolCallIndexes.has(idx))
197
- continue;
198
- let args = {};
199
- try {
200
- args = JSON.parse(tb.argsBuf || "{}");
201
- }
202
- catch {
203
- args = {};
204
- }
205
- emittedToolCallIndexes.add(idx);
206
- yield { type: "tool_call", id: tb.id, name: tb.name, arguments: args };
207
- }
301
+ rememberStream();
302
+ yield* emitPendingToolCalls();
208
303
  }
209
304
  }
210
- for (const part of extractor.flush()) {
211
- if (part.type === "thinking") {
212
- accumulatedReasoning += part.content;
213
- yield { type: "thinking_delta", delta: part.content };
214
- }
215
- else {
216
- accumulatedContent += part.content;
217
- yield { type: "text_delta", delta: part.content };
218
- }
219
- }
220
- const toolCalls = Object.values(toolCallBufs).map(tb => ({
221
- id: tb.id, name: tb.name, arguments: tb.argsBuf || "{}",
222
- }));
223
- if (toolCalls.length || accumulatedReasoning) {
224
- this.chat.rememberReplayFields({ content: accumulatedContent, toolCalls }, { reasoning_content: accumulatedReasoning });
225
- }
226
- for (const [index, tb] of Object.entries(toolCallBufs)) {
227
- const idx = Number(index);
228
- if (emittedToolCallIndexes.has(idx))
229
- continue;
230
- let args = {};
231
- try {
232
- args = JSON.parse(tb.argsBuf || "{}");
233
- }
234
- catch {
235
- args = {};
305
+ if (useTags) {
306
+ for (const part of extractor.flush()) {
307
+ if (part.type === "thinking") {
308
+ accumulatedReasoning += part.content;
309
+ yield { type: "thinking_delta", delta: part.content };
310
+ }
311
+ else {
312
+ accumulatedContent += part.content;
313
+ yield { type: "text_delta", delta: part.content };
314
+ }
236
315
  }
237
- emittedToolCallIndexes.add(idx);
238
- yield { type: "tool_call", id: tb.id, name: tb.name, arguments: args };
239
316
  }
317
+ rememberStream();
318
+ yield* emitPendingToolCalls();
240
319
  if (totalTokens > 0)
241
320
  yield { type: "usage", totalTokens, inputTokens, outputTokens, ...(cacheReadTokens > 0 ? { cacheReadInputTokens: cacheReadTokens } : {}) };
242
321
  }
@@ -729,6 +729,46 @@ export declare const modelProfiles: {
729
729
  readonly preserveAcrossToolTurns: false;
730
730
  };
731
731
  };
732
+ readonly "minimax/MiniMax-M3": {
733
+ readonly id: "minimax/MiniMax-M3";
734
+ readonly providerId: "minimax";
735
+ readonly defaultEndpointId: "minimax.anthropic";
736
+ readonly contextWindow: 204800;
737
+ readonly modalities: {
738
+ readonly input: ["text", "image"];
739
+ readonly output: ["text"];
740
+ };
741
+ readonly tools: {
742
+ readonly supported: true;
743
+ };
744
+ readonly reasoning: {
745
+ readonly supported: true;
746
+ readonly preserveAcrossToolTurns: true;
747
+ };
748
+ readonly policy: {
749
+ readonly maxTurns: 35;
750
+ };
751
+ };
752
+ readonly "minimax/MiniMax-M3-highspeed": {
753
+ readonly id: "minimax/MiniMax-M3-highspeed";
754
+ readonly providerId: "minimax";
755
+ readonly defaultEndpointId: "minimax.anthropic";
756
+ readonly contextWindow: 204800;
757
+ readonly modalities: {
758
+ readonly input: ["text", "image"];
759
+ readonly output: ["text"];
760
+ };
761
+ readonly tools: {
762
+ readonly supported: true;
763
+ };
764
+ readonly reasoning: {
765
+ readonly supported: true;
766
+ readonly preserveAcrossToolTurns: true;
767
+ };
768
+ readonly policy: {
769
+ readonly maxTurns: 35;
770
+ };
771
+ };
732
772
  readonly "minimax/MiniMax-M2.7": {
733
773
  readonly id: "minimax/MiniMax-M2.7";
734
774
  readonly providerId: "minimax";
@@ -1650,6 +1690,26 @@ export declare const modelProfiles: {
1650
1690
  readonly preserveAcrossToolTurns: false;
1651
1691
  };
1652
1692
  };
1693
+ readonly "glm/glm-5.2": {
1694
+ readonly id: "glm/glm-5.2";
1695
+ readonly providerId: "glm";
1696
+ readonly defaultEndpointId: "glm.anthropic";
1697
+ readonly contextWindow: 200000;
1698
+ readonly modalities: {
1699
+ readonly input: ["text"];
1700
+ readonly output: ["text"];
1701
+ };
1702
+ readonly tools: {
1703
+ readonly supported: true;
1704
+ };
1705
+ readonly reasoning: {
1706
+ readonly supported: true;
1707
+ readonly preserveAcrossToolTurns: true;
1708
+ };
1709
+ readonly policy: {
1710
+ readonly maxTurns: 50;
1711
+ };
1712
+ };
1653
1713
  readonly "glm/glm-5.1": {
1654
1714
  readonly id: "glm/glm-5.1";
1655
1715
  readonly providerId: "glm";
@@ -341,6 +341,21 @@ export const modelProfiles = {
341
341
  tools: { supported: false }, reasoning: { supported: false, preserveAcrossToolTurns: false },
342
342
  },
343
343
  // ── MiniMax ────────────────────────────────────────────────────────────────
344
+ "minimax/MiniMax-M3": {
345
+ id: "minimax/MiniMax-M3", providerId: "minimax", defaultEndpointId: "minimax.anthropic",
346
+ contextWindow: 204_800,
347
+ // Natively multimodal — image input verified live via the Anthropic image-block path.
348
+ modalities: { input: ["text", "image"], output: ["text"] },
349
+ tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: true },
350
+ policy: { maxTurns: 35 },
351
+ },
352
+ "minimax/MiniMax-M3-highspeed": {
353
+ id: "minimax/MiniMax-M3-highspeed", providerId: "minimax", defaultEndpointId: "minimax.anthropic",
354
+ contextWindow: 204_800,
355
+ modalities: { input: ["text", "image"], output: ["text"] },
356
+ tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: true },
357
+ policy: { maxTurns: 35 },
358
+ },
344
359
  "minimax/MiniMax-M2.7": {
345
360
  id: "minimax/MiniMax-M2.7", providerId: "minimax", defaultEndpointId: "minimax.anthropic",
346
361
  contextWindow: 204_800,
@@ -668,6 +683,13 @@ export const modelProfiles = {
668
683
  tools: { supported: false }, reasoning: { supported: false, preserveAcrossToolTurns: false },
669
684
  },
670
685
  // ── GLM ────────────────────────────────────────────────────────────────────
686
+ "glm/glm-5.2": {
687
+ id: "glm/glm-5.2", providerId: "glm", defaultEndpointId: "glm.anthropic",
688
+ contextWindow: 200_000,
689
+ modalities: { input: ["text"], output: ["text"] },
690
+ tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: true },
691
+ policy: { maxTurns: 50 },
692
+ },
671
693
  "glm/glm-5.1": {
672
694
  id: "glm/glm-5.1", providerId: "glm", defaultEndpointId: "glm.anthropic",
673
695
  contextWindow: 200_000,
@@ -1,37 +1,38 @@
1
- import OpenAI from "openai";
2
- import type { LLMProvider, Message, ProviderDescriptor, RenderedContext, StreamEvent, ToolSchema, RuntimePolicy, ProviderReplay } from "../types.js";
3
- import { AnthropicProvider } from "./anthropic.js";
4
- import { CircuitBreaker } from "./base.js";
5
- import { OpenAIChatAdapter } from "./openai-chat.js";
1
+ import type { Message, ProviderDescriptor, ProviderReplay, RuntimePolicy } from "../types.js";
2
+ import { OpenAIChatProvider } from "./openai.js";
3
+ import { AnthropicCompatibleProvider } from "./anthropic-compatible.js";
6
4
  /**
7
5
  * Qwen over its Anthropic-compatible endpoint.
6
+ * @deprecated Prefer `qwen({ protocol: "anthropic" })`. Behavior is now fully
7
+ * data-driven via `anthropicVendorProfiles.qwen`; this thin shim is kept for
8
+ * backward compatibility and `instanceof` checks.
8
9
  */
9
- export declare class QwenAnthropicProvider extends AnthropicProvider {
10
+ export declare class QwenAnthropicProvider extends AnthropicCompatibleProvider {
10
11
  constructor(apiKey: string, model?: string, retry?: {
11
12
  maxRetries: number;
12
13
  baseDelay: number;
13
14
  }, baseURL?: string);
14
- protected providerName(): string;
15
- runtimePolicy(): RuntimePolicy;
16
15
  }
17
- export declare class QwenProvider implements LLMProvider {
18
- protected readonly model: string;
19
- protected client: OpenAI;
20
- protected circuit: CircuitBreaker;
21
- protected maxRetries: number;
22
- protected baseDelay: number;
23
- protected readonly chat: OpenAIChatAdapter;
16
+ /**
17
+ * Qwen / DashScope over its OpenAI-compatible (DashScope) endpoint. Reasoning is carried
18
+ * out-of-band as `reasoning_content`; thinking is opted into via `enable_thinking` /
19
+ * `thinking_budget` (sent under `extra_body`). The streaming / tool-call machinery and the
20
+ * default `{ reasoning_content }` replay are inherited from OpenAIChatProvider; only request
21
+ * shaping and the (string-coerced) replay peek differ, supplied via the Template-Method hooks.
22
+ */
23
+ export declare class QwenProvider extends OpenAIChatProvider {
24
24
  constructor(apiKey: string, model?: string, retry?: {
25
25
  maxRetries: number;
26
26
  baseDelay: number;
27
27
  }, baseURL?: string);
28
28
  runtimePolicy(): RuntimePolicy;
29
29
  descriptor(): ProviderDescriptor;
30
- private buildChatMessages;
30
+ protected cacheKeyParams(): Record<string, unknown>;
31
+ protected usesInlineThinkingTags(): boolean;
32
+ protected requestBodyExtras(extensions?: Record<string, unknown>): Record<string, unknown>;
33
+ protected requestExtensions(extensions?: Record<string, unknown>): Record<string, unknown>;
34
+ private searchExtraBody;
31
35
  peekProviderReplay(message: Pick<Message, "content" | "toolCalls">): ProviderReplay | undefined;
32
36
  seedProviderReplay(message: Pick<Message, "content" | "toolCalls">, replay: ProviderReplay): void;
33
- complete(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): Promise<Message>;
34
- stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): AsyncIterable<StreamEvent>;
35
37
  private thinkingExtraBody;
36
- private requestExtensions;
37
38
  }