@deepstrike/sdk 0.1.14 → 0.1.16

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/dist/index.d.ts CHANGED
@@ -25,6 +25,7 @@ export { OpenAIChatAdapter } from "./providers/openai-chat.js";
25
25
  export { OpenAIResponsesAdapter, OpenAIResponsesProvider } from "./providers/openai-responses.js";
26
26
  export type { OpenAIResponsesRunState } from "./providers/openai-responses.js";
27
27
  export { endpointProfiles, modelProfiles, getModelProfile } from "./providers/profiles.js";
28
+ export type { ModelProfileId, ProviderId } from "./providers/profiles.js";
28
29
  export { createProvider } from "./providers/catalog.js";
29
30
  export type { CreateProviderOptions, EndpointProfileId } from "./providers/catalog.js";
30
31
  export { tool, streamingTool, executeTools, readFile, validateToolArguments } from "./tools/index.js";
@@ -43,7 +44,7 @@ export { Governance } from "./governance.js";
43
44
  export type { GovernanceVerdict } from "./governance.js";
44
45
  export { SinglePassHarness, EvalLoopHarness, HarnessLoop } from "./harness/harness.js";
45
46
  export type { HarnessRequest, HarnessOutcome, HarnessLoopOptions, QualityGate } from "./harness/harness.js";
46
- export type { Message, ToolCall, ToolResult, ToolSchema, ContentPart, TextPart, ImagePart, AudioPart, StreamEvent, TextDelta, ThinkingDelta, ToolCallEvent, ToolChunk, ToolDeltaEvent, ToolSuspendEvent, ToolResultEvent, DoneEvent, ErrorEvent, PermissionRequestEvent, LLMProvider, RetryConfig, TokenUsage, ProviderToolSpec, ProviderRunState, RenderedContext, } from "./types.js";
47
+ export type { Message, ToolCall, ToolResult, ToolSchema, ContentPart, TextPart, ImagePart, AudioPart, StreamEvent, TextDelta, ThinkingDelta, ToolCallEvent, ToolChunk, ToolDeltaEvent, ToolSuspendEvent, ToolResultEvent, DoneEvent, ErrorEvent, PermissionRequestEvent, LLMProvider, RetryConfig, TokenUsage, ProviderToolSpec, ProviderRunState, ProviderReplay, RenderedContext, } from "./types.js";
47
48
  export type { AcceptanceCriterion, VerificationContract, ContractCheckResult, } from "./collaboration/contract.js";
48
49
  export { ContractBuilder, formatContractForSystemPrompt, contractToCriteriaStrings, } from "./collaboration/contract.js";
49
50
  export { AgentPool } from "./collaboration/pool.js";
@@ -1,4 +1,4 @@
1
- import type { Message, RenderedContext, ToolSchema, StreamEvent, LLMProvider, RuntimePolicy } from "../types.js";
1
+ import type { Message, ProviderReplay, RenderedContext, ToolSchema, StreamEvent, LLMProvider, RuntimePolicy } from "../types.js";
2
2
  interface AnthropicProviderOptions {
3
3
  baseURL?: string;
4
4
  authMode?: "api-key" | "bearer";
@@ -15,6 +15,8 @@ export declare class AnthropicProvider implements LLMProvider {
15
15
  baseDelay: number;
16
16
  }, options?: AnthropicProviderOptions);
17
17
  runtimePolicy(): RuntimePolicy;
18
+ peekProviderReplay(message: Pick<Message, "content" | "toolCalls">): ProviderReplay | undefined;
19
+ seedProviderReplay(message: Pick<Message, "content" | "toolCalls">, replay: ProviderReplay): void;
18
20
  private buildTools;
19
21
  complete(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): Promise<Message>;
20
22
  stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): AsyncIterable<StreamEvent>;
@@ -24,6 +26,5 @@ export declare class AnthropicProvider implements LLMProvider {
24
26
  private streamMessage;
25
27
  private buildMessages;
26
28
  private rememberNativeBlocks;
27
- private assistantReplayKey;
28
29
  }
29
30
  export {};
@@ -1,12 +1,16 @@
1
1
  import Anthropic from "@anthropic-ai/sdk";
2
+ import { assistantReplayKey } from "../runtime/provider-replay.js";
2
3
  import { withServerRuntimeGuard } from "../runtime/server.js";
3
4
  import { CircuitBreaker, normalizeToolCall, omitExtensionKeys, toAnthropicMessages } from "./base.js";
4
5
  const CLAUDE_POLICIES = {
6
+ "claude-opus-4-1": { maxTurns: 50 },
5
7
  "claude-opus-4-7": { maxTurns: 50 },
6
8
  "claude-opus-4-6": { maxTurns: 50 },
9
+ "claude-opus-4-0": { maxTurns: 50 },
7
10
  "claude-sonnet-4-6": { maxTurns: 25 },
11
+ "claude-sonnet-4-0": { maxTurns: 25 },
8
12
  "claude-haiku-4-5": { maxTurns: 15 },
9
- "claude-haiku-4-5-20251001": { maxTurns: 15 },
13
+ "claude-3-5-haiku-latest": { maxTurns: 15 },
10
14
  };
11
15
  export class AnthropicProvider {
12
16
  model;
@@ -28,6 +32,15 @@ export class AnthropicProvider {
28
32
  runtimePolicy() {
29
33
  return CLAUDE_POLICIES[this.model] ?? {};
30
34
  }
35
+ peekProviderReplay(message) {
36
+ const blocks = this.nativeAssistantBlocks.get(assistantReplayKey(message));
37
+ return blocks?.length ? { native_blocks: blocks } : undefined;
38
+ }
39
+ seedProviderReplay(message, replay) {
40
+ if (replay.native_blocks?.length) {
41
+ this.nativeAssistantBlocks.set(assistantReplayKey(message), replay.native_blocks);
42
+ }
43
+ }
31
44
  buildTools(tools) {
32
45
  return tools.map(t => ({
33
46
  name: t.name,
@@ -161,17 +174,13 @@ export class AnthropicProvider {
161
174
  : this.client.messages.stream(params));
162
175
  }
163
176
  buildMessages(context) {
164
- return toAnthropicMessages(context.turns, message => this.nativeAssistantBlocks.get(this.assistantReplayKey(message)));
177
+ return toAnthropicMessages(context.turns, message => this.nativeAssistantBlocks.get(assistantReplayKey(message)));
165
178
  }
166
179
  rememberNativeBlocks(message, blocks) {
167
- if (!message.toolCalls?.length)
180
+ if (!blocks.length)
168
181
  return;
169
- this.nativeAssistantBlocks.set(this.assistantReplayKey(message), blocks);
170
- }
171
- assistantReplayKey(message) {
172
- return JSON.stringify({
173
- content: message.content,
174
- toolCalls: message.toolCalls ?? [],
175
- });
182
+ if (!message.toolCalls?.length && !blocks.some(b => b.type === "thinking"))
183
+ return;
184
+ this.nativeAssistantBlocks.set(assistantReplayKey(message), blocks);
176
185
  }
177
186
  }
@@ -23,3 +23,15 @@ export declare function toOpenAIContent(msg: Message): string | Array<Record<str
23
23
  /** Build the full OpenAI messages array from a RenderedContext.
24
24
  * Prepends systemText as the first system message, then converts turns. */
25
25
  export declare function toOpenAIMessageParams(context: RenderedContext): Array<Record<string, unknown>>;
26
+ export declare class ThinkingTagStreamExtractor {
27
+ private buffer;
28
+ private inThinking;
29
+ feed(chunk: string): Array<{
30
+ type: "text" | "thinking";
31
+ content: string;
32
+ }>;
33
+ flush(): Array<{
34
+ type: "text" | "thinking";
35
+ content: string;
36
+ }>;
37
+ }
@@ -166,3 +166,78 @@ export function toOpenAIMessageParams(context) {
166
166
  }
167
167
  return result;
168
168
  }
169
+ export class ThinkingTagStreamExtractor {
170
+ buffer = "";
171
+ inThinking = false;
172
+ feed(chunk) {
173
+ this.buffer += chunk;
174
+ const events = [];
175
+ while (true) {
176
+ if (!this.inThinking) {
177
+ const thinkIndex = this.buffer.indexOf("<think>");
178
+ if (thinkIndex !== -1) {
179
+ const textBefore = this.buffer.substring(0, thinkIndex);
180
+ if (textBefore) {
181
+ events.push({ type: "text", content: textBefore });
182
+ }
183
+ this.inThinking = true;
184
+ this.buffer = this.buffer.substring(thinkIndex + 7);
185
+ continue;
186
+ }
187
+ const possibleTagStart = this.buffer.lastIndexOf("<");
188
+ if (possibleTagStart !== -1 && "<think>".startsWith(this.buffer.substring(possibleTagStart))) {
189
+ const toEmit = this.buffer.substring(0, possibleTagStart);
190
+ if (toEmit) {
191
+ events.push({ type: "text", content: toEmit });
192
+ }
193
+ this.buffer = this.buffer.substring(possibleTagStart);
194
+ break;
195
+ }
196
+ else {
197
+ if (this.buffer) {
198
+ events.push({ type: "text", content: this.buffer });
199
+ this.buffer = "";
200
+ }
201
+ break;
202
+ }
203
+ }
204
+ else {
205
+ const endThinkIndex = this.buffer.indexOf("</think>");
206
+ if (endThinkIndex !== -1) {
207
+ const thinkingContent = this.buffer.substring(0, endThinkIndex);
208
+ if (thinkingContent) {
209
+ events.push({ type: "thinking", content: thinkingContent });
210
+ }
211
+ this.inThinking = false;
212
+ this.buffer = this.buffer.substring(endThinkIndex + 8);
213
+ continue;
214
+ }
215
+ const possibleEndStart = this.buffer.lastIndexOf("<");
216
+ if (possibleEndStart !== -1 && "</think>".startsWith(this.buffer.substring(possibleEndStart))) {
217
+ const toEmit = this.buffer.substring(0, possibleEndStart);
218
+ if (toEmit) {
219
+ events.push({ type: "thinking", content: toEmit });
220
+ }
221
+ this.buffer = this.buffer.substring(possibleEndStart);
222
+ break;
223
+ }
224
+ else {
225
+ if (this.buffer) {
226
+ events.push({ type: "thinking", content: this.buffer });
227
+ this.buffer = "";
228
+ }
229
+ break;
230
+ }
231
+ }
232
+ }
233
+ return events;
234
+ }
235
+ flush() {
236
+ const events = [];
237
+ if (this.buffer) {
238
+ events.push({ type: this.inThinking ? "thinking" : "text", content: this.buffer });
239
+ this.buffer = "";
240
+ }
241
+ return events;
242
+ }
243
+ }
@@ -1,9 +1,10 @@
1
1
  import type { LLMProvider } from "../types.js";
2
- import { endpointProfiles, type ModelProfileId } from "./profiles.js";
2
+ import { endpointProfiles, type ModelProfileId, type ProviderId } from "./profiles.js";
3
3
  export type EndpointProfileId = keyof typeof endpointProfiles;
4
4
  export interface CreateProviderOptions {
5
- model: ModelProfileId;
5
+ model: ModelProfileId | string;
6
6
  apiKey: string;
7
+ provider?: ProviderId;
7
8
  endpoint?: EndpointProfileId;
8
9
  retry?: {
9
10
  maxRetries: number;
@@ -1,3 +1,4 @@
1
+ import { AnthropicProvider } from "./anthropic.js";
1
2
  import { OpenAIChatProvider } from "./openai.js";
2
3
  import { DeepSeekProvider } from "./deepseek.js";
3
4
  import { KimiProvider } from "./kimi.js";
@@ -5,20 +6,35 @@ import { OpenAIResponsesProvider } from "./openai-responses.js";
5
6
  import { MiniMaxProvider } from "./minimax.js";
6
7
  import { QwenProvider } from "./qwen.js";
7
8
  import { GeminiProvider } from "./gemini.js";
8
- import { endpointProfiles, getModelProfile } from "./profiles.js";
9
+ import { GLMProvider } from "./glm.js";
10
+ import { endpointProfiles, getModelProfile, modelProfiles } from "./profiles.js";
9
11
  export function createProvider(options) {
10
- const profile = getModelProfile(options.model);
11
- const endpointId = (options.endpoint ?? profile.defaultEndpointId);
12
+ const profile = isModelProfileId(options.model) ? getModelProfile(options.model) : undefined;
13
+ const parsedProviderId = providerPrefix(options.model);
14
+ const endpointId = (options.endpoint ?? profile?.defaultEndpointId ?? defaultEndpointForProvider(options.provider ?? parsedProviderId));
15
+ if (!endpointId) {
16
+ throw new Error(`Unknown model profile: ${options.model}. Pass provider or endpoint for custom model names.`);
17
+ }
12
18
  const endpoint = endpointProfiles[endpointId];
13
19
  if (!endpoint) {
14
20
  throw new Error(`Unknown endpoint profile: ${endpointId}`);
15
21
  }
16
- if (endpoint.providerId !== profile.providerId) {
17
- throw new Error(`Endpoint ${endpoint.id} does not belong to provider ${profile.providerId}`);
22
+ const providerId = profile?.providerId ?? options.provider ?? parsedProviderId ?? endpoint.providerId;
23
+ if (profile && options.provider && options.provider !== profile.providerId) {
24
+ throw new Error(`Model ${profile.id} belongs to provider ${profile.providerId}, not ${options.provider}`);
25
+ }
26
+ if (parsedProviderId && options.provider && parsedProviderId !== options.provider) {
27
+ throw new Error(`Model ${options.model} uses provider prefix ${parsedProviderId}, not ${options.provider}`);
28
+ }
29
+ if (endpoint.providerId !== providerId) {
30
+ throw new Error(`Endpoint ${endpoint.id} does not belong to provider ${providerId}`);
18
31
  }
19
- const model = options.model.slice(`${profile.providerId}/`.length);
32
+ const model = modelNameForProvider(options.model, providerId);
20
33
  const baseURL = options.baseURL ?? endpoint.baseURL;
21
- if (profile.providerId === "openai") {
34
+ if (providerId === "anthropic" && endpoint.protocol === "anthropic-messages") {
35
+ return new AnthropicProvider(options.apiKey, model, options.retry, { baseURL });
36
+ }
37
+ if (providerId === "openai") {
22
38
  if (endpoint.protocol === "openai-chat") {
23
39
  return new OpenAIChatProvider(options.apiKey, model, options.retry, baseURL);
24
40
  }
@@ -26,20 +42,52 @@ export function createProvider(options) {
26
42
  return new OpenAIResponsesProvider(options.apiKey, model, options.retry, baseURL);
27
43
  }
28
44
  }
29
- if (profile.providerId === "minimax" && endpoint.protocol === "anthropic-messages") {
45
+ if (providerId === "minimax" && endpoint.protocol === "anthropic-messages") {
30
46
  return new MiniMaxProvider(options.apiKey, model, options.retry, baseURL);
31
47
  }
32
- if (profile.providerId === "deepseek" && endpoint.protocol === "openai-chat") {
48
+ if (providerId === "deepseek" && endpoint.protocol === "openai-chat") {
33
49
  return new DeepSeekProvider(options.apiKey, model, options.retry, baseURL);
34
50
  }
35
- if (profile.providerId === "kimi" && endpoint.protocol === "openai-chat") {
51
+ if (providerId === "kimi" && endpoint.protocol === "openai-chat") {
36
52
  return new KimiProvider(options.apiKey, model, options.retry, baseURL);
37
53
  }
38
- if (profile.providerId === "qwen" && endpoint.protocol === "openai-chat") {
54
+ if (providerId === "qwen" && endpoint.protocol === "openai-chat") {
39
55
  return new QwenProvider(options.apiKey, model, options.retry, baseURL);
40
56
  }
41
- if (profile.providerId === "gemini" && endpoint.protocol === "gemini") {
57
+ if (providerId === "gemini" && endpoint.protocol === "gemini") {
42
58
  return new GeminiProvider(options.apiKey, model, options.retry, baseURL);
43
59
  }
44
- throw new Error(`No Node provider factory for ${profile.id} on ${endpoint.id}`);
60
+ if (providerId === "glm" && endpoint.protocol === "openai-chat") {
61
+ return new GLMProvider(options.apiKey, model, options.retry, baseURL);
62
+ }
63
+ throw new Error(`No Node provider factory for ${options.model} on ${endpoint.id}`);
64
+ }
65
+ function isModelProfileId(model) {
66
+ return Object.prototype.hasOwnProperty.call(modelProfiles, model);
67
+ }
68
+ function providerPrefix(model) {
69
+ const [prefix] = model.split("/", 1);
70
+ return providerIds().includes(prefix) ? prefix : undefined;
71
+ }
72
+ function providerIds() {
73
+ return Array.from(new Set(Object.values(endpointProfiles).map(endpoint => endpoint.providerId)));
74
+ }
75
+ function defaultEndpointForProvider(providerId) {
76
+ if (!providerId)
77
+ return undefined;
78
+ const defaults = {
79
+ anthropic: "anthropic.messages",
80
+ openai: "openai.chat",
81
+ minimax: "minimax.anthropic",
82
+ deepseek: "deepseek.openai",
83
+ kimi: "kimi.openai",
84
+ qwen: "qwen.dashscope",
85
+ gemini: "gemini.google",
86
+ glm: "glm.openai",
87
+ };
88
+ return defaults[providerId];
89
+ }
90
+ function modelNameForProvider(model, providerId) {
91
+ const prefix = `${providerId}/`;
92
+ return model.startsWith(prefix) ? model.slice(prefix.length) : model;
45
93
  }
@@ -91,7 +91,7 @@ export class DeepSeekProvider extends OpenAIChatProvider {
91
91
  const toolCalls = Object.values(toolCallBufs).map(tb => ({
92
92
  id: tb.id, name: tb.name, arguments: tb.argsBuf || "{}",
93
93
  }));
94
- if (toolCalls.length) {
94
+ if (toolCalls.length || reasoningContent) {
95
95
  this.chat.rememberReplayFields({ content: finalText, toolCalls }, { reasoning_content: reasoningContent });
96
96
  }
97
97
  for (const [index, tb] of Object.entries(toolCallBufs)) {
@@ -1,10 +1,13 @@
1
+ import { type Content } from "@google/generative-ai";
1
2
  import type { Message, RenderedContext, ToolSchema, StreamEvent, LLMProvider, RuntimePolicy } from "../types.js";
3
+ export declare function buildContents(turns: Message[]): Content[];
2
4
  export declare class GeminiProvider implements LLMProvider {
3
5
  private readonly model;
4
6
  private genAI;
5
7
  private circuit;
6
8
  private maxRetries;
7
9
  private baseDelay;
10
+ private requestOptions;
8
11
  constructor(apiKey: string, model?: string, retry?: {
9
12
  maxRetries: number;
10
13
  baseDelay: number;
@@ -4,6 +4,9 @@ import { CircuitBreaker, normalizeToolCall } from "./base.js";
4
4
  import { endpointProfiles } from "./profiles.js";
5
5
  const GEMINI_BASE = endpointProfiles["gemini.google"].baseURL;
6
6
  const GEMINI_POLICIES = {
7
+ "gemini-3-pro-preview": { maxTurns: 50 },
8
+ "gemini-3-flash-preview": { maxTurns: 25 },
9
+ "gemini-3.5-flash": { maxTurns: 30 },
7
10
  "gemini-2.5-pro": { maxTurns: 35 },
8
11
  "gemini-2.5-flash": { maxTurns: 20 },
9
12
  "gemini-2.0-flash": { maxTurns: 15 },
@@ -11,15 +14,30 @@ const GEMINI_POLICIES = {
11
14
  "gemini-1.5-pro": { maxTurns: 30 },
12
15
  "gemini-1.5-flash": { maxTurns: 15 },
13
16
  };
14
- function buildContents(turns) {
17
+ export function buildContents(turns) {
15
18
  const contents = [];
16
19
  for (const msg of turns) {
17
20
  if (msg.role === "tool") {
18
21
  const parts = (msg.contentParts ?? [])
19
22
  .filter(p => p.type === "tool_result")
20
- .map(p => p.type === "tool_result" ? ({
21
- functionResponse: { name: p.callId, response: { output: p.output } },
22
- }) : ({ text: "" }));
23
+ .map(p => {
24
+ if (p.type !== "tool_result")
25
+ return { text: "" };
26
+ let toolName = p.callId;
27
+ for (let i = turns.length - 1; i >= 0; i--) {
28
+ const turn = turns[i];
29
+ if (turn.role === "assistant" && turn.toolCalls) {
30
+ const matched = turn.toolCalls.find(tc => tc.id === p.callId);
31
+ if (matched) {
32
+ toolName = matched.name;
33
+ break;
34
+ }
35
+ }
36
+ }
37
+ return {
38
+ functionResponse: { name: toolName, response: { output: p.output } },
39
+ };
40
+ });
23
41
  if (parts.length)
24
42
  contents.push({ role: "user", parts });
25
43
  continue;
@@ -62,12 +80,14 @@ export class GeminiProvider {
62
80
  circuit;
63
81
  maxRetries;
64
82
  baseDelay;
83
+ requestOptions;
65
84
  constructor(apiKey, model = "gemini-2.0-flash", retry = { maxRetries: 3, baseDelay: 1000 }, baseURL = GEMINI_BASE) {
66
85
  this.model = model;
67
86
  this.genAI = withServerRuntimeGuard(() => new GoogleGenerativeAI(apiKey));
68
87
  this.circuit = new CircuitBreaker();
69
88
  this.maxRetries = retry.maxRetries;
70
89
  this.baseDelay = retry.baseDelay;
90
+ this.requestOptions = { baseUrl: baseURL };
71
91
  }
72
92
  runtimePolicy() {
73
93
  return GEMINI_POLICIES[this.model] ?? {};
@@ -86,7 +106,7 @@ export class GeminiProvider {
86
106
  model: this.model,
87
107
  ...(system ? { systemInstruction: system } : {}),
88
108
  ...(geminiTools.length ? { tools: geminiTools } : {}),
89
- });
109
+ }, this.requestOptions);
90
110
  const resp = await m.generateContent({ contents });
91
111
  this.circuit.recordSuccess();
92
112
  const candidate = resp.response.candidates?.[0];
@@ -127,7 +147,7 @@ export class GeminiProvider {
127
147
  model: this.model,
128
148
  ...(system ? { systemInstruction: system } : {}),
129
149
  ...(geminiTools.length ? { tools: geminiTools } : {}),
130
- });
150
+ }, this.requestOptions);
131
151
  const result = await m.generateContentStream({ contents });
132
152
  const toolCalls = [];
133
153
  for await (const chunk of result.stream) {
@@ -0,0 +1,9 @@
1
+ import type { RuntimePolicy } from "../types.js";
2
+ import { OpenAIChatProvider } from "./openai.js";
3
+ export declare class GLMProvider extends OpenAIChatProvider {
4
+ constructor(apiKey: string, model?: string, retry?: {
5
+ maxRetries: number;
6
+ baseDelay: number;
7
+ }, baseURL?: string);
8
+ runtimePolicy(): RuntimePolicy;
9
+ }
@@ -0,0 +1,21 @@
1
+ import { OpenAIChatProvider } from "./openai.js";
2
+ import { endpointProfiles } from "./profiles.js";
3
+ const GLM_BASE = endpointProfiles["glm.openai"].baseURL;
4
+ const GLM_POLICIES = {
5
+ "glm-5.1": { maxTurns: 50 },
6
+ "glm/glm-5.1": { maxTurns: 50 },
7
+ "glm-4-plus": { maxTurns: 35 },
8
+ "glm/glm-4-plus": { maxTurns: 35 },
9
+ "glm-4-flash": { maxTurns: 15 },
10
+ "glm/glm-4-flash": { maxTurns: 15 },
11
+ "glm-4-air": { maxTurns: 20 },
12
+ "glm/glm-4-air": { maxTurns: 20 },
13
+ };
14
+ export class GLMProvider extends OpenAIChatProvider {
15
+ constructor(apiKey, model = "glm-5.1", retry, baseURL = GLM_BASE) {
16
+ super(apiKey, model, retry, baseURL);
17
+ }
18
+ runtimePolicy() {
19
+ return GLM_POLICIES[this.model] ?? {};
20
+ }
21
+ }
@@ -7,6 +7,8 @@ const KIMI_POLICIES = {
7
7
  "moonshot-v1-128k": { maxTurns: 30 },
8
8
  "kimi-k2.5": { maxTurns: 30 },
9
9
  "kimi-k2.6": { maxTurns: 35 },
10
+ "kimi-k2-thinking": { maxTurns: 50 },
11
+ "kimi-k2-thinking-turbo": { maxTurns: 40 },
10
12
  };
11
13
  export class KimiProvider extends OpenAIChatProvider {
12
14
  constructor(apiKey, model = "kimi-k2.6", retry, baseURL = MOONSHOT_BASE) {
@@ -2,7 +2,12 @@ import { AnthropicProvider } from "./anthropic.js";
2
2
  import { endpointProfiles } from "./profiles.js";
3
3
  const MINIMAX_POLICIES = {
4
4
  "MiniMax-M2.7": { maxTurns: 35 },
5
+ "MiniMax-M2.7-highspeed": { maxTurns: 35 },
5
6
  "MiniMax-M2.5": { maxTurns: 25 },
7
+ "MiniMax-M2.5-highspeed": { maxTurns: 25 },
8
+ "MiniMax-M2.1": { maxTurns: 25 },
9
+ "MiniMax-M2.1-highspeed": { maxTurns: 25 },
10
+ "MiniMax-M2": { maxTurns: 20 },
6
11
  "MiniMax-Text-01": { maxTurns: 20 },
7
12
  };
8
13
  export class MiniMaxProvider extends AnthropicProvider {
@@ -23,5 +23,5 @@ export declare class OpenAIChatAdapter {
23
23
  arguments: string;
24
24
  }>;
25
25
  rememberReplayFields(message: Pick<Message, "content" | "toolCalls">, fields: Record<string, unknown>): void;
26
- private assistantReplayKey;
26
+ peekReplayFields(message: Pick<Message, "content" | "toolCalls">): Record<string, unknown> | undefined;
27
27
  }
@@ -1,3 +1,4 @@
1
+ import { assistantReplayKey } from "../runtime/provider-replay.js";
1
2
  import { normalizeToolCall, toOpenAIMessageParams } from "./base.js";
2
3
  export class OpenAIChatAdapter {
3
4
  replayFields = new Map();
@@ -18,7 +19,7 @@ export class OpenAIChatAdapter {
18
19
  continue;
19
20
  }
20
21
  if (source.role === "assistant") {
21
- const replay = this.replayFields.get(this.assistantReplayKey(source));
22
+ const replay = this.replayFields.get(assistantReplayKey(source));
22
23
  if (replay)
23
24
  serialized[cursor] = { ...serialized[cursor], ...replay };
24
25
  }
@@ -32,12 +33,9 @@ export class OpenAIChatAdapter {
32
33
  .filter(Boolean);
33
34
  }
34
35
  rememberReplayFields(message, fields) {
35
- this.replayFields.set(this.assistantReplayKey(message), fields);
36
+ this.replayFields.set(assistantReplayKey(message), fields);
36
37
  }
37
- assistantReplayKey(message) {
38
- return JSON.stringify({
39
- content: message.content,
40
- toolCalls: message.toolCalls ?? [],
41
- });
38
+ peekReplayFields(message) {
39
+ return this.replayFields.get(assistantReplayKey(message));
42
40
  }
43
41
  }
@@ -115,11 +115,20 @@ export class OpenAIResponsesProvider {
115
115
  }
116
116
  runtimePolicy() {
117
117
  const table = {
118
+ "gpt-5.5": { maxTurns: 60 },
119
+ "gpt-5.4": { maxTurns: 50 },
120
+ "gpt-5.4-mini": { maxTurns: 25 },
121
+ "gpt-5.4-nano": { maxTurns: 15 },
122
+ "gpt-5.2": { maxTurns: 50 },
123
+ "gpt-5.2-pro": { maxTurns: 60 },
124
+ "gpt-5.1": { maxTurns: 50 },
118
125
  "gpt-4.1": { maxTurns: 35 },
119
126
  "gpt-4.1-mini": { maxTurns: 20 },
120
127
  "gpt-4.1-nano": { maxTurns: 15 },
121
128
  "gpt-5": { maxTurns: 50 },
129
+ "gpt-5-pro": { maxTurns: 60 },
122
130
  "gpt-5-mini": { maxTurns: 25 },
131
+ "gpt-5-nano": { maxTurns: 15 },
123
132
  "o3": { maxTurns: 50 },
124
133
  "o3-mini": { maxTurns: 25 },
125
134
  "o4-mini": { maxTurns: 25 },
@@ -1,5 +1,5 @@
1
1
  import OpenAI from "openai";
2
- import type { Message, RenderedContext, ToolSchema, StreamEvent, LLMProvider, RuntimePolicy } from "../types.js";
2
+ import type { Message, ProviderReplay, RenderedContext, ToolSchema, StreamEvent, LLMProvider, RuntimePolicy } from "../types.js";
3
3
  import { CircuitBreaker } from "./base.js";
4
4
  import { OpenAIChatAdapter } from "./openai-chat.js";
5
5
  export declare class OpenAIChatProvider implements LLMProvider {
@@ -14,6 +14,8 @@ export declare class OpenAIChatProvider implements LLMProvider {
14
14
  baseDelay: number;
15
15
  }, baseURL?: string);
16
16
  runtimePolicy(): RuntimePolicy;
17
+ peekProviderReplay(message: Pick<Message, "content" | "toolCalls">): ProviderReplay | undefined;
18
+ seedProviderReplay(message: Pick<Message, "content" | "toolCalls">, replay: ProviderReplay): void;
17
19
  complete(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): Promise<Message>;
18
20
  stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): AsyncIterable<StreamEvent>;
19
21
  protected requestExtensions(extensions?: Record<string, unknown>): Record<string, unknown>;