@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.
@@ -5,16 +5,19 @@ import { OpenAIChatAdapter } from "./openai-chat.js";
5
5
  import { endpointProfiles } from "./profiles.js";
6
6
  const QWEN_BASE = endpointProfiles["qwen.dashscope"].baseURL;
7
7
  const QWEN_POLICIES = {
8
- "qwen-max": { maxTurns: 25 },
9
- "qwen-plus": { maxTurns: 20 },
10
- "qwen-turbo": { maxTurns: 15 },
11
- "qwq-plus": { maxTurns: 40 },
12
- "qwq-32b": { maxTurns: 35 },
13
- "qwen3-235b-a22b": { maxTurns: 35 },
14
- "qwen3-72b": { maxTurns: 25 },
15
- "qwen3-32b": { maxTurns: 20 },
16
- "qwen3-14b": { maxTurns: 15 },
17
- "qwen3-8b": { maxTurns: 15 },
8
+ "qwen3.7-max-preview": { maxTurns: 45 },
9
+ "qwen3.7-plus-preview": { maxTurns: 40 },
10
+ "qwen3.6-max-preview": { maxTurns: 40 },
11
+ "qwen3.6-plus": { maxTurns: 35 },
12
+ "qwen3.6-flash": { maxTurns: 20 },
13
+ "qwen3.6-35b-a3b": { maxTurns: 25 },
14
+ "qwen3.6-27b": { maxTurns: 25 },
15
+ "qwen3.5-plus": { maxTurns: 35 },
16
+ "qwen3.5-flash": { maxTurns: 20 },
17
+ "qwen3.5-397b-a17b": { maxTurns: 35 },
18
+ "qwen3.5-122b-a10b": { maxTurns: 25 },
19
+ "qwen3.5-35b-a3b": { maxTurns: 20 },
20
+ "qwen3.5-27b": { maxTurns: 20 },
18
21
  };
19
22
  export class QwenProvider {
20
23
  model;
@@ -23,7 +26,7 @@ export class QwenProvider {
23
26
  maxRetries;
24
27
  baseDelay;
25
28
  chat = new OpenAIChatAdapter();
26
- constructor(apiKey, model = "qwen-max", retry = { maxRetries: 3, baseDelay: 1000 }, baseURL = QWEN_BASE) {
29
+ constructor(apiKey, model = "qwen3.6-plus", retry = { maxRetries: 3, baseDelay: 1000 }, baseURL = QWEN_BASE) {
27
30
  this.model = model;
28
31
  this.client = withServerRuntimeGuard(() => new OpenAI({ apiKey, baseURL }));
29
32
  this.circuit = new CircuitBreaker();
@@ -33,6 +36,17 @@ export class QwenProvider {
33
36
  runtimePolicy() {
34
37
  return QWEN_POLICIES[this.model] ?? {};
35
38
  }
39
+ peekProviderReplay(message) {
40
+ const fields = this.chat.peekReplayFields(message);
41
+ if (!fields || !("reasoning_content" in fields))
42
+ return undefined;
43
+ return { reasoning_content: String(fields.reasoning_content ?? "") };
44
+ }
45
+ seedProviderReplay(message, replay) {
46
+ if (replay.reasoning_content !== undefined) {
47
+ this.chat.rememberReplayFields(message, { reasoning_content: replay.reasoning_content });
48
+ }
49
+ }
36
50
  async complete(context, tools, extensions) {
37
51
  if (this.circuit.isOpen())
38
52
  throw new Error("Circuit breaker open");
@@ -66,6 +80,8 @@ export class QwenProvider {
66
80
  const msgs = this.chat.buildMessages(context);
67
81
  const toolCallBufs = {};
68
82
  const emittedToolCallIndexes = new Set();
83
+ let reasoningContent = "";
84
+ let finalText = "";
69
85
  const extraBody = this.thinkingExtraBody(extensions);
70
86
  const stream = await this.client.chat.completions.create({
71
87
  ...this.requestExtensions(extensions),
@@ -86,10 +102,14 @@ export class QwenProvider {
86
102
  if (!choice)
87
103
  continue;
88
104
  const delta = choice.delta;
89
- if (delta.reasoning_content)
105
+ if (delta.reasoning_content) {
106
+ reasoningContent += String(delta.reasoning_content);
90
107
  yield { type: "thinking_delta", delta: delta.reasoning_content };
91
- if (delta.content)
108
+ }
109
+ if (delta.content) {
110
+ finalText += String(delta.content);
92
111
  yield { type: "text_delta", delta: delta.content };
112
+ }
93
113
  for (const tc of delta.tool_calls ?? []) {
94
114
  const idx = tc.index;
95
115
  if (!toolCallBufs[idx])
@@ -99,6 +119,10 @@ export class QwenProvider {
99
119
  toolCallBufs[idx].argsBuf += tc.function?.arguments ?? "";
100
120
  }
101
121
  if (choice.finish_reason === "tool_calls") {
122
+ const toolCalls = Object.values(toolCallBufs).map(tb => ({
123
+ id: tb.id, name: tb.name, arguments: tb.argsBuf || "{}",
124
+ }));
125
+ this.chat.rememberReplayFields({ content: finalText, toolCalls }, { reasoning_content: reasoningContent });
102
126
  for (const [index, tb] of Object.entries(toolCallBufs)) {
103
127
  const idx = Number(index);
104
128
  if (emittedToolCallIndexes.has(idx))
@@ -115,6 +139,12 @@ export class QwenProvider {
115
139
  }
116
140
  }
117
141
  }
142
+ const toolCalls = Object.values(toolCallBufs).map(tb => ({
143
+ id: tb.id, name: tb.name, arguments: tb.argsBuf || "{}",
144
+ }));
145
+ if (toolCalls.length || reasoningContent) {
146
+ this.chat.rememberReplayFields({ content: finalText, toolCalls }, { reasoning_content: reasoningContent });
147
+ }
118
148
  for (const [index, tb] of Object.entries(toolCallBufs)) {
119
149
  const idx = Number(index);
120
150
  if (emittedToolCallIndexes.has(idx))
@@ -0,0 +1,7 @@
1
+ import type { LLMProvider, Message, ProviderReplay, ToolCall } from "../types.js";
2
+ import type { SessionEvent } from "./session-log.js";
3
+ export declare function assistantReplayKey(message: Pick<Message, "content" | "toolCalls">): string;
4
+ export declare function seedProviderReplayFromEvents(provider: LLMProvider, events: Array<{
5
+ event: SessionEvent;
6
+ }>): void;
7
+ export declare function peekProviderReplay(provider: LLMProvider, content: string, toolCalls: ToolCall[]): ProviderReplay | undefined;
@@ -0,0 +1,47 @@
1
+ function sortObjectKeys(val) {
2
+ if (val === null || typeof val !== "object") {
3
+ return val;
4
+ }
5
+ if (Array.isArray(val)) {
6
+ return val.map(sortObjectKeys);
7
+ }
8
+ const sortedKeys = Object.keys(val).sort();
9
+ const result = {};
10
+ for (const key of sortedKeys) {
11
+ result[key] = sortObjectKeys(val[key]);
12
+ }
13
+ return result;
14
+ }
15
+ export function assistantReplayKey(message) {
16
+ const toolCalls = (message.toolCalls ?? []).map(tc => {
17
+ let normalizedArgs = tc.arguments;
18
+ try {
19
+ const parsed = typeof tc.arguments === "string" ? JSON.parse(tc.arguments) : tc.arguments;
20
+ normalizedArgs = JSON.stringify(sortObjectKeys(parsed));
21
+ }
22
+ catch {
23
+ // fallback
24
+ }
25
+ return {
26
+ id: tc.id,
27
+ name: tc.name,
28
+ arguments: normalizedArgs,
29
+ };
30
+ });
31
+ return JSON.stringify({
32
+ content: message.content,
33
+ toolCalls,
34
+ });
35
+ }
36
+ export function seedProviderReplayFromEvents(provider, events) {
37
+ if (!provider.seedProviderReplay)
38
+ return;
39
+ for (const { event } of events) {
40
+ if (event.kind !== "llm_completed" || !event.provider_replay)
41
+ continue;
42
+ provider.seedProviderReplay({ content: event.content, toolCalls: event.tool_calls ?? [] }, event.provider_replay);
43
+ }
44
+ }
45
+ export function peekProviderReplay(provider, content, toolCalls) {
46
+ return provider.peekProviderReplay?.({ content, toolCalls });
47
+ }
@@ -1,4 +1,5 @@
1
1
  import { getKernel } from "../kernel.js";
2
+ import { peekProviderReplay, seedProviderReplayFromEvents } from "./provider-replay.js";
2
3
  export class RuntimeRunner {
3
4
  opts;
4
5
  interrupted = false;
@@ -128,6 +129,7 @@ export class RuntimeRunner {
128
129
  if (this.opts.knowledgeSource)
129
130
  sm.setKnowledgeEnabled(true);
130
131
  if (priorEvents && priorEvents.length > 0) {
132
+ seedProviderReplayFromEvents(this.opts.provider, priorEvents);
131
133
  sm.preloadHistory(replayMessages(priorEvents));
132
134
  }
133
135
  const sessionStart = Date.now();
@@ -202,12 +204,14 @@ export class RuntimeRunner {
202
204
  toolCalls: finalToolCalls,
203
205
  tokenCount: turnTokens || undefined,
204
206
  });
207
+ const providerReplay = peekProviderReplay(this.opts.provider, finalText, finalToolCalls);
205
208
  await this.opts.sessionLog.append(sessionId, {
206
209
  kind: "llm_completed",
207
210
  turn: sm.turn,
208
211
  content: finalText,
209
212
  token_count: turnTokens || undefined,
210
213
  tool_calls: finalToolCalls,
214
+ ...(providerReplay ? { provider_replay: providerReplay } : {}),
211
215
  });
212
216
  }
213
217
  else if (action.kind === "execute_tools") {
@@ -1,4 +1,4 @@
1
- import type { ToolCall } from "../types.js";
1
+ import type { ProviderReplay, ToolCall } from "../types.js";
2
2
  export type SessionEvent = {
3
3
  kind: "run_started";
4
4
  run_id: string;
@@ -12,6 +12,7 @@ export type SessionEvent = {
12
12
  content: string;
13
13
  token_count?: number;
14
14
  tool_calls: ToolCall[];
15
+ provider_replay?: ProviderReplay;
15
16
  } | {
16
17
  kind: "tool_requested";
17
18
  turn: number;
package/dist/types.d.ts CHANGED
@@ -152,6 +152,13 @@ export interface RetryConfig {
152
152
  * Responses `previous_response_id` without leaking those semantics into the kernel.
153
153
  */
154
154
  export type ProviderRunState = Record<string, unknown>;
155
+ /** Provider-native fields required to replay a turn across requests (thinking blocks, reasoning_content, etc.). */
156
+ export interface ProviderReplay {
157
+ /** Anthropic-style assistant content blocks (thinking, text, tool_use). */
158
+ native_blocks?: Array<Record<string, unknown>>;
159
+ /** OpenAI-compatible reasoning field (DeepSeek, etc.). */
160
+ reasoning_content?: string;
161
+ }
155
162
  /** Structured render output produced by the kernel for each LLM call. */
156
163
  export interface RenderedContext {
157
164
  /** Combined system text: system partition + dashboard (when non-empty).
@@ -180,6 +187,10 @@ export interface LLMProvider {
180
187
  * maxTurns / timeoutMs in RuntimeOptions.
181
188
  */
182
189
  runtimePolicy?(): RuntimePolicy;
190
+ /** Read provider-native replay fields captured after the most recent assistant turn. */
191
+ peekProviderReplay?(message: Pick<Message, "content" | "toolCalls">): ProviderReplay | undefined;
192
+ /** Restore provider-native replay fields when rebuilding history from SessionLog. */
193
+ seedProviderReplay?(message: Pick<Message, "content" | "toolCalls">, replay: ProviderReplay): void;
183
194
  complete(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): Promise<Message>;
184
195
  stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>, state?: ProviderRunState): AsyncIterable<StreamEvent>;
185
196
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deepstrike/sdk",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "description": "DeepStrike Node.js SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -17,7 +17,7 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "@anthropic-ai/sdk": "^0.39.0",
20
- "@deepstrike/core": "0.1.14",
20
+ "@deepstrike/core": "0.1.16",
21
21
  "@google/generative-ai": "^0.24.1",
22
22
  "openai": "^4.77.0"
23
23
  },